ELB経由のnginxでアクセス元IPアドレスをアクセスログの$remote_addrとして書くようにする

通常、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)" "-"
```

デフォルトでは以下のようなログフォーマットでした。

```/etc/nginx/nginx.conf
...
    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を設定します。


```/etc/nginx/nginx.conf
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アドレスが継続して記載されています。