カスタム404ページの設定と正しい実装方法

本物の404を返し、ソフト404のシグナルを避け、訪問者に役立つ導線を用意する方法。フレームワークとサーバー設定の両方で解説します。

ユーザーがリンク切れのURLにアクセスしたら、サーバーは404 Not Foundのステータスを返す必要があります。ところが実際のプロジェクトでは、このルールが驚くほど頻繁に破られています。CMSが200 OKを返す、リダイレクトでトップページに飛ばす、「404ページ」のコードは正しくても画面が真っ白になる、といった具合です。どれもSEOとユーザーの両方にとって別々の問題です。

正しく設定した404ページは、3つの問題を同時に解決します。URLが存在しないことをGoogleに伝えます。ユーザーをサイト内にとどめ、目的のセクションへ案内します。無駄なクロールからクロールバジェットを守ります。以下、順に見ていきます。

Googleは、404ページがあるというだけでサイトにペナルティを与えることはありません。問題になるのは404コードそのものではなく、誤った実装です。404のはずが200 OKを返す、内部リンクが404のURLを指している、数千ページを301リダイレクトなしで削除した、といったケースが該当します。

404ページとは

404 Not Foundは、リクエストされたリソースが存在しないときにサーバーが返すHTTPレスポンスコードです。サーバーは正常に動作していてルーティングも解決できたものの、該当するドキュメントがない、という意味になります。この点で、500(サーバーエラー)や503(サービス利用不可)とは異なります。

約74%

カスタム404がないサイト

ほとんどのサイトは、ナビゲーションつきの独自ページではなく、プラットフォーム標準の404を表示している

数週間

インデックス削除までの期間

正しく404を返しているURLは、通常、数週間でGoogleのインデックスから削除される。Search Consoleで早められる

ソフト404

最も多い間違い

CMSが404ではなく200 OKを返すと、Googleが空のページをインデックスに登録し、サイトのテーマの一貫性が薄れる

410

削除が早い

Googleは410(Gone)を404よりかなり早くインデックスから削除する。大量のページを削除するときに使う

404ページは2つのレベルで存在します。HTTPレベルは、検索クローラーが見るヘッダーのレスポンスコードです。表示レベルは、ユーザーが見るHTMLコンテンツです。どちらも同じく重要です。HTTPコードの誤りはSEOの問題で、表示の不備はUXの問題です。

最重要ルール:必ずHTTP 404を返す

最初で最も重要なルールは、エラーページがHTTPステータス404(または410)を返すことです。200は返してはいけません。これを「ハード404」と呼び、「ソフト404」と区別します。

致命的な間違い:HTTPステータス200 OKのまま、「ページが見つかりません」というメッセージのHTMLを返すこと。Googleは「成功した」レスポンスと判断し、そのページをインデックス登録の対象にします。その結果、同じ内容の無意味なURLが何百件もインデックスに登録されます。

どのページのHTTPステータスも、ブラウザーで直接確認できます。F12 → Network → ページを再読み込み → 最初のリクエストを選択 → Status列を見ます。ターミナルならcurlでも確認できます。

bash
# Check HTTP status of a page
curl -s -o /dev/null -w "%{http_code}" https://example.com/non-existent-url
# Expected output: 404

# Check full response headers
curl -I https://example.com/non-existent-url
ブラウザーでの簡単な確認:DevTools(F12)を開き、Networkタブで404ページにアクセスして、最初のリクエストのStatus列を見ます。200ではなく404と表示されるのが正しい状態です。

ソフト404と410の違い

「ハード404」のほかに、実務で混同されやすいものが2つあります。ソフト404と、410ステータスです。削除したページを正しく扱うには、この違いの理解が欠かせません。

ステータスHTTPコードGoogleにとっての意味使う場面
ハード404404リソースが見つからない。数週間でGoogleのインデックスから削除されるページを削除した、またはもともと存在しない
ソフト404200(誤り)Googleが「成功した」レスポンスと見なし、空のコンテンツをインデックスに登録する使わない。意図した選択ではなく、実装のバグ
Gone410リソースを恒久的に削除した。Googleは404よりかなり早くインデックスから削除する大量のページ削除(旧商品、不要になったセクション)
ソフト404は、開発者が意図して選ぶものではなく、バグです。WordPressなどのCMSで特に起こりやすく、404テンプレートがメインレイアウトに組み込まれていて、常に200が返されるのが原因です。今すぐ、curlかDevToolsで自サイトの404ページを確認してください。

Googleは、404のURLからトップページや無関係な別ページへのリダイレクトも、ソフト404と見なします。検索エンジンから見ると、ユーザーはAを探してBにたどり着いたのに、Bの内容は検索クエリへの答えになっていません。これでリダイレクト先ページの品質シグナルが下がります。

404ページに入れる要素

404ページに着いたユーザーは、すでに軽くいらだっています。ページの役割は、そのいらだちを和らげ、次に何をすればよいかを明確に示すことです。効果的な404ページは、決まった構成になっています。

カスタム404ページがユーザーをサイト内にとどめる仕組み。

わかりやすいエラーメッセージ

状況を平易な言葉で説明します。「ページが見つかりません」「このページは存在しないようです」といった表現です。画面上の文言には、専門用語やエラーコードを使いません。

検索ボックス

404ページで最も効果的な要素です。ユーザーは探しているものをすでに知っています。Googleに戻らなくても、その場で探せるようにします。

主要セクションへのナビゲーション

トップページや人気のセクション、サイトマップへのリンクです。ユーザーが現在地をつかみ、サイト内の移動を続けられます。

戻るボタン

元のページに戻りたいユーザーは多くいます。戻るリンクやボタンがあると、直帰率が下がり、UXも向上します。

ECで最も効果的なのは、404ページに人気商品やカテゴリーを表示することです。特定の商品へのリンク切れから来たユーザーは、そのカテゴリーに関心がある可能性が高いからです。

404ページでやってはいけないこと:JavaScript(window.location.href = '/')でユーザーを自動的にトップページへ移動させることです。Googleはこれをソフト404と見なすことがあります。ユーザーが期待したのはAなのに、Bに飛ばされ、内容は無関係だからです。404のURLからサーバー側で301リダイレクトするのは、本当に代わりになるページがある場合に限ります。

実装:Next.js、Nginx、Apache

カスタム404ページの設定方法は、技術スタックによって異なります。ここでは、特によく使われる3つの構成を取り上げます。Next.js App Router、Nginx、Apacheです。

Next.js App Router

Next.js 13以降のApp Routerでは、app/ディレクトリ内のnot-found.tsxファイルでカスタム404ページを作成します。i18n(next-intlなど)を使う場合、ファイルはapp/[locale]/に置きます。

tsx
// app/[locale]/not-found.tsx
import Link from 'next/link';

export default function NotFound() {
  return (
    <main style={{ textAlign: 'center', padding: '4rem 1rem' }}>
      <h1>404 — Page Not Found</h1>
      <p>The link may be outdated or the address was mistyped.</p>
      <Link href="/">Back to homepage</Link>
    </main>
  );
}

// Next.js automatically returns HTTP 404 for this file.

404をプログラムから生成する場合(動的ルートapp/[locale]/blog/[slug]/page.tsxなど)は、next/navigationのnotFound()関数を使います。この関数を呼ぶとレンダリングを即座に中断し、HTTP 404を返してnot-found.tsxを表示します。

tsx
// app/[locale]/blog/[slug]/page.tsx
import { notFound } from 'next/navigation';
import { getArticleDoc } from '@/messages/blog-articles/registry';

export default async function ArticlePage({ params }: { params: { slug: string } }) {
  const article = getArticleDoc(params.slug);

  // If slug does not exist — return HTTP 404 and render not-found.tsx
  if (!article) {
    notFound();
  }

  return <ArticleRenderer article={article} />;
}
Pages Router(Next.js 13未満)では、カスタム404ページの作り方が異なります。pages/404.tsxを作成すると、Next.jsが自動的にそのページへルーティングし、HTTP 404を返します。Pages RouterではnotFound()関数は使えません。代わりに、getStaticPropsかgetServerSidePropsで{ notFound: true }を返します。
tsx
// Pages Router: pages/blog/[slug].tsx (legacy approach)
export async function getServerSideProps({ params }) {
  const article = getArticleDoc(params.slug);

  if (!article) {
    // Next.js will return HTTP 404 and show pages/404.tsx
    return { notFound: true };
  }

  return { props: { article } };
}

Nginx

Nginxでは、serverブロック内のerror_pageディレクティブでカスタム404ページを設定します。404.htmlが指定したパスに存在するか、そのファイルを返す際に200への内部リダイレクトが起きていないかを確認します。

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

    # Custom page for 404 errors
    error_page 404 /404.html;

    # The location for the file itself — returns 404, not 200
    location = /404.html {
        internal;
    }

    # Custom pages for other errors
    error_page 500 502 503 504 /50x.html;
    location = /50x.html {
        internal;
    }
}
internalディレクティブは、/404.htmlへの外部からの直接アクセスを防ぎます。ページはエラーレスポンスとしてのみ表示されます。これがないと、/404.htmlを直接開いて200が返され、コンテンツの重複が生じます。

Apache / .htaccess

Apacheでは、ErrorDocumentでカスタム404を設定します。メイン設定ファイルでも.htaccessでも設定できます。

apache
# .htaccess in the site root

# Custom 404 page
ErrorDocument 404 /404.html

# You can also point to a PHP file
# ErrorDocument 404 /404.php

# Custom pages for other errors
ErrorDocument 403 /403.html
ErrorDocument 500 /500.html

# Enable mod_rewrite for SPA routing
<IfModule mod_rewrite.c>
    RewriteEngine On
    # For React/Vue SPA: all non-existent routes → index.html
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteRule ^ /index.html [L]
</IfModule>
ApacheやNginxでSPAのルーティングを設定するときは注意が必要です。存在しないルートをすべて200コードのindex.htmlで返すと、検索エンジンが存在しないページをインデックスに登録します。対策は2つあります。SPA側で、404ページに<meta name="robots" content="[noindex](/glossary/noindex)">をクライアント側で追加するか、SSR/SSGで適切なHTTPステータスコードを返します。

PHP(WordPressなどのCMS)

WordPressのカスタム404ページは、テーマ内の404.phpファイルです。パーマリンクが正しく設定されていれば、WordPressは存在しないURLに対して自動的にHTTP 404を返します。CMSが404ではなく200を返す場合、原因は通常.htaccessかサーバー設定にあります。

php
<?php
// themes/your-theme/404.php
// WordPress automatically returns HTTP 404
get_header();
?>
<main class="error-404">
    <h1>Page Not Found</h1>
    <p>Try using search:</p>
    <?php get_search_form(); ?>
    <p>Or return to the <a href="<?php echo home_url(); ?>">homepage</a>.</p>
</main>
<?php
get_footer();

404ページを正しく設定するのは、作業の半分にすぎません。残りの半分は、存在しないページを指すリンクをすべて見つけて解消することです。インデックスに404が現れる主な原因は、リンク切れです。

ステップ1Google Search Consoleで見つける

Search Console →「インデックス作成」→「ページ」→「見つかりませんでした(404)」を開きます。無料で最も網羅的な情報源です。表示されるのは、Googleがクロール中に見つけた404だけで、SEOに直結するものばかりです。

ステップ2Screaming Frogでサイトをクロールする

Screaming Frog SEO Spiderでサイトをクロールします。フィルターはResponse Codes → 4xxです。404のURLだけでなく、リンク元のページもわかります。どのページにリンク切れがあるかを正確に把握できます。

ステップ3サーバーログを確認する

ログには、Googleがまだ見つけていないものも含め、すべてのリクエストが記録されています。grep ' 404 ' access.log | awk '{print $7}' | sort | uniq -c | sort -rn | head -20で、404を返しているURLの上位20件がわかります。

ステップ4修正するかリダイレクトを設定する

見つけた404ごとに、次の3つから選びます。似たページがあれば、該当する代替URLへの301を設定します。そのURLを指す内部リンクをすべて削除します。リンクが1本もなければ、404のままにします(Googleが自動的にインデックスから削除します)。

404ページの実装例:
bash
# Find top-20 broken URLs in Nginx/Apache logs
grep ' 404 ' /var/log/nginx/access.log \
  | awk '{print $7}' \
  | sort \
  | uniq -c \
  | sort -rn \
  | head -20

# Example output:
# 143 /old-product-page
#  87 /blog/removed-article
#  34 /wp-login.php  (attack attempts — not critical)
すべての404のURLをトップページへ301リダイレクトしてはいけません。これは「トップページへのリダイレクトチェーン」と呼ばれ、Googleはソフト404と見なします。リダイレクトが適切なのは、削除したページとテーマが近いページがある場合だけです。代わりになるページがなければ、正しい404を返すのが正解です。

404エラーの監視

一度きりの監査は有効ですが、新しい404は絶えず発生します。ページ名の変更、商品の削除、外部サイトからの存在しないURLへのリンクなどが原因です。定期的な監視を設定しておくことが重要です。

ツール監視対象頻度無料
Google Search ConsoleGooglebotがクロール中に見つけた404毎日更新可
Screaming Frog+スケジューラーサイト全体のクロールで見つかったすべての404週次/月次500 URLまで
サーバーログ(goaccess、awstats)access.logにあるすべての404をリアルタイムで確認リアルタイム可
Ahrefs / Semrushサイト監査404と、404を指す外部からの被リンク週次の自動チェック有料
UptimeRobot / Better Uptime主要URLの稼働監視1〜5分ごと基本プランは無料

大規模サイト(1万ページ以上)では、サーバーログが特に役立ちます。ボットやユーザー、スクリプトを含む、リクエストの100%を網羅しているからです。Search Consoleに表示されるのは、Googlebotがクロールで見つけたものだけで、全体の一部にすぎません。

Google Search Consoleでアラートを設定します。「設定」→「メール通知」の順に開きます。デプロイでルーティングが壊れた場合など、404の件数が急増すると、GSCから通知が届きます。

正しい404ページのチェックリスト

HTTPステータス

  • 404ページがHTTPステータス404を返している(curlまたはDevToolsで確認済み)
  • ソフト404がない:エラーメッセージのページが200 OKを返していない
  • 存在しないURLからトップページへのJavaScriptリダイレクトがない
  • 代わりのページがない大量削除ページには410 Goneを使っている
  • 301リダイレクトは、関連性のある代替ページがあるURLにだけ設定している

ページの内容

  • 専門用語を使わない、わかりやすいエラーメッセージがある
  • 検索ボックス、またはサイト内検索へのリンクがある
  • トップページへのリンクがある
  • 人気のセクションやカテゴリーへのリンクが2〜4件ある
  • サイトのブランドに合ったデザインにしている(ヘッダー、フッター、フォント)

実装

  • Next.js:not-found.tsxを作成し、存在しないスラッグでnotFound()を呼んでいる
  • Nginx:error_page 404ディレクティブを設定し、404.htmlをinternalにしている
  • Apache:.htaccessまたはメイン設定にErrorDocument 404を設定している
  • WordPress:有効なテーマに404.phpがある
  • SPA(SSRなしのReact/Vue):404ページでクライアント側からnoindexのmetaタグを追加している

監視

  • Google Search Consoleを接続し、メールアラートを設定している
  • Screaming Frogなどで定期的にクロールしている(少なくとも月1回)
  • サーバーログにアクセスでき、アクセスの多いサイトでは分析している
  • 404のURLを指す内部リンクをすべて見つけて修正した
今すぐ自サイトの404ページを確認してください。存在しないURL(yourdomain.com/test-404-checkなど)を開き、DevToolsのNetworkで最初のリクエストのステータスを見ます。200なら、ソフト404になっているため、サーバー設定を修正する必要があります。

よくある質問

監査や開発の場面でよく出る、404ページの設定に関する質問に答えます。

404ページにnoindexタグは必要ですか?
必要ありません。HTTP 404を返すページは、noindexの有無にかかわらず、Googleにインデックス登録されません。単に追加されないだけです。200 OKにnoindexを付けて返すと、Googleが再評価するまでの間、一時的にインデックス登録可能なページとして処理することがあります。メタタグより、正しいHTTPコードのほうが重要です。
Googleで上位表示されていたページが404を返すようになったら、どうすればよいですか?
Googleが自動的にインデックスから削除します。通常、Googlebotがそのページを再訪問してから1〜4週間かかります。早めたい場合は、Search Consoleの削除ツールを使います。テーマが近い代替ページがある場合は、301リダイレクトを設定します。リンク評価が引き継がれ、検索順位の回復も早くなります。
404ページをデザイン性の高いブランドページにしてもよいですか?
むしろそうすべきです。ナビゲーションのあるブランド仕様の404ページは、ユーザーをサイト内にとどめ、直帰率を下げます。ヘッダーでHTTP 404を返しても、ページの見た目は自由に作れます。大切なのは、正しいHTTPコードを返し、次の行動をユーザーに明確に示すことです。
存在しないURLすべてで、404ページは同じでよいですか?
ほとんどのサイトでは、共通の404ページ1つで問題ありません。ECでは、カスタマイズを加える方法もあります。URLパターンからユーザーが来たカテゴリーを判別し、関連商品を表示します。ただし、手間をかける価値があるのは、404ページへのアクセスが多い場合に限ります。
クロールバジェットとは何ですか?404はどう消費しますか?
クロールバジェットとは、Googlebotが一定期間にサイトでクロールするページ数の目安です。内部リンクが404のURLを指していると、ボットは公開中のページではなく、存在しないアドレスを繰り返し訪問します。数百万URLのサイトでは致命的です。404を指す内部リンクはすべて削除してください。

Check it with SpiderHead

Free and local: run the audit on your own machine.

Try it