2026年5月22日

2026年5月22日

WordPressでNginxのプロキシキャッシュを設定する方法|ログイン中・管理画面を除外する設定例

Nginx のプロキシキャッシュ(proxy_cache)を使うと、Nginx の後ろで動いている WordPress(Apache や別のアプリケーションサーバー)が作ったページを Nginx が保存し、次の訪問者には保存したページを返せます。PHP とデータベースの処理が減るので、アクセスが多いサイトでサーバーの負担を下げられます。

この記事では、Nginx をリバースプロキシにして、ポート 8080 の Apache で動く WordPress の前に置く構成を例に、プロキシキャッシュの設定を説明します。設定は 2026年10月時点の Nginx 1.30(stable)で nginx -t による構文チェックと、キャッシュの HIT・BYPASS の動きを確認しています。

なお、Nginx から PHP-FPM を直接呼んでいる構成(fastcgi_pass を使う構成)では、プロキシキャッシュではなく fastcgi_cache を使います。考え方は同じですが、ディレクティブの名前が fastcgi_cache_path・fastcgi_cache_key のように変わります。

構成と前提

役割 待ち受け 内容
Nginx 80(必要なら 443) 訪問者からの接続を受け、キャッシュがあれば返す。なければ Apache に転送する
Apache + PHP(WordPress) 127.0.0.1:8080 WordPress のページを作る

Nginx のプロキシ機能(ngx_http_proxy_module)は、標準でビルドに含まれています。ディストリビューションのパッケージや nginx.org のパッケージを使っていれば、Nginx を作り直す必要はありません(旧版の記事にあった --with-http_proxy_module という configure オプションはありません。外す場合のオプション --without-http_proxy_module があるだけです)。

ステップ1: Apacheを127.0.0.1:8080で待ち受けるようにする

Debian / Ubuntu の Apache では、/etc/apache2/ports.conf の Listen を変えます。

# /etc/apache2/ports.conf
Listen 127.0.0.1:8080

サイトの設定(例: /etc/apache2/sites-available/000-default.conf)の VirtualHost も合わせます。

<VirtualHost 127.0.0.1:8080>
    ServerName example.com
    DocumentRoot /var/www/html
</VirtualHost>

Apache のアクセスログに訪問者の IP アドレスを残したい場合は、mod_remoteip を有効にし、Nginx が送る X-Forwarded-For を読むようにします。

# /etc/apache2/conf-available/remoteip.conf
RemoteIPHeader X-Forwarded-For
RemoteIPInternalProxy 127.0.0.1
sudo a2enmod remoteip
sudo a2enconf remoteip
sudo apache2ctl -t && sudo systemctl restart apache2

ステップ2: Nginxにプロキシキャッシュを設定する

次の内容で、Nginx の設定ファイル(例: /etc/nginx/conf.d/wp-proxy-cache.conf)を作ります。Debian / Ubuntu のパッケージでも nginx.org のパッケージでも、/etc/nginx/conf.d/*.conf は http ブロックの中で読み込まれるので、proxy_cache_path や map をこのファイルに書けます。

# キャッシュの保存場所と大きさ
proxy_cache_path /var/cache/nginx/wp levels=1:2 keys_zone=wpcache:10m
                 max_size=1g inactive=60m use_temp_path=off;

# ログイン中・パスワード保護ページ閲覧中・コメント投稿者・カートに商品がある人はキャッシュしない
map $http_cookie $wp_skip_cookie {
    default 0;
    ~*wordpress_logged_in_ 1;
    ~*wp-postpass_ 1;
    ~*comment_author_ 1;
    ~*woocommerce_items_in_cart 1;
}

# 管理画面・ログイン・WP-Cron・XML-RPC・REST API・プレビューはキャッシュしない
map $request_uri $wp_skip_uri {
    default 0;
    ~*^/wp-admin/ 1;
    ~*^/wp-login\.php 1;
    ~*^/wp-cron\.php 1;
    ~*^/xmlrpc\.php 1;
    ~*^/wp-json/ 1;
    ~*preview=true 1;
}

server {
    listen 80;
    server_name example.com;

    set $skip_cache 0;
    if ($request_method = POST) { set $skip_cache 1; }
    if ($wp_skip_cookie) { set $skip_cache 1; }
    if ($wp_skip_uri) { set $skip_cache 1; }

    location / {
        proxy_pass http://127.0.0.1:8080;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;

        proxy_cache wpcache;
        proxy_cache_key $scheme$request_method$host$request_uri;
        proxy_cache_valid 200 301 302 10m;
        proxy_cache_valid 404 1m;
        proxy_cache_bypass $skip_cache;
        proxy_no_cache $skip_cache;
        proxy_cache_use_stale error timeout updating http_500 http_502 http_503 http_504;
        proxy_cache_background_update on;
        proxy_cache_lock on;

        add_header X-Cache-Status $upstream_cache_status always;
    }
}

主なディレクティブの意味

ディレクティブ 意味
proxy_cache_path キャッシュを置くフォルダーと設定。keys_zone=wpcache:10m はキャッシュの索引を置く共有メモリの名前と大きさ(Nginx の公式ドキュメントでは 1MB で約8千件)、max_size はディスク上の上限、inactive=60m は60分間使われなかったキャッシュを削除する指定、use_temp_path=off は一時ファイルを経由せずキャッシュのフォルダーに直接書く指定
proxy_cache 使うキャッシュの名前(keys_zone で付けた名前)
proxy_cache_key キャッシュを見分けるキー。既定値は $scheme$proxy_host$request_uri で、proxy_pass 先が同じだと複数のドメインが混ざるおそれがあるため、$host を入れている
proxy_cache_valid ステータスコードごとの保存期間。ここでは 200・301・302 を10分、404 を1分
proxy_cache_bypass 値が空でも 0 でもないとき、キャッシュを使わず Apache に転送する
proxy_no_cache 値が空でも 0 でもないとき、Apache からの応答をキャッシュに保存しない
proxy_cache_use_stale Apache がエラーや応答なしのとき、期限切れのキャッシュを返す
proxy_cache_background_update 期限切れのキャッシュを返しながら、裏で新しいページを取りに行く(proxy_cache_use_stale に updating が必要)
proxy_cache_lock 同じページへの同時アクセスで、Apache への問い合わせを1つにまとめる

proxy_cache_bypass と proxy_no_cache は両方指定します。proxy_cache_bypass だけだと、ログイン中のユーザーに作られたページがキャッシュに保存され、ほかの訪問者に表示されるおそれがあります。

また、Nginx は初期設定で、Set-Cookie ヘッダーが付いた応答や、Cache-Control: private・no-cache・no-store が付いた応答を保存しません。WordPress がログイン時などに送る Cookie 付きの応答は、この仕組みでも保存されません。キャッシュの対象になるリクエストの方法も、初期設定では GET と HEAD だけです。

ステップ3: 構文チェックと反映

キャッシュの親フォルダーがなければ作ってから、構文をチェックして反映します。Nginx は起動時に /var/cache/nginx/wp を作り、ワーカーのユーザーに所有者を変えます。

sudo mkdir -p /var/cache/nginx
sudo nginx -t
sudo systemctl reload nginx

nginx -t で syntax is ok と test is successful が出ることを確認してから reload します。

ステップ4: キャッシュが効いているか確認する

X-Cache-Status ヘッダーで、キャッシュの状態を確認できます。同じ URL に2回アクセスすると、1回目は MISS、2回目は HIT になります。

curl -s -o /dev/null -D - https://example.com/sample-page/ | grep -i x-cache-status
curl -s -o /dev/null -D - https://example.com/sample-page/ | grep -i x-cache-status

ログイン中の Cookie を付けたリクエストや、/wp-admin/ へのリクエストは BYPASS になります。

curl -s -o /dev/null -D - -H 'Cookie: wordpress_logged_in_test=1' https://example.com/sample-page/ | grep -i x-cache-status

$upstream_cache_status の主な値は次のとおりです。

値 意味
MISS キャッシュがなく、Apache から取得した
HIT キャッシュから返した
BYPASS proxy_cache_bypass の条件に当たり、キャッシュを使わなかった
EXPIRED キャッシュの期限が切れていたため、Apache から取得した
STALE proxy_cache_use_stale により、期限切れのキャッシュを返した
UPDATING 更新中のため、期限切れのキャッシュを返した

Cookie を付けていないのに何度アクセスしても MISS のままのときは、WordPress のテーマやプラグインが Set-Cookie や Cache-Control: no-cache を送っている可能性があります。curl -I http://127.0.0.1:8080/ -H 'Host: example.com' で Apache の応答ヘッダーを直接確認してください。

X-Cache-Status ヘッダーは確認用です。外部に見せたくない場合は、確認が終わったら add_header の行を消します。

キャッシュを削除する

記事を更新しても、キャッシュの保存期間(この例では10分)が過ぎるまでは古いページが表示されます。無料版の Nginx には、特定の URL のキャッシュを消す proxy_cache_purge ディレクティブがありません(商用版の NGINX Plus の機能です)。

すぐに反映したい場合は、キャッシュのフォルダーの中身を削除します。削除した後のアクセスは MISS になり、新しいページが保存されます。

sudo find /var/cache/nginx/wp -type f -delete

更新をすぐに反映したいページが多い場合は、proxy_cache_valid の時間を短くする、またはキャッシュ削除に対応したサードパーティー製モジュールを組み込む方法があります。

HTTPSをNginxで終端する場合

Nginx で HTTPS を受け、Apache には HTTP で転送する構成では、WordPress が「HTTP で表示されている」と判断し、管理画面へのリダイレクトが繰り返されることがあります。WordPress の公式ドキュメント(Administration Over SSL)にあるとおり、wp-config.php の /* That's all, stop editing! */ より前に次の設定を書きます。

<?php
// Nginx で HTTPS を終端し、バックエンドへ HTTP で渡している場合
if ( isset( $_SERVER['HTTP_X_FORWARDED_PROTO'] ) && 'https' === $_SERVER['HTTP_X_FORWARDED_PROTO'] ) {
	$_SERVER['HTTPS'] = 'on';
}

(wp-config.php にはすでに <?php があるので、追記するのは2行目以降です。)Nginx の設定には、ステップ2のとおり proxy_set_header X-Forwarded-Proto $scheme; が必要です。

注意点

  • キャッシュを入れると、ページの表示ごとに動く処理(アクセス数のカウント、表示のたびに変わる内容など)は、キャッシュの保存期間の間は動かなくなります。会員サイトやネットショップでは、ログインや購入の流れで使う URL と Cookie をすべて除外条件に入れてから使ってください
  • WordPress のキャッシュ系プラグインと同時に使うと、どちらのキャッシュが表示されているか分かりにくくなります。どちらか一方にし、X-Cache-Status で動きを確認します
  • Apache の 8080 番ポートは 127.0.0.1 だけで待ち受け、外部から直接アクセスされないようにします
  • 設定を変えたら、nginx -t で構文を確かめてから reload します

まとめ

  • Nginx の proxy_cache で、Apache などで動く WordPress のページを Nginx に保存して返せる
  • ログイン中の Cookie、管理画面・ログイン・REST API などの URL、POST を proxy_cache_bypass と proxy_no_cache の両方で除外する
  • X-Cache-Status ヘッダーで MISS・HIT・BYPASS を確認する
  • 無料版の Nginx では、キャッシュの削除はフォルダーの中身を消すか、保存期間を短くして対応する
  • HTTPS を Nginx で終端する場合は、wp-config.php で X-Forwarded-Proto を見て $_SERVER['HTTPS'] を設定する

関連記事:

お気軽にご相談ください

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