2026年7月24日
2026年7月24日
VarnishでWordPressのページをキャッシュする設定(Nginx・HTTPS構成)
Varnish は、Web サーバーの前に置いて HTTP の応答をメモリに保存し、同じページへの次のアクセスには WordPress を動かさずに保存した内容を返すキャッシュサーバー(リバースプロキシ)です。ログインしていない訪問者向けのページを Varnish から返せば、PHP と DB の処理が減り、アクセスが集中したときにもサーバーが持ちこたえやすくなります。
この記事では、Ubuntu 24.04 のサーバー1台で、Nginx・Varnish・PHP-FPM を組み合わせて WordPress のページをキャッシュする手順を説明します。2026年11月時点で Ubuntu 24.04 の標準パッケージから入る Varnish 7.1.1 と Nginx 1.24.0 で、設定の読み込み、キャッシュの HIT/MISS、ログイン中のキャッシュ除外、削除(PURGE)の動作を確認しています。
構成
Varnish は HTTPS を扱えません。そのため、HTTPS の受け付けは Nginx が行い、復号したリクエストを Varnish に渡します。Varnish にキャッシュが無いときは、裏側の Nginx(PHP-FPM で WordPress を動かす)に取りに行きます。
| 順番 | 役割 | 待ち受け |
|---|---|---|
| 1 | Nginx(外側): HTTPS を受け、Varnish に渡す | 80・443(インターネット向け) |
| 2 | Varnish: キャッシュを返す、無ければ裏側に取りに行く | 127.0.0.1:6081 |
| 3 | Nginx(内側): PHP-FPM で WordPress を動かす | 127.0.0.1:8080 |
Varnish と内側の Nginx は 127.0.0.1 だけで待ち受け、インターネットから直接アクセスできないようにします。
前提:
- Nginx + PHP-FPM で WordPress が動いていること(WordPress は
/var/www/htmlにある前提で書きます) - Let's Encrypt などの証明書を取得済みであること
- 作業前にサーバー設定と WordPress のバックアップを取っておくこと
手順1: Varnishをインストールする
sudo apt update
sudo apt install varnish
varnishd -V
Ubuntu のパッケージは、初期状態ですべてのアドレスの 6081 番で待ち受け、キャッシュ用のメモリは 256MB です。待ち受けを 127.0.0.1 に限るため、systemd の設定を上書きします。
sudo systemctl edit varnish
開いた編集画面に次の内容を書いて保存します。ExecStart= の空行は、元の起動コマンドを消すために必要です。
[Service]
ExecStart=
ExecStart=/usr/sbin/varnishd -j unix,user=vcache -F -a 127.0.0.1:6081 -T localhost:6082 -f /etc/varnish/default.vcl -S /etc/varnish/secret -s malloc,256m
-s malloc,256m がキャッシュに使うメモリの上限です。サーバーのメモリに合わせて変えてください。
手順2: WordPress用のVCLを書く
Varnish の動きは /etc/varnish/default.vcl に VCL という言語で書きます。元のファイルを残してから、次の内容に置き換えます。
sudo cp /etc/varnish/default.vcl /etc/varnish/default.vcl.orig
sudo nano /etc/varnish/default.vcl
vcl 4.1;
# WordPress を動かしている Web サーバー(Varnish の裏側)
backend default {
.host = "127.0.0.1";
.port = "8080";
}
# PURGE を受け付ける送信元(WordPress と同じサーバー)
acl purge {
"localhost";
"127.0.0.1";
"::1";
}
sub vcl_recv {
# Proxy Cache Purge プラグインからの削除要求
if (req.method == "PURGE") {
if (client.ip !~ purge) {
return (synth(405, "Not allowed"));
}
if (req.http.X-Purge-Method == "regex") {
ban("req.http.host == " + req.http.host + " && req.url ~ " + req.url);
return (synth(200, "Banned"));
}
return (purge);
}
# GET と HEAD 以外(フォーム送信など)はキャッシュしない
if (req.method != "GET" && req.method != "HEAD") {
return (pass);
}
# 管理画面・ログイン・プレビュー・cron などはキャッシュしない
if (req.url ~ "^/wp-(admin|login\.php|cron\.php)" ||
req.url ~ "^/xmlrpc\.php" ||
req.url ~ "[?&]preview=true") {
return (pass);
}
# ログイン中・パスワード保護ページ閲覧中・コメント投稿者はキャッシュしない
if (req.http.Cookie ~ "wordpress_logged_in_|wordpress_sec_|wp-postpass_|comment_author_") {
return (pass);
}
# それ以外の Cookie(アクセス解析など)は外してキャッシュ対象にする
unset req.http.Cookie;
return (hash);
}
sub vcl_backend_response {
# Cache-Control の無い通常ページは 10 分保持し、期限切れ後も 1 時間は古い内容を返せるようにする
if (beresp.status == 200 && !beresp.http.Cache-Control && !beresp.http.Set-Cookie) {
set beresp.ttl = 10m;
}
set beresp.grace = 1h;
}
sub vcl_deliver {
# 動作確認用: キャッシュから返したかどうかをヘッダーで示す
if (obj.hits > 0) {
set resp.http.X-Cache = "HIT";
} else {
set resp.http.X-Cache = "MISS";
}
}
この VCL のポイントは次のとおりです。
- キャッシュしないもの: 管理画面、ログイン画面、プレビュー、フォームの送信(POST)、ログイン中の訪問者(
wordpress_logged_in_の Cookie を持つ)など。ログイン中の画面がほかの人に見えてしまう事故を防ぎます。 - Cookie の扱い: Varnish は、初期状態では Cookie 付きのリクエストをキャッシュしません。アクセス解析などの Cookie が付いているだけでキャッシュが効かなくなるので、WordPress が使う Cookie 以外は外しています。ネットショップなど、ほかにも訪問者ごとに表示が変わる Cookie を使っている場合は、その名前も
passの条件に加えます。 - PURGE: 同じサーバー(127.0.0.1)から来た PURGE だけを受け付けます。
X-Purge-Method: regex付きのものは、正規表現に合う URL をまとめて無効にします(Proxy Cache Purge の「全削除」がこの形で送られます)。 - X-Cache: 確認のためのヘッダーです。動作を確かめたあとは消してもかまいません。
書き終えたら、文法を確認してから起動し直します。OK と表示されれば文法の誤りはありません。誤りがあるときは、行番号つきのエラーが表示されます。
sudo varnishd -C -f /etc/varnish/default.vcl > /dev/null 2>&1 && echo OK || sudo varnishd -C -f /etc/varnish/default.vcl 2>&1 | head -n 20
sudo systemctl restart varnish
以後、VCL だけを変えたときは sudo systemctl reload varnish で、キャッシュを残したまま読み込み直せます。
手順3: Nginxを外側と内側に分ける
外側(HTTPS を受けて Varnish に渡す)の設定を /etc/nginx/sites-available/example.com-front に書きます。example.com と証明書のパスは自分のものに変えてください。
# 外側: HTTPS を受けて Varnish に渡す
server {
listen 80;
listen [::]:80;
server_name example.com;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
listen [::]:443 ssl;
server_name example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
client_max_body_size 64m;
# 外部からの PURGE は受け付けない
if ($request_method = PURGE) {
return 405;
}
location / {
proxy_pass http://127.0.0.1:6081;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto https;
}
}
Varnish から見ると、すべてのリクエストが外側の Nginx(127.0.0.1)から来ます。外側で PURGE を止めておかないと、インターネットから送られた PURGE も「127.0.0.1 から来たもの」として受け付けられてしまうため、ここで 405 を返します。
内側(WordPress を動かす)の設定を /etc/nginx/sites-available/example.com-backend に書きます。今まで WordPress を動かしていた server ブロックの listen を 127.0.0.1:8080 に変え、SSL の設定を外したものです。
# 内側: Varnish からだけ受けて WordPress を動かす
server {
listen 127.0.0.1:8080;
server_name example.com;
root /var/www/html;
index index.php;
# 訪問者の IP アドレスを X-Forwarded-For から取り出す
set_real_ip_from 127.0.0.1;
real_ip_header X-Forwarded-For;
real_ip_recursive on;
location / {
try_files $uri $uri/ /index.php?$args;
}
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/run/php/php8.3-fpm.sock;
}
}
set_real_ip_from などの3行で、WordPress やアクセスログに記録される IP アドレスが、127.0.0.1 ではなく訪問者のものになります。
古い設定を無効にし、2つの設定を有効にしてから、文法を確認して読み込み直します。
sudo ln -s /etc/nginx/sites-available/example.com-front /etc/nginx/sites-enabled/
sudo ln -s /etc/nginx/sites-available/example.com-backend /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx
sites-enabled に今まで使っていた同じドメインの設定が残っていると、待ち受けが重なります。古いものは sites-enabled から外してください。
手順4: WordPressにHTTPSであることを伝える
内側の Nginx は HTTP で動いているため、そのままだと WordPress は「HTTP でアクセスされている」と判断し、管理画面へのログインでリダイレクトが繰り返されることがあります。wp-config.php の「編集が必要なのはここまでです」の行より上に、次を加えます。
<?php
// 外側の Nginx が付けた X-Forwarded-Proto を見て、HTTPS で動いていると WordPress に伝える
if ( isset( $_SERVER['HTTP_X_FORWARDED_PROTO'] ) && 'https' === $_SERVER['HTTP_X_FORWARDED_PROTO'] ) {
$_SERVER['HTTPS'] = 'on';
}
この書き方は、内側の Nginx に 127.0.0.1 からしか届かない構成であることが前提です。内側をインターネットに公開すると、だれでもこのヘッダーを付けられるので注意してください。
手順5: 更新時にキャッシュを消すプラグインを入れる
Varnish は、記事を更新しても保存期間(この VCL では 10 分)が過ぎるまで古いページを返します。更新したらすぐに反映されるよう、プラグイン「Proxy Cache Purge」(スラッグ varnish-http-purge)を入れます。投稿の更新やコメントの追加のときに、その記事やトップページなどの URL に PURGE を送ってくれます。
cd /var/www/html
wp plugin install varnish-http-purge --activate
wp config set VHP_VARNISH_IP 127.0.0.1:6081
VHP_VARNISH_IP は PURGE の送り先です。設定しないとサイトのドメイン名(外側の Nginx)に送られ、上で止めた PURGE として扱われてしまうため、Varnish の待ち受けアドレスを直接指定します。
このプラグインはパーマリンク設定が「基本」以外(投稿名など)になっていることが必要です。管理画面からキャッシュをすべて消す操作もできます。
手順6: 動作を確認する
ログインしていない状態で同じページに2回アクセスし、X-Cache を確認します。
curl -sI https://example.com/ | grep -i x-cache
curl -sI https://example.com/ | grep -i x-cache
1回目が MISS、2回目が HIT になれば、キャッシュが効いています。ログイン中を想定した Cookie を付けると、キャッシュされないことも確かめられます。
curl -sI -H 'Cookie: wordpress_logged_in_test=1' https://example.com/ | grep -i x-cache
プラグインからの削除は WP-CLI で試せます。
wp varnish purge https://example.com/ --url-only
curl -sI https://example.com/ | grep -i x-cache
削除の直後は MISS になります。キャッシュの効き具合は varnishstat で確認できます。
varnishstat -1 -f MAIN.cache_hit -f MAIN.cache_miss
注意点
- キャッシュ系プラグインとの重複: ページキャッシュを作るプラグイン(WP Super Cache など)と併用すると、どちらのキャッシュが原因で古い内容が出ているのか分かりにくくなります。ページのキャッシュは Varnish に任せ、プラグイン側のページキャッシュは止めることを検討してください。
- 訪問者ごとに内容が変わるページ: カート、マイページ、フォームの完了画面などは、Cookie や URL を
passの条件に加えてキャッシュから外します。設定後は、ログインしていない状態とログインした状態の両方で表示を確かめます。 - うまく反映されないとき: 更新したのに古い内容が出る場合は、
varnishlog -g request -q 'ReqMethod eq "PURGE"'を動かしたまま記事を更新し、PURGE が届いているかを確認します。 - やめるとき: 外側の Nginx の
proxy_passを内側の WordPress に向けるか、元の設定に戻せば Varnish を通らなくなります。
まとめ
- Varnish は HTTPS を扱えないので、外側の Nginx で HTTPS を受けて 127.0.0.1:6081 の Varnish に渡し、その裏の 127.0.0.1:8080 で WordPress を動かす
- VCL では、管理画面・ログイン中・フォーム送信をキャッシュせず、WordPress 以外の Cookie を外す
- PURGE は Varnish 側で 127.0.0.1 に限り、外側の Nginx でも止める
wp-config.phpでX-Forwarded-Protoを見て HTTPS を伝える- Proxy Cache Purge を入れ、
VHP_VARNISH_IPに127.0.0.1:6081を指定する
関連記事: