CDNを入れたら「アクセスログが全部同じIP」になりました…。
こんにちは!「LINUX工房」管理人の「リナックス先生」です。
全8回の応用講座、お疲れ様でした。
これまでの知識で、あなたのNginxサーバーは単体としては最強クラスに仕上がっているはずです。
しかし、実際の商用サービスでは、Nginxがインターネットの最前線に立つことは少なくなってきました。
その前段に、CDN(Content Delivery Network)が配置されることが当たり前だからです。
Cloudflare、AWS CloudFront、Fastly……これらは強力な味方ですが、Nginxの設定を間違えると、とんでもないトラブルを引き起こす「諸刃の剣」でもあります。
先生、助けてください!
サイトを高速化しようと思ってCloudflareを導入したんです。
そしたら、アクセスログのIPアドレスが全部CloudflareのIPになっちゃって、誰がアクセスしてるのか全然わからなくなりました!
あと、WAFで設定した「社内IP制限」も効かなくなって、誰でも管理画面に入れるようになっちゃって……これじゃセキュリティ崩壊ですよ!
あらら、典型的な「CDN導入の失敗例」ね。
CDNを通すと、Nginxから見た接続元はすべてCDNのエッジサーバーになってしまうの。
でも安心して。Nginxには、CDN越しでも「真のクライアントIP」を見抜く機能が標準で備わっているわ。
今回は、CDNとNginxを正しく連携させて、高速化とセキュリティを両立させるプロの設定術を教えるわね!
本記事では、CDN導入時に必須となる「Real IP」の設定、恐怖の「無限リダイレクトループ」の回避策、そしてCDNをすり抜けてオリジンサーバーを直接攻撃されないための防御策までを徹底解説します。
📚 Nginx応用講座(全8回)アーカイブ
これまでの講座で学んだ知識を組み合わせることで、より強固なインフラが構築できます。
- 【第1回】大規模負荷分散とキャッシュ戦略。数万リクエストをさばく「Proxy Cache」と「Upstream」の極意
- 【第2回】WAF(Web Application Firewall)の構築。ModSecurityと最新のNginxセキュリティ
- 【第3回】マイクロサービス時代のルーティング。gRPC、WebSocket、認証プロキシ(auth_request)の統合
- 【第4回】Nginxをプログラマブルに。Lua言語(OpenResty)による動的処理と機能拡張
- 【第5回】絶対停止させない高可用性(HA)。KeepalivedによるVIP管理とフェイルオーバー
- 【第6回】可観測性(Observability)の確保。Prometheus/Grafana連携とカスタムメトリクス
- 【第7回】動的モジュールとカスタムビルド。必要な機能だけを組み込む軽量化テクニック
- 【第8回】Kubernetes Ingress Controller入門。クラウドネイティブ時代のNginx運用
第1章:なぜ「IPアドレス」が偽装されるのか?
通常、クライアント(スマホやPC)がNginxにアクセスすると、TCPパケットの送信元IPアドレスはクライアントのものです。
しかし、CDNを挟むと通信経路は以下のようになります。
[Client] ---> [CDN Edge Server] ---> [Nginx (Origin)]
Nginxから見ると、直前の接続相手は「CDNのエッジサーバー」です。
そのため、アクセスログの $remote_addr にはCDNのIPアドレスが記録されます。
これが原因で、以下の機能が全滅します。
- アクセスログ解析(全部同じIPに見える)
- IPアドレス制限(allow/deny)
- GeoIP(国別制限)
- Rate Limiting(IPごとの制限)
救世主「X-Forwarded-For」
CDNは親切にも、「本当の接続元IP」をHTTPヘッダーに乗せて送ってくれます。
それが X-Forwarded-For です。
Nginx側で「送信元IPではなく、このヘッダーの中身を信じる」ように設定を変更する必要があります。
第2章:ngx_http_realip_module の正しい設定
Nginxには、この問題を解決するための標準モジュール ngx_http_realip_module があります。
(通常はデフォルトでビルドされていますが、nginx -V で --with-http_realip_module があるか確認してください)
設定手順
nginx.conf または conf.d/default.conf に以下のように記述します。
# CloudflareのIPアドレス帯域を信頼する(2026年時点の例) set_real_ip_from 173.245.48.0/20; 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 141.101.64.0/18; set_real_ip_from 108.162.192.0/18; set_real_ip_from 190.93.240.0/20; set_real_ip_from 188.114.96.0/20; set_real_ip_from 197.234.240.0/22; set_real_ip_from 198.41.128.0/17; set_real_ip_from 162.158.0.0/15; set_real_ip_from 104.16.0.0/13; set_real_ip_from 104.24.0.0/14; set_real_ip_from 172.64.0.0/13; set_real_ip_from 131.0.72.0/22; # 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; # どのヘッダーを真実として扱うか real_ip_header CF-Connecting-IP; # Cloudflareの場合 # real_ip_header X-Forwarded-For; # AWS CloudFrontなどの場合
解説:
set_real_ip_from で指定したIPアドレス(CDN)から来たリクエストに限り、real_ip_header で指定したヘッダーの中身を $remote_addr として上書きします。
これにより、ログ出力やアクセス制限の設定を変更することなく、これまで通り扱えるようになります。
💡 プロの自動化テクニック
CDNのIPアドレス帯域は不定期に変更されます。手動更新は事故の元です。
cronを使って定期的に公式サイトからIPリストを取得し、confファイルを生成するスクリプトを仕込んでおくのが正解です。
#!/bin/bash # update-cloudflare-ip.sh curl -s https://www.cloudflare.com/ips-v4 | sed 's/^/set_real_ip_from /; s/$/;/' > /etc/nginx/conf.d/cloudflare-ip.conf curl -s https://www.cloudflare.com/ips-v6 | sed 's/^/set_real_ip_from /; s/$/;/' >> /etc/nginx/conf.d/cloudflare-ip.conf systemctl reload nginx
第3章:恐怖の「無限リダイレクトループ」を防ぐ
CDN導入後、サイトにアクセスすると「リダイレクトが多すぎます(ERR_TOO_MANY_REDIRECTS)」と表示されて真っ白になる……。
これは、CDNとNginxの間で「HTTPS化の認識齟齬」が起きている時に発生します。
発生メカニズム
- ユーザーが
https://example.comにアクセス。 - CDNはHTTPSで受け付け、裏側のNginxにはHTTP(80番ポート)で転送する(Flexible SSL設定など)。
- Nginxは「HTTPで来たからHTTPSにリダイレクトしなきゃ!」と判断し、
301 https://example.comを返す。 - ユーザー(ブラウザ)は言われた通り
https://example.comに再アクセス。 - 1に戻る(永遠に繰り返し)。
解決策:X-Forwarded-Proto を見る
CDNは「ユーザーとはHTTPSで通信しましたよ」という情報を X-Forwarded-Proto: https というヘッダーで伝えてくれます。
Nginx側でこれを検知し、HTTPSとみなすように設定します。
nginx.conf(httpブロック内):
# X-Forwarded-Protoがhttpsならon、それ以外ならoffと判定
map $http_x_forwarded_proto $fe_https {
default off;
https on;
}
server {
listen 80;
# 既にHTTPSならリダイレクトしない
if ($fe_https = on) {
break;
}
# HTTPならHTTPSへリダイレクト
if ($fe_https = off) {
return 301 https://$host$request_uri;
}
}
また、WordPressなどのアプリ側でも、このヘッダーを認識させる設定(wp-config.php の修正など)が必要になる場合があります。
第4章:キャッシュ戦略の階層化(ブラウザ vs CDN)
第1回の講座で「ブラウザキャッシュ」の設定を紹介しましたが、CDNが入ると話は複雑になります。
「ブラウザにはキャッシュさせたいけど、CDNにはさせたくない」あるいはその逆など、制御を分ける必要があります。
Cache-Controlヘッダーの使い分け
s-maxage というディレクティブを使うと、CDN(共有キャッシュ)専用の有効期限を指定できます。
location ~* \.(jpg|png|css|js)$ {
# ブラウザ: 1時間 (max-age=3600)
# CDN: 1日 (s-maxage=86400)
add_header Cache-Control "public, max-age=3600, s-maxage=86400";
}
動的コンテンツの事故防止
管理画面やマイページなど、キャッシュしてはいけないページには、明示的に private または no-store を返します。
location /admin/ {
add_header Cache-Control "no-store, no-cache, private";
}
CDNによっては、Nginxが Set-Cookie ヘッダーを返すと自動的にキャッシュを無効化してくれる機能もありますが、過信せずに明示的にヘッダーで制御するのがプロの作法です。
第5章:オリジンサーバーを隠蔽せよ(Origin Protection)
CDNを導入しても、Nginx(オリジン)のグローバルIPアドレスがバレてしまえば、攻撃者はCDNを迂回して直接攻撃(DDoSなど)を仕掛けてきます。
これを防ぐには、「CDN経由のアクセス以外はすべて拒否する」設定が必要です。
レベル1:IPアドレスによる制限
第2章で設定した set_real_ip_from は「IPを書き換える」設定ですが、アクセス自体は許可しています。
これとは別に、allow / deny ディレクティブを使って制限します。
server {
listen 80;
# CloudflareのIPのみ許可(includeを使うと管理しやすい)
include /etc/nginx/conf.d/cloudflare-allow.conf;
# それ以外は拒否
deny all;
}
※cloudflare-allow.conf には allow 173.245.48.0/20; といった記述を羅列します。
レベル2:Authenticated Origin Pulls(相互TLS認証)
IPアドレス制限だけでは不安な場合(IP偽装など)、クライアント証明書を使った認証を行います。
Cloudflare等が発行する証明書をNginxに設置し、「その証明書を持ってきたアクセスしか受け入れない」ようにします。
server {
listen 443 ssl;
# クライアント証明書の検証を有効化
ssl_client_certificate /etc/nginx/certs/cloudflare.crt;
ssl_verify_client on;
}
ここまでやれば、オリジンサーバーは完全に要塞化され、CDN経由の正規ルート以外からは指一本触れられなくなります。
第6章:ログ解析の拡張(CDN独自の情報を記録する)
CDNは、リクエストに独自のヘッダーを付与してオリジンに送ってくれます。
これらをログに残すと、トラブルシューティングが劇的に楽になります。
Cloudflareの場合
- CF-Ray: リクエストごとのユニークID。サポートに問い合わせる時に必須。
- CF-IPCountry: アクセス元の国コード。
- CF-Connecting-IP: 接続元IP。
ログフォーマットの定義
nginx.conf の http ブロックで定義します。
log_format cdn_combined '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent" '
'RayID:$http_cf_ray Country:$http_cf_ipcountry';
access_log /var/log/nginx/access.log cdn_combined;
これで、ログファイルを見るだけで「どこの国からのアクセスか」「どのRayIDでエラーが出たか」が一目瞭然になります。
第7章:トラブルシューティング集
最後に、CDN連携時によくあるトラブルと解決策をまとめます。
Q1. 502 Bad Gateway が頻発する
原因: Nginx側の処理タイムアウトや、ヘッダーサイズオーバー。
対策: CDNは大きなヘッダーを付与することがあるため、バッファサイズを増やします。
large_client_header_buffers 4 16k; fastcgi_buffers 16 16k;
Q2. サイトのデザインが崩れる(CSSが当たらない)
原因: Mixed Content(HTTPSのページ内でHTTPのCSSを読み込んでいる)。
対策: 第3章のリダイレクト設定を見直すか、アプリ側で生成するURLを強制的にHTTPSにする(WordPressなら FORCE_SSL_ADMIN など)。
Q3. Nginxの設定を変えたのに反映されない
原因: CDNが古いコンテンツを強力にキャッシュしている。
対策: Nginxをreloadしただけではダメです。CDNの管理画面から「キャッシュパージ(Purge Cache)」を行う必要があります。
まとめ:CDNは「魔法」ではない。正しい設定で飼い慣らせ。
お疲れ様でした!
今回は、CDNとNginxを連携させるための必須テクニックを解説しました。
今回の重要ポイント:
ngx_http_realip_moduleでCDNのIPを剥がし、真のIPを取得する。X-Forwarded-Protoを見て、無限リダイレクトループを防ぐ。s-maxageヘッダーで、ブラウザとCDNのキャッシュ期間を使い分ける。- IP制限や相互TLS認証で、オリジンサーバーをCDN以外から隠蔽する。
CDNは導入するだけでサイトが速くなる「魔法の杖」と思われがちですが、裏側のNginxで適切な受け入れ態勢を作らなければ、逆にトラブルの温床になります。
しかし、今回学んだ設定を施せば、CDNのパワーを最大限に引き出し、世界中どこからでも爆速で安全なWebサイトを提供できるはずです。
これで本当にNginx講座は完結です。
基本から応用、そしてCDN連携まで。
あなたが学んだ知識は、個人ブログから大規模な商用サービスまで、あらゆるインフラを支える強固な土台となります。
自信を持って、最高のサーバーを構築してください!
Good Luck, and Keep It Running!
▼ CDN連携環境をテストする ▼
Cloudflareと連携実験
「VPS」で自分専用環境
大規模配信基盤を支える
「ITエンジニア転職」

コメント