前回、AWS のロードバランサで IP ベースの振り分けをすることを試しました。 その際の振り分けルールとして「自分の使用しているグローバル IP だったら振り分ける」ということを行いました。 ですが、nginx のログに自分の使っているグローバル IP が載ってこなかったので、調べました。 (正確には記載場所が違ったということでしたが。)
アクセス元の IP アドレス他での振り分けをまとめたメモです。
目次
比較 nginx のログを比較します。
ログフォーマットは以下のようになってます。
ログフォーマット(/etc/nginx/nginx.confより) 1 2 3 log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for"';
ログを比較します。
ログ比較 1 2 3 4 5 6 7 8 9 10 11 12 # サーバー自身で curl localhost 127.0.0.1 - - [04/Apr/2020:12:24:38 +0000] "GET / HTTP/1.1" 200 3521 "-" "curl/7.61.1" "-" # chromeでサーバーのアドレスに直接アクセス http://xxx.xxx.xxx.xxx xxx.xxx.xxx.xxx - - [04/Apr/2020:12:39:29 +0000] "GET / HTTP/1.1" 304 0 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.149 Safari/537.36" "-" # xxx.xxx.xxx.xxx部分は、アクセス元の使用しているグローバルIPアドレス # chromeでサーバーに中継しているロードバランサーに割り当てたのドメインにアクセス http://[ドメイン] 172.31.39.178 - - [04/Apr/2020:12:43:24 +0000] "GET / HTTP/1.1" 304 0 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.149 Safari/537.36" "xxx.xxx.xxx.xxx" # 172.31.39.178部分は、ALBのIPアドレス? # xxx.xxx.xxx.xxx部分は、アクセス元の使用しているグローバルIPアドレス
ALB の IP アドレス確認してみました。 AWS コンソールの、ネットワークインターフェースを見てみます。
ALB に割り当てられているアドレスで間違いなさそうです。
ログフォーマットと照らし合わせると、 直接リクエストを送ったクライアントの IP は、$remote_addr
で取り扱う。 中継する前のクライアントの IP は、$http_x_forwarded_for
として取り扱うということがわかりました。
ロードバランサーを中継して通信しなかった場合をブロックしてみる 初めに/etc/nginx/nginx.conf
を以下のようにしました。
/etc/nginx/nginx.conf 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 user nginx; worker_processes auto; error_log /var/log/nginx/error.log; pid /run/nginx.pid; include /usr/share/nginx/modules/*.conf; events { worker_connections 1024; } http { log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for"' ; access_log /var/log/nginx/access.log main; sendfile on; tcp_nopush on; tcp_nodelay on; keepalive_timeout 65; types_hash_max_size 2048; include /etc/nginx/mime.types; default_type application/octet-stream; include /etc/nginx/conf.d/*.conf; }
デフォルトでは server の設定がありますが、こちらを削除しました。 詳細な内容はすべてinclude /etc/nginx/conf.d/
以下に作成した.conf
ファイルへ記述することにします。
/etc/nginx/conf.d/direct_block.conf
を以下のように作成します。
/etc/nginx/conf.d/direct_block.conf 1 2 3 4 5 6 7 8 server { listen 80; server_name localhost; error_page 404 /404.html; location / { return 404; } }
/etc/nginx/conf.d/use_domain.conf
を以下のように作成します。
/etc/nginx/conf.d/use_domain.conf 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 server { listen 80; server_name [ロードバランサーに割り当てているドメイン]; root /usr/share/nginx/html; location / { } error_page 404 /404.html; location = /40x.html { } error_page 500 502 503 504 /50x.html; location = /50x.html { } }
できたら、sudo nginx -t
で記述に誤りがないかテストしてからsudo nginx -s reload
を実行して設定を再読み込みします。http://[割り当てたドメイン]
とhttp://[サーバーのグローバルIPアドレス]
にそれぞれアクセス。 後者の時は 404 が返ってくることが確認できます。
return 404;
をreturn 302 https://www.google.com;
と書き換えることで、google へのリダイレクトもできました。
作った 2 ファイルは拡張子を.conf_
とでもして読み込み対象から外します。
443 番ポートを受け付ける 今までサーバーは 80 番ポートを受け付けていました。 443 番ポートを受け付けるようにしてみます。
以下のディレクトリと、ファイルを作成します。ファイルの記述は見分けられればなんでもいいです。
/usr/share/nginx-443
/usr/share/nginx-443/html
/usr/share/nginx-443/html/index.html
/etc/nginx/conf.d/distinction_port.conf
を作成します。 以下の様にしました。
/etc/nginx/conf.d/distinction_port.conf 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 server { listen 80; server_name _; root /usr/share/nginx/html; location / { } } server { listen 443; server_name _; root /usr/share/nginx-443/html; location / { } }
http://[サーバーのグローバルIPアドレス]
とhttp://[サーバーのグローバルIPアドレス]:443
でアクセスしたときの表示が変わりました。 ポートでの振り分けができました。
作ったファイルは拡張子を.conf_
とでもして読み込み対象から外します。
転送前のアクセス元の IP で振り分ける $http_x_forwarded_for
に転送される前の IP が記述されること確認していました。$http_x_forwarded_for
を検証してアクセス元の IP アドレスで振り分けてみます。
以下のディレクトリと、ファイルを作成します。ファイルの記述は見分けられればなんでもいいです。
/usr/share/nginx-forwarded
/usr/share/nginx-forwarded/html
/usr/share/nginx-forwarded/html/index.html
/etc/nginx/conf.d/forwarded_ip.conf
を作成します。 以下の様にしました。
/etc/nginx/conf.d/forwarded_ip.conf 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 server { listen 80; server_name _; error_page 404 /404.html; # アクセス元IPを検証 location / { # 基本はこっちがルート root /usr/share/nginx/html; if ($http_x_forwarded_for = xxx.xxx.xxx.xxx){ # アクセス元IPが指定のものであればこっちがrootになる root /usr/share/nginx-forwarded/html; } } }
指定したグローバル IP を使っている手元の PC でアクセスしたときと、キャリア回線のスマートフォンで確認します。http://[割り当てたドメイン]
にアクセスすると、それぞれでの表示が変わりました。 アクセス元の IP を基準に振り分けできました。
しかし、1 つづつしか設定できないのは不便です。 以下のように/etc/nginx/conf.d/forwarded_ip.conf
を変更しました。
/etc/nginx/conf.d/forwarded_ip.conf 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 geo $from { default nginx; yyy.yyy.yyy.yyy/32 nginx-forwarded; zzz.zzz.zzz.zzz/32 nginx-forwarded; } server { listen 80; server_name _; error_page 404 /404.html; location / { root /usr/share/$from/html; } }
geo ディレクティブを使用することで、アクセス元 IP アドレスの判定が可能でした。 上の場合、判定した結果が $from
に返ってくることになります。
こちらで複数の IP アドレスを記述できました。 ただし、判定されるのは$remote_addr
になるので、記述する IP アドレスはロードバランサーの IP アドレスになります。 少し意図と外れたので、別の方法を試します。
以下のように/etc/nginx/conf.d/forwarded_ip.conf
を変更しました。
/etc/nginx/conf.d/forwarded_ip.conf 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 map $http_x_forwarded_for $local { default 0; xxx.xxx.xxx.xxx 1; aaa.aaa.aaa.aaa 1; } server { listen 80; server_name _; error_page 404 /404.html; location / { root /usr/share/nginx/html; if ($local){ root /usr/share/nginx-forwarded/html; } } }
map ディレクティブを使うことで、$http_x_forwarded_for
の内容を場合分けして、変数に格納できます。 アクセス元の IP アドレスを一か所に複数記述して、振り分けることができました。
調べてみると$http_x_forwarded_for
には、複数の IP アドレスが記述されていることがあるらしく、 正規表現での記述の必要がある様です。 参考:ELB + EC2 + nginx 環境でアクセス元 IP アドレスによる制限をかける
以下のように/etc/nginx/conf.d/forwarded_ip.conf
を直しました。
/etc/nginx/conf.d/forwarded_ip.conf 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 map $http_x_forwarded_for $local { default 0; ~\s*xxx.xxx.xxx.xxx$ 1; ~\s*aaa.aaa.aaa.aaa$ 1; } server { listen 80; server_name _; error_page 404 /404.html; location / { root /usr/share/nginx/html; if ($local){ root /usr/share/nginx-forwarded/html; } } }
$http_x_forwarded_for
に複数の IP が記述される再現できなかったですが、メモとして記載です。
作ったファイルは拡張子を.conf_
とでもして読み込み対象から外します。
ファイルが見つからない時 アクセス先のファイルが見つからなかった時に、指定した先へリダイレクトするようにしてみます。/etc/nginx/conf.d/not_found.conf
を作成します。 以下のようにしました。
/etc/nginx/conf.d/not_found.conf 1 2 3 4 5 6 7 8 9 10 11 12 13 server{ listen 80; server_name _; error_page 404 /404.html; root /usr/share/nginx/html; location /{ try_files $uri $uri/ @not_found; } location @not_found{ return 302 https://www.google.com; } }
@[名称]
を使うことで、ほかのlocation @[名称]
へ飛ばすことができました。
http://[割り当てたドメイン]
とhttp://[割り当てたドメイン]/[適当な文字列]
にアクセスすると、それぞれでの表示が変わりました。http://[割り当てたドメイン]/[適当な文字列]
時は、google にリダイレクトされました。
return 302 https://www.google.com;
の部分は、rewrite ^(.*)$ https://www.google.com;
でも可能でした。
今回は、nginx での振り分け処理を試してみました。 触っていない項目もあるので、もう少し探りたいところです。
ではでは。