通常、nginxではアクセス元IPアドレスはログフォーマットで
$remote_addrと指定した列に書かれます。
ただし、ELBなどロードバランサーを経由した場合、$remote_addにはELBのIPアドレスが書かれ、代わりに$http_x_forwarded_forにアクセス元のIPアドレスが記載されます。
ELB経由でも$remote_addrにアクセス元IPアドレスを書くやり方があったのでメモ。
デフォルト状態でどうなるか確認
EC2にnginx(1.8)を立てます。
# インストール。バージョン確認
$sudo yum install nginx
$nginx -v
nginx version: nginx/1.8.0
# サービスの起動
$sudo service nginx start
# ローカルホストからの接続
$curl http://localhost
$sudo cat /var/log/nginx/access.log
127.0.0.1 - - [10/Oct/2015:08:24:41 +0000] "GET / HTTP/1.1" 200 3770 "-" "Wget/1.16.1 (linux-gnu)" "-"
デフォルトでは以下のようなログフォーマットでした。
...
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
...
ローカルホストからアクセスした際には最初の列($remote_addr)には自身を示す127.0.0.1が記載され、最後の列($http_x_forwardef_for)ではどこからもforwardされていない事を示す-(ハイフン)が記載されています。
次にELBを起動してELB経由でアクセスしてみます。
172.31.12.7 - - [10/Oct/2015:08:41:24 +0000] "GET / HTTP/1.1" 304 0 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.101 Safari/537.36" "101.111.xxx.xx"
$remote_addrにはELBのIPアドレスが記載され、$http_x_forwarded_forは先ほどは-(ハイフン)となっていましたが、こちらはELBでforwardされたため、アクセス元IPが記載されています。
やってみる
利用するhttp_realip_moduleモジュールが組み込まれているか確認します。
$nginx -V |grep realip
nginx version: nginx/1.8.0
built by gcc 4.8.3 20140911 (Red Hat 4.8.3-9) (GCC)
built with OpenSSL 1.0.1k-fips 8 Jan 2015
TLS SNI support enabled
configure arguments: --prefix=/usr/share/nginx --sbin-path=/usr/sbin/nginx --conf-path=/etc/nginx/nginx.conf --error-log-path=/var/log/nginx/error.log --http-log-path=/var/log/nginx/access.log --http-client-body-temp-path=/var/lib/nginx/tmp/client_body --http-proxy-temp-path=/var/lib/nginx/tmp/proxy --http-fastcgi-temp-path=/var/lib/nginx/tmp/fastcgi --http-uwsgi-temp-path=/var/lib/nginx/tmp/uwsgi --http-scgi-temp-path=/var/lib/nginx/tmp/scgi --pid-path=/var/run/nginx.pid --lock-path=/var/lock/subsys/nginx --user=nginx --group=nginx --with-file-aio --with-ipv6 --with-http_ssl_module --with-http_spdy_module --with-http_realip_module --with-http_addition_module --with-http_xslt_module --with-http_image_filter_module --with-http_geoip_module --with-http_sub_module --with-http_dav_module --with-http_flv_module --with-http_mp4_module --with-http_gunzip_module --with-http_gzip_static_module --with-http_random_index_module --with-http_secure_link_module --with-http_degradation_module --with-http_stub_status_module --with-http_perl_module --with-mail --with-mail_ssl_module --with-pcre --with-pcre-jit --with-google_perftools_module --with-debug --with-cc-opt='-O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m64 -mtune=generic' --with-ld-opt=' -Wl,-E'
AmazonLinuxから利用出来るnginxでは組み込まれているようです。
設定ファイルに設定を追記します。
set_real_ip_from にはELBに設定しているサブネットのネットワークアドレスを指定します。
real_ip_header にはアクセス元IPアドレスが記載されるヘッダであるX-Forwarded-Forを設定します。
set_real_ip_from 172.31.0.0/16;
real_ip_header X-Forwarded-For;
再起動します。
$sudo service nginx restart
Stopping nginx: [ OK ]
Starting nginx: [ OK ]
ローカルホストから接続してみます。
$curl http://localhost
# ローカルホストからの接続
$sudo cat /var/log/nginx/access.log |tail -n 5
127.0.0.1 - - [10/Oct/2015:09:08:04 +0000] "GET / HTTP/1.1" 200 3770 "-" "curl/7.40.0" "-"
ローカルホストなどX-Forwarded-Forがない場合(ELB経由でない)場合は設定ファイル変更前後で変わりはないようです。
次に別のEC2からELB経由でアクセスし、アクセスログを確認します。
$sudo cat /var/log/nginx/access.log |tail -n 5
52.68.143.223 - - [10/Oct/2015:09:09:09 +0000] "GET / HTTP/1.1" 200 3770 "-" "curl/7.40.0" "52.68.143.223"
上記のように設定を行うことで$remote_addにはアクセス元のIPアドレスが記載できるようになりました。なお、$http_x_forwarded_forはそのままアクセス元のIPアドレスが継続して記載されています。