2026年6月6日

2026年6月6日

Caddy を WordPress の前に置くリバースプロキシ構成|実 IP・HTTPS 判定・リダイレクトループの対処

Caddy を WordPress のリバースプロキシとして使う(Caddy が HTTPS を受け、後ろの Apache や Nginx + PHP で動く WordPress へ HTTP で転送する)構成では、WordPress 側に「自分は HTTPS で公開されている」と教える設定が要ります。これを入れないと、ログイン画面がリダイレクトを繰り返す、画像や CSS が http:// で読まれて混在コンテンツになる、コメントやログイン試行の IP がすべて Caddy の IP になる、という 3 つの問題が起きます。

結論を先にまとめます。

  • Caddy は既定で X-Forwarded-Proto と X-Forwarded-For を付けて転送します。Caddy 側で特別な設定は要りません。
  • WordPress 側の wp-config.php で HTTP_X_FORWARDED_PROTO を見て $_SERVER['HTTPS'] を on にします(WordPress 公式の推奨手順)。
  • サイト URL は https:// で WP_HOME と WP_SITEURL に固定します。
  • 実 IP が必要なら、後ろの Web サーバー(Apache の mod_remoteip、Nginx の real_ip_header)で X-Forwarded-For から復元します。WordPress の中で REMOTE_ADDR を書き換える方法は最後の手段です。
  • 1 台で完結するなら、プロキシではなく Caddy の php_fastcgi で直接 PHP-FPM につなぐ構成のほうが問題が起きにくいです。
Caddy と WordPress の構成の判断。1 台で完結するなら php_fastcgi で直接、既存サーバーを残すならリバースプロキシ構成にして wp-config.php に転送ヘッダーの設定を入れる

Caddy のリバースプロキシそのものの書き方(reverse_proxy、自動 HTTPS の条件、header_up、確認方法)は「Caddy でリバースプロキシを設定する方法」にまとめています。この記事はその続きで、WordPress 固有の問題だけを扱います。

2 つの構成の違い

構成 仕組み 利点 起きやすい問題
直接構成 Caddy → PHP-FPM(php_fastcgi) 設定が少ない。WordPress は HTTPS を正しく認識する テーマやプラグインが .htaccess に依存していると書き換えが要る
プロキシ構成 Caddy → Apache / Nginx → PHP 既存サーバーを残せる。複数サイトの入口を 1 つにできる HTTPS 判定、実 IP、リダイレクトループ

新しく WordPress を立てるなら直接構成が簡単です。Caddy 公式の Caddyfile のパターン集にも WordPress 向けの例があり、xmlrpc.php や wp-content/uploads 内の PHP を止める書き方が示されています。

example.com {
	root * /var/www/wordpress
	encode
	php_fastcgi unix//run/php/php8.3-fpm.sock
	file_server

	@blocked path /xmlrpc.php *.sql /wp-content/uploads/*.php
	rewrite @blocked /index.php
}

以下は、既存の Apache や Nginx を残してプロキシ構成にする場合の手順です。

手順 1: Caddy 側の設定を確認する

Caddyfile は最小構成で足ります。Caddy は転送時にクライアントの IP を X-Forwarded-For に追加し、X-Forwarded-Proto(https)と X-Forwarded-Host を設定します(reverse_proxy の公式ドキュメント)。Host ヘッダーはそのまま渡されるため、後ろの Web サーバーのバーチャルホストはそのまま一致します。

example.com {
	reverse_proxy 127.0.0.1:8080
}

後ろの Web サーバーが同じホストの 8080 番で HTTP を待ち受けている前提です。Caddy の前に CDN(Cloudflare など)があるときは、グローバルオプションで servers { trusted_proxies static <CDN の IP 範囲> } を書かないと、X-Forwarded-For に入るのは CDN の IP になります。

手順 2: WordPress に HTTPS だと教える

WordPress は $_SERVER['HTTPS'] を見て自分が HTTPS かどうかを判断します。プロキシ構成では後ろのサーバーは HTTP で受けるので、この値が空になり、FORCE_SSL_ADMIN やサイト URL の https:// との間で転送が無限に続きます。WordPress 公式の Administration Over SSL が示す対処は、X-Forwarded-Proto を見て HTTPS を補うことです。

wp-config.php の /* That's all, stop editing! */ より前に追記します。

if ( isset( $_SERVER['HTTP_X_FORWARDED_PROTO'] ) && strpos( $_SERVER['HTTP_X_FORWARDED_PROTO'], 'https' ) !== false ) {
	$_SERVER['HTTPS'] = 'on';
}
define( 'FORCE_SSL_ADMIN', true );

X-Forwarded-Proto がカンマ区切りで複数入る環境があるため、公式の例と同じく strpos で https を含むかどうかを見ています。

この設定は「転送ヘッダーを信頼する」設定です。後ろの Web サーバーが Caddy 以外からも直接アクセスできる状態だと、外部から X-Forwarded-Proto: https を付けたリクエストで偽装できます。後ろのサーバーは 127.0.0.1 だけで待ち受けるか、ファイアウォールで Caddy からの接続だけを許可してください。

手順 3: サイト URL を https で固定する

管理画面の「設定 → 一般」の WordPress アドレスとサイトアドレスを https://example.com にします。管理画面に入れない状態なら、wp-config.php で固定します。

define( 'WP_HOME', 'https://example.com' );
define( 'WP_SITEURL', 'https://example.com' );

既存の記事本文や画像の URL が http:// のままだと混在コンテンツになります。WP-CLI の wp search-replace 'http://example.com' 'https://example.com' --dry-run で件数を確認してから置き換えます(実行前にデータベースのバックアップを取ります。手順は「WordPress のデータベースを手動でバックアップする方法」)。

手順 4: 実 IP を復元する

プロキシ構成では、後ろのサーバーから見たアクセス元はすべて Caddy の IP です。そのままだと、コメントの投稿者 IP、ログイン試行の制限、Wordfence などのセキュリティプラグインの IP 判定が働きません。復元は Web サーバー側で行うのが基本です。

Apache(mod_remoteip):

RemoteIPHeader X-Forwarded-For
RemoteIPTrustedProxy 127.0.0.1

Nginx(ngx_http_realip_module):

set_real_ip_from 127.0.0.1;
real_ip_header X-Forwarded-For;
real_ip_recursive on;

set_real_ip_from と RemoteIPTrustedProxy には Caddy の IP だけを書きます。これで REMOTE_ADDR が実 IP になり、WordPress 側の変更は要りません。Web サーバーの設定を変えられない場合に限り、wp-config.php で X-Forwarded-For の先頭を REMOTE_ADDR に入れる方法もありますが、ヘッダーが偽装できる環境では使わないでください。

手順 5: 確認する

# 転送が 1 回で止まるか(301 や 302 が繰り返されていないか)
curl -sIL https://example.com/wp-login.php | grep -i -E "^HTTP|^location"
# 管理画面の URL が https で返るか
curl -s https://example.com/wp-json/ | head -c 300
# 混在コンテンツの有無(http:// の参照)
curl -s https://example.com/ | grep -o 'http://example.com[^"]*' | head

ブラウザーの開発者ツールでもコンソールに Mixed Content の警告が出ていないかを見ます。実 IP は、テスト用のコメントを投稿して管理画面のコメント一覧の IP が自分の IP になっていれば復元できています。

WordPress の観点

このサイトに寄せられる相談で多いのは、「サーバー移転や HTTPS 化のあとでログイン画面が開かない(リダイレクトが繰り返される)」というものです。原因の多くはこの記事の手順 2 と 3 で、wp-config.php の数行で直ります。管理画面に入れない状態での作業になるため、FTP や SSH で wp-config.php を編集できるかどうかを先に確認してください。自分で直すか頼むかの判断は「WordPress の不具合を頼むか自分で直すかの判断基準」を参考にしてください。

よくある質問

Caddy の後ろの WordPress でログインがループします

後ろのサーバーが HTTP で受けているのに、サイト URL が https:// か FORCE_SSL_ADMIN が有効になっている状態です。wp-config.php に HTTP_X_FORWARDED_PROTO を見て $_SERVER['HTTPS'] = 'on' にする記述を入れます。Caddy は既定でこのヘッダーを付けるので、Caddy 側の変更は要りません。

Caddy でヘッダーを付け足す必要はありますか

X-Forwarded-For、X-Forwarded-Proto、X-Forwarded-Host は既定で付きます。X-Real-IP を期待する設定が後ろにあるときだけ header_up X-Real-IP {remote_host} を足します。

プロキシ構成と直接構成のどちらにすべきですか

1 台で完結し、.htaccess に依存するプラグインが無ければ、php_fastcgi の直接構成が簡単で、この記事の問題は起きません。既存の Apache や Nginx を残す理由(他のサイトが同居している、.htaccess の設定が多い)があるときにプロキシ構成を選びます。

Cloudflare と Caddy の両方を通すと IP はどうなりますか

Cloudflare → Caddy → Web サーバーの順に通るので、Caddy に trusted_proxies で Cloudflare の IP 範囲を信頼させないと、X-Forwarded-For に入るのは Cloudflare の IP です。Cloudflare 側の設定は「WordPress に Cloudflare を設定する方法」を参照してください。

まとめ

  • Caddy のリバースプロキシの後ろに WordPress を置くときは、wp-config.php で HTTP_X_FORWARDED_PROTO を見て HTTPS を on にし、WP_HOME / WP_SITEURL を https:// で固定します。
  • 実 IP は Apache の mod_remoteip か Nginx の real_ip_header で復元し、信頼するプロキシは Caddy の IP だけにします。
  • 1 台で済むなら php_fastcgi の直接構成を選ぶと、これらの問題は起きません。

関連記事

参考: WordPress Developer Resources – Administration Over SSL(Using a Reverse Proxy)、Caddy – reverse_proxy、Caddy – Common Caddyfile Patterns

更新履歴: 2026-11-09 全面改訂(定型文を、Caddy の後ろで WordPress を動かすときの HTTPS 判定・実 IP・リダイレクトループの対処に書き換え、php_fastcgi の直接構成との使い分けを追加)。この記事はワードプレス博士(ライトセンド株式会社)が運営しています。

お気軽にご相談ください

お見積りへ お問い合わせへ
▲