Cloudflareを経由してNginxにアクセスする構成で、allow/denyディレクティブによるIP制限が想定通りに動かないケースがあります。特定のIPからのみアクセスを許可したいのに、すべてのリクエストが403になってしまう問題の原因と対処法を解説します。
なぜallowが効かないのか
Cloudflareを通すと、Nginxから見た接続元IPはクライアントの実際のIPではなく、CloudflareのリバースプロキシサーバのIPになります。
# この設定だとうまくいかない
allow 192.0.2.1; # あなたのIP
deny all;
上記の設定は「192.0.2.1からのアクセスのみ許可」という意図ですが、実際にNginxに届くリクエストの送信元IPはCloudflareのIP(例: 104.16.x.x など)です。そのため、すべてのリクエストがdeny allに該当し、403 Forbiddenが返されます。
対処法: real_ip_headerを使う
NginxにはリバースプロキシのIPではなく、実際のクライアントIPを使うための機能があります。Cloudflareの場合、CF-Connecting-IPヘッダーに実際のクライアントIPが格納されています。
# CloudflareのIPレンジを信頼する
set_real_ip_from 103.21.244.0/22;
set_real_ip_from 103.22.200.0/22;
set_real_ip_from 103.31.4.0/22;
set_real_ip_from 104.16.0.0/13;
set_real_ip_from 104.24.0.0/14;
set_real_ip_from 108.162.192.0/18;
set_real_ip_from 131.0.72.0/22;
set_real_ip_from 141.101.64.0/18;
set_real_ip_from 162.158.0.0/15;
set_real_ip_from 172.64.0.0/13;
set_real_ip_from 173.245.48.0/20;
set_real_ip_from 188.114.96.0/20;
set_real_ip_from 190.93.240.0/20;
set_real_ip_from 197.234.240.0/22;
set_real_ip_from 198.41.128.0/17;
# IPv6も必要な場合
set_real_ip_from 2400:cb00::/32;
set_real_ip_from 2606:4700::/32;
set_real_ip_from 2803:f800::/32;
set_real_ip_from 2405:b500::/32;
set_real_ip_from 2405:8100::/32;
set_real_ip_from 2a06:98c0::/29;
set_real_ip_from 2c0f:f248::/32;
# Cloudflareのヘッダーから実際のIPを取得
real_ip_header CF-Connecting-IP;
これにより、$remote_addrにクライアントの実際のIPが入り、allow/denyが正しく機能するようになります。
X-Forwarded-For(XFF)の落とし穴
X-Forwarded-Forヘッダーを使う方法もありますが、注意が必要です。
real_ip_header X-Forwarded-For;
real_ip_recursive on;
XFFヘッダーは複数のプロキシを経由すると複数のIPがカンマ区切りで追加されていきます。また、クライアント側で偽装することも可能です。
real_ip_recursive onを設定すると、信頼できるプロキシのIPを除外して最後の信頼できないIPを使用しますが、設定を誤るとセキュリティホールになる可能性があります。
Cloudflare経由の場合は、CF-Connecting-IPを使う方が確実です。
設定の確認方法
設定が正しく機能しているか確認するには、アクセスログに実際のIPが記録されているかを見ます。
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent"';
$remote_addrに自分のIPが表示されていれば、設定が正しく機能しています。CloudflareのIPが表示されている場合は、set_real_ip_fromの設定を見直してください。
CloudflareのIPレンジの更新
CloudflareのIPレンジは時々変更されます。最新のIPレンジは公式ページ(https://www.cloudflare.com/ips/)で確認できます。
定期的に更新するか、自動化スクリプトでNginxの設定を更新する仕組みを作っておくと安心です。
まとめ
Cloudflare経由でNginxのallow/denyが効かない原因は、接続元IPがCloudflareのIPになっているためです。set_real_ip_fromとreal_ip_header CF-Connecting-IPを設定することで、実際のクライアントIPに基づいたアクセス制御が可能になります。