2026年5月31日

2026年5月31日

Nginxのカスタムエラーページ設定方法|error_pageの書き方とWordPressの404・502との関係

Nginx のカスタムエラーページは、error_page ディレクティブでステータスコードと表示するファイルを結び付け、そのファイルを置く location に internal を付けるだけで設定できます。ただし WordPress サイトでは、404 ページの多くは Nginx ではなく WordPress(テーマの 404 テンプレート)が出しているため、Nginx 側で何を担当させるかを決めずに設定すると「テーマの 404 が消えた」「存在しないページが 200 で返る」といった問題が起きます。この記事では、基本の書き方、WordPress と組み合わせるときの役割分担、PHP-FPM が止まったときの 502 / 504 ページ、メンテナンス用の 503 ページ、反映後の確認方法までを説明します。

error_page の基本の書き方

error_page は「このステータスコードになったら、この URI を内部的に表示する」という指定です。http・server・location のいずれのブロックにも書けますが、サイト単位で管理しやすい server ブロックに書くのが一般的です。

server {
    listen 80;
    server_name example.com;
    root /var/www/example.com;

    error_page 404 /errors/404.html;
    error_page 500 502 503 504 /errors/50x.html;

    location ^~ /errors/ {
        root /var/www/example.com;
        internal;
    }
}

ポイントは三つあります。

  • 一つの error_page に複数のコードを並べられます。5xx 系をまとめて一つのページにするのはよくある書き方です。
  • internal を付けると、その location は Nginx 内部の転送からしか使えなくなります。利用者が /errors/404.html を直接開いても 404 になり、エラーページそのものが検索結果に載るのを防げます。
  • エラーページは、PHP やデータベースに頼らない静的な HTML にします。5xx は「PHP やデータベースが動いていない」ときに出るため、エラーページまで PHP で作ると表示できなくなります。CSS は HTML 内に直接書き、画像も最小限にしておくと安心です。

ディストリビューションのパッケージで Nginx を入れた場合、/usr/share/nginx/html/50x.html のような既定のエラーページと、それを使う設定例が最初から入っていることがあります(2026年10月現在)。内容はパッケージや版によって異なります。既定の設定を残したまま独自の設定を足すと、どちらが効いているか分かりにくくなるので、nginx -T で読み込まれている設定全体を確認してから編集してください。

sudo nginx -T 2>/dev/null | grep -n "error_page"

継承のルールに注意する

error_page は、その階層に error_page が一つも書かれていない場合に限って、上の階層の設定を引き継ぎます。たとえば server に 404 と 5xx を書き、ある location の中で 403 だけを指定すると、その location では server の 404 と 5xx の設定は使われなくなります。location で追加するときは、必要なコードをまとめて書き直すと混乱しません。

ステータスコードを変えない

error_page には、表示するページと同時にステータスコードを書き換える書き方があります。

# 避けたい例:存在しないページを 200 として返してしまう
error_page 404 =200 /errors/404.html;

この書き方では、ページが見つからないのに「成功(200)」として返ります。検索エンジンからは中身の薄いページが大量にあるように見え、Google Search Console では「ソフト 404」として報告されることがあります。エラーページは見た目だけを差し替え、ステータスコードは元の 404 や 503 のまま返すのが基本です。

= の後に何も書かない error_page 404 = @fallback; という形は、転送先が返したコードをそのまま使う指定で、名前付き location(@ で始まる location)に処理を渡すときに使います。

WordPress と組み合わせるときの役割分担

WordPress を Nginx で動かす一般的な設定では、次の try_files によって、存在しないファイルへのリクエストは index.php に渡されます。

location / {
    try_files $uri $uri/ /index.php?$args;
}

この構成では、存在しない記事の URL は WordPress が処理し、テーマの 404 テンプレートで 404 を返します。Nginx の error_page 404 が使われるのは、try_files $uri =404; のように WordPress へ渡さない location だけです。役割は次のように分けると整理できます。

  • 記事やページの 404:WordPress(テーマの 404 テンプレート)が担当。デザインもサイトに合わせられます。
  • 画像・CSS・JS など静的ファイルの 404:Nginx が担当。ここで重い PHP を動かさないため、WordPress に渡さないのが一般的です。
  • PHP-FPM が落ちた・応答しないときの 502 / 504:Nginx が担当。WordPress は動いていないので、静的なエラーページが必要です。
# 静的ファイルは WordPress に渡さず、無ければ Nginx の 404 を返す
location ~* \.(?:css|js|jpe?g|png|gif|webp|svg|woff2?)$ {
    try_files $uri =404;
    expires 30d;
}

fastcgi_intercept_errors の落とし穴

PHP-FPM が返したエラーを Nginx のエラーページに差し替えたい場合は、fastcgi_intercept_errors on; を使います。この設定を有効にすると、PHP 側が返したステータスコードのうち、error_page が定義されているものが Nginx のページに置き換わります。

ここでつまずきやすいのが、server ブロックに error_page 404 を書いたまま、PHP の location で fastcgi_intercept_errors on; を有効にするケースです。WordPress が返したテーマの 404 ページまで Nginx の簡素なページに置き換わり、検索フォームや関連記事への導線が消えてしまいます。

PHP の致命的なエラー(500)だけを差し替えたい場合は、PHP の location の中で 5xx だけを指定します。上で書いたとおり、location に error_page を書くと上の階層の設定は引き継がれないため、PHP の location では 404 は WordPress のものがそのまま返ります。

location ~ \.php$ {
    include fastcgi_params;
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    fastcgi_pass unix:/run/php/php-fpm.sock;   # 環境に合わせて変更

    fastcgi_intercept_errors on;
    error_page 500 502 503 504 /errors/50x.html;
}

PHP-FPM のソケットのパスはディストリビューションや PHP の版によって異なります。既存の設定に書かれている値を使ってください。なお、PHP-FPM が停止していて接続できない場合の 502 や、応答がなく時間切れになった場合の 504 は Nginx 自身が出すエラーなので、fastcgi_intercept_errors を有効にしなくても error_page の設定が使われます。

リバースプロキシで別のサーバーに渡している構成では、対応する設定は proxy_intercept_errors です。考え方は同じで、バックエンドの 404 を消したくないときは差し替えるコードを絞ります。

メンテナンス中の 503 ページ

サーバー作業の間だけメンテナンス画面を出したい場合は、503 と Retry-After ヘッダーを組み合わせます。503 は「一時的に利用できない」という意味で、検索エンジンにも一時的な停止であることが伝わります。

server {
    # ...(既存の設定)

    set $maintenance 0;
    if (-f $document_root/maintenance.flag) {
        set $maintenance 1;
    }
    if ($uri ~ ^/errors/) {
        set $maintenance 0;
    }
    if ($maintenance = 1) {
        return 503;
    }

    error_page 503 /errors/maintenance.html;

    location ^~ /errors/ {
        root /var/www/example.com;
        internal;
    }

    location = /errors/maintenance.html {
        root /var/www/example.com;
        internal;
        add_header Retry-After 3600 always;
    }
}

ドキュメントルートに maintenance.flag というファイルを置くとメンテナンス画面に切り替わり、削除すると通常に戻ります。判定を server ブロックに書いているのは、location / の中だけに書くと /wp-login.php のように PHP の location へ直接届くリクエストが素通りしてしまうためです。最初の例で error_page 500 502 503 504 と書いている場合は、503 を外して重複させないようにします。

/errors/ で始まる URI を判定から外しているのは、エラーページへの内部転送でもこの判定がもう一度実行されるからです。除外しないと、エラーページを表示しようとして再び 503 になり、自作のページではなく Nginx の既定のページが表示されます。

add_header は標準では成功やリダイレクトの応答にしか付かないため、503 の応答にヘッダーを付けるには always が必要です。メンテナンス用ページの location にだけ書くことで、通常の 404 ページなどには Retry-After が付きません。

自分の作業用 IP からは通常どおり見たい場合は、geo や map で接続元を判定して条件を加えます。また、長時間 503 を返し続けると、検索エンジンがページを削除対象と判断することがあるため、メンテナンスは短時間で終えるのが望ましいとされています。

WordPress のコア更新時に自動で出るメンテナンス表示(.maintenance ファイルによるもの)は WordPress 側の仕組みで、ここで説明した Nginx の設定とは別物です。

反映前後の確認方法

設定ファイルを編集する前に、バックアップを取っておきます。

sudo cp -a /etc/nginx/sites-available/example.com /etc/nginx/sites-available/example.com.bak
sudo nginx -t
sudo systemctl reload nginx

設定ファイルの場所は環境によって /etc/nginx/conf.d/ などの場合もあります。nginx -t で「syntax is ok」「test is successful」と出たことを確かめてから reload してください。構文エラーのまま restart すると、Nginx が起動せずサイト全体が止まります。

反映後は、ブラウザでの見た目だけでなく、ステータスコードを curl で確認します。

# 静的ファイルの 404(Nginx のページが出て、コードは 404 のまま)
curl -sI https://example.com/no-such-file.jpg | head -n 1

# 記事の 404(WordPress の 404 テンプレート、コードは 404)
curl -sI https://example.com/no-such-post/ | head -n 1

# エラーページを直接開けないこと(internal が効いていれば 404)
curl -sI https://example.com/errors/50x.html | head -n 1

5xx のページは、本番で PHP-FPM を止めて試すのではなく、ステージング環境で確認します。ステージングで PHP-FPM を一時停止すれば 502 が出るので、デザインとステータスコードの両方を確認できます。

うまく表示されないときの確認ポイント

  • エラーページではなく Nginx の既定のページが出る:error_page を書いた階層より下の location に別の error_page があり、継承が切れていないかを確認します。
  • エラーページ自体が 404 になる:root と URI の組み合わせを確認します。/errors/404.html を指定したなら、root 配下に errors/404.html が存在する必要があります。ファイルの読み取り権限も確認します。
  • テーマの 404 が出なくなった:PHP の location で fastcgi_intercept_errors on; と error_page 404 が同時に効いていないかを確認します。
  • 自作したものと違う画面が出る:ブラウザや拡張機能が独自のエラー画面を出していることがあります。curl で取得した本文が自分の HTML かどうかで切り分けます。
  • CDN を使っている:CDN 側にも独自のエラーページ機能があり、オリジンの 5xx を CDN のページに置き換える場合があります。どちらで表示されているかを確認します。

まとめ

  • error_page でコードとページを結び付け、エラーページの location には internal を付ける。
  • エラーページは PHP に頼らない静的 HTML にし、ステータスコードは書き換えずに 404 や 503 のまま返す。
  • WordPress では記事の 404 はテーマが担当し、Nginx は静的ファイルの 404 と PHP-FPM 停止時の 502 / 504 を担当させると整理しやすい。
  • fastcgi_intercept_errors on; を使うときは差し替えるコードを 5xx に絞り、テーマの 404 を消さない。
  • 反映前に nginx -t、反映後は curl -I でステータスコードまで確認し、5xx の見た目はステージングで試す。

お気軽にご相談ください

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