Nginxで海外からのアクセスを拒否する

(2014.7.17追記)
Apacheの場合の拒否ルールが間違っていたので修正しました。


このWebサイトはアクセス解析ツールAWStatsでアクセス解析を行っていて、ときおりアクセス情報をチェックしているのですが、先週半ばの6月11日、12日は、PVがふだんの4倍から8倍程度まで増えていました。
調べてみたところ、海外からのアクセスが極端に増えたようです。
どのアクセス元IPアドレスでも、PVとヒット数の数値が同じことから、意図はわかりませんが何らかのプログラムによる機械的なアクセスだと思います。
それなのに、User Agentが一般的なWebブラウザと同じようになっているので、AWStatsでは「ロボット/スパイダー」とはみなされず、ふつうにカウントされてしまうのです。

もともとアクセス数はさほど多くありませんし、一応チューニングしてあるのでそれぐらい増えてもサーバーの負荷が上がるということはありません。
それでも、不要なアクセスでサーバーリソースをわずかでも使われるのは嫌なのと、有効なアクセス数が取れないのは痛いです。

これまではWordPressのWordfenceプラグインで、手作業でちょこちょことブロックするIPアドレスを登録していたのですが、それも面倒になってきたので、Webサーバーソフトとして使用しているNginxで海外の特定の国からのアクセスを拒否する設定を行いました。

大まかな手順としては、国別のIPアドレスリストを取得し、それを加工してNginxのアクセス元IPアドレス拒否ルールを作成し、NginxのConfigに組み込みます。
以下、CentOS 6.5における設定例です。

(参考)
Nginxで特定IPアドレスを拒否する

isd国別のIPアドレスリストを取得

国別のIPv4アドレスリストを加工して公開してくださっている方がいるので、これを利用させていただきます。
ありがとうございます!

― 世界の国別 IPv4 アドレス割り当てリスト ―
http://nami.jp/ipv4bycc/

このサイトから、CIDR表記版のgzipファイルをダウンロードします。

 # wget http://nami.jp/ipv4bycc/cidr.txt.gz
 # gunzip cidr.txt.gz

 

このファイルには、CIDR表記のIPアドレスと、そのIPアドレスが割り当てられている国名コードが記載されています。

AD      85.94.160.0/19
AD      91.187.64.0/19
AD      109.111.96.0/19
AD      185.4.52.0/22
AD      194.158.64.0/19
AE      2.48.0.0/14
AE      5.30.0.0/15
...

 

isdNginxのアクセス元IPアドレス拒否ルールを作成

Nginxでは、denyでIPアドレスを拒否します。

deny <IPアドレス>;

 

先ほどダウンロードした国別のIPv4アドレスリストから、sedコマンドで特定の国のIPアドレス行をピックアップ&加工して、Nginxの仕様に合わせた拒否IPアドレスリストファイル /etc/nginx/dropip.conf を作成します。
「アクセスを拒否する特定の国」としては、これまでのアクセスログを参照してアクセスが多く、また、Webサイトの死活監視に使用しているPingdomの監視サーバーがない、CN(中国)、UA(ウクライナ)、RU(ロシア)をピックアップしてみました。
(該当国からこのサイトを見ている方がいらっしゃいましたらすみません。)

 # sed -n 's/^CN\t\(.*\)/deny \1;/p' cidr.txt > /etc/nginx/dropip.conf
 # sed -n 's/^UA\t\(.*\)/deny \1;/p' cidr.txt >> /etc/nginx/dropip.conf
 # sed -n 's/^RU\t\(.*\)/deny \1;/p' cidr.txt >> /etc/nginx/dropip.conf

 

この3か国だけでも、11551行のIPアドレスアクセス拒否ルールが作成されました。

ちなみに、Apacheであれば下記のようにして拒否ルールを作成できます。

 # echo "Order allow,deny" > .htaccess
 # echo "Allow from all" >> .htaccess
 # sed -n 's/^CN\t/Deny from /p' cidr.txt >> .htaccess

 

isdNginxのConfigに組み込み

Nginxで、拒否IPアドレスリストファイル /etc/nginx/dropip.conf をincludeします。

Nginxは基本的に上から順に適用されるので、includeする箇所としては、グローバル設定の /etc/nginx/nginx.conf で、conf.d/*.conf を読み込む前としてしまいます。
これで、複数の VirtualHost に対しても適用されます。

 # vi /etc/nginx/nginx.conf

--
http {
...
    include /etc/nginx/dropip.conf;
    include /etc/nginx/conf.d/*.conf;
}
--

 

Nginxをreloadして反映させます。

 # /etc/init.d/nginx configtest
 # /etc/init.d/nginx reload

 

設定後は、日本国内から問題なくアクセスできることと、Nginxのエラーログに該当のIPアドレスからのアクセス拒否が記録されていることを確認します。
Nginxのエラーログには、アクセス拒否は下記のように、’access forbidden by rule’と記録されます。

2014/06/16 12:56:51 [error] 1443#0: *357366 access forbidden by rule, client: 27.xxx.xxx.xxx, server: inaba-serverdesign.jp, request: "GET / HTTP/1.1", host: "inaba-serverdesign.jp"

 

公開されている「IPv4 アドレス割り当てリスト」は基本的に毎日更新されるとのことです。
wgetからdropip.confの作成、Nginxへの反映までの一連の処理を自動化して毎日アップデートすることもできますが、今のところそこまでしなくてもよいかな、と。

また、iptablesの拒否ルールに追加してHTTP以外のパケットも拒否してしまうこともできますが、昔、iptablesのルールに懲りすぎてWebサーバーの性能を著しく劣化させてしまった痛い経験があるので、今回はやめておきます。

isdまとめ

公開されている「国別のIPアドレスリスト」を元に、Nginxで特定の国からのアクセスを拒否する設定を行いました。

この設定後、アクセス解析ツールに現れるアクセス数が激減してしまいましたが(笑)、本当のアクセス数がわかるようになりました。
無用なアクセスはなくなってほしいものです。。

(関連記事)
・ipsetとiptablesでSSHを日本国内からの接続に限定する (CentOS 6)
https://inaba-serverdesign.jp/blog/20150209/ipset_iptables_country_centos6.html

Follow me!