はじめに
過去に仕事で作成したWebサイトが表示されないとクライアントから連絡がありました。見てみると確かに以下のようなエラー画面が表示され、Webサイトが表示できない状態になっていました(以下はMicrosoft Edgeの場合)。
申し訳ございません。このページに到達できません
(ドメイン)により、接続が拒否されました。
ERR_CONNECTION_REFUSED
以前、利用しているVPSで機器障害があり、復旧後にWebサーバー(nginx)を再起動する必要があったため、今回も同じような対処をすればすぐに復旧できるだろうと考えていました。しかし、今回はWebサーバーの再起動を行っても、VPSの再起動を行っても復旧しませんでした。私が初めて遭遇した事象のため、備忘も含めて記事に残しておきます。
調査
エラー画面にもある通り、サーバーに接続を拒否されたときに「ERR_CONNECTION_REFUSED」というエラーが表示されます。エラーメッセージで調べるとブラウザのキャッシュクリアだったりDNSの変更だったり、いずれもクライアントサイドの対処法が書かれているばかりで、原因がサーバーサイドにある場合についてはほとんど書かれていません。
今回はクライアントからWebサイトが表示されないと連絡があり、そして私の環境でも同様だったため、原因はクライアントサイドではなくサーバーサイドにあると考えられます。
ひとまずVPSにSSH接続して設定を確認していくことにしました。
SSH接続の設定を行い、VPSにSSH接続しようとしたところ、SSH接続することができませんでした。いろいろ試していくうちにわかったのは、どうやらSSHのデフォルトのポート番号(22/tcp)以外だとSSH接続できないということでした。デフォルトのポート番号であればSSH接続できるので、いったんこの問題は置いておくことにしました。
VPSまたはローカルから以下の確認を行いました。
- ping/traceroute/nslookup:すべて問題なし
- Webサーバー(nginx/unicorn)再起動:状況変わらず
- VPS再起動:状況変わらず
原因
SSH接続ができなかった際、原因を調べている中でよく出てきたのはファイアウォールの設定で接続がブロックされているということでした。調べると、CentOS 7ではfirewalldというツールでファイアウォールの設定を行っていることがわかりました。
今までファイアウォールの設定はしたことがなく、それでも問題なくWebサイトは運用できていました。しかし、何らかのきっかけでfirewalldの設定が有効になり、Web通信を拒否するようになっていました。
以下のコマンドを実行すると、firewalldが有効になっているか確認できます。
$ sudo systemctl status firewalld
● firewalld.service - firewalld - dynamic firewall daemon
Loaded: loaded (/usr/lib/systemd/system/firewalld.service; disabled; vendor preset: enabled)
Active: active (running) since 土 2022-08-06 16:33:48 JST; 2h 53min ago
別のクライアントで使用しているVPSではfirewalldは有効になっていませんでした(現在は有効にして設定済み)。なぜ特定のVPSだけ、突然firewalldが有効になっているのかはわかりませんが、Webサイトが表示されない原因はわかりました。当然、ファイアウォールは設定されているほうがいいので、有効にした上で適切な設定を行います。
対処
firewalldの有効化
まず、firewalldが有効になっていない場合は以下のコマンドを実行します。
# 起動
$ sudo systemctl start firewalld
# 停止
$ sudo systemctl stop firewalld
# 再起動
$ sudo systemctl restart firewalld
また、VPSの再起動時にfirewalldを自動起動する設定を有効化します。
# 有効化
$ sudo systemctl enable firewalld.service
# 無効化
$ sudo systemctl disable firewalld.service
# 設定確認
$ sudo systemctl is-enabled firewalld.service
許可するサービスの追加
以下のコマンドを実行すると、firewalldで通信を許可するサービスやポート番号が確認できます。
$ sudo firewall-cmd --list-all
public (active)
target: default
icmp-block-inversion: no
interfaces: eth0
sources:
services: dhcpv6-client ssh
ports:
protocols:
masquerade: no
forward-ports:
source-ports:
icmp-blocks:
rich rules:
servicesを見ると、dhcpv6-clientとsshしか登録されていません。Web通信はhttpまたはhttpsですが、firewalldはこれらの通信を許可していませんでした。以下のコマンドを実行してサービスを追加します。
$ sudo firewall-cmd --add-service=http --add-service=https --permanent
$ sudo firewall-cmd --reload
--permanent
オプションをつけると恒久的な設定になります。このオプションをつけないと、設定を追加してもfirewalldを再起動すると消えてしまいます。また、このオプションをつけた場合はfirewalldの再起動が必要になります。
$ sudo firewall-cmd --list-all
public (active)
target: default
icmp-block-inversion: no
interfaces: eth0
sources:
services: dhcpv6-client http https ssh
ports:
protocols:
masquerade: no
forward-ports:
source-ports:
icmp-blocks:
rich rules:
servicesにhttpおよびhttpsが追加されました。これで表示できていなかったクライアントのWebサイトが表示できるようになりました。
許可するポート番号の追加
ついでにSSH接続の設定も追加します。SSH接続はservicesにsshが登録されていましたが、SSH接続に使用するポート番号をデフォルトの22/tcp以外に設定していると接続が拒否されます。特定のポート番号を登録するには以下のコマンドを実行します。
$ sudo firewall-cmd --add-port=10022/tcp --add-port=10022/udp --permanent
$ sudo firewall-cmd --reload
これでデフォルトのポート番号以外でもSSH接続できるようになりました。
まとめ
ファイアウォールが原因だということは、解決してみればごく当たり前のことだと思うかもしれません。しかし、これまで3年近く問題なく運用を続けてきたVPSだったので、まさか突然ファイアウォールが原因になるだろうということになかなか思い当たりませんでした。それでも調査開始から数時間で解決できたのでまだ良かったのかなと思います。