これまで「なんとなく」で構築していたメンテナンスページを、改めて仕様を意識して作ってみました。
ポイントは以下の通りです。
意識したポイント
- ステータスコードを503(Service Unavailable)にする
- 作業期間はユーザーにはJSTでわかりやすく表示し、内部ではGMTに変換してHTTPヘッダーへ設定する
- .htaccessを適切に設定する
ユーザーはもちろん、検索エンジンやクローラーにも配慮したメンテナンスページになるようにしました。
準備するもの
maintenance.php
メンテナンス画面を表示するページ。
.htaccess
サイトをメンテナンス状態へ切り替えるための設定。
maintenance.php

<?php
// HTTPヘッダーの設定
http_response_code(503);
header('Content-Type: text/html; charset=UTF-8');
header('Cache-Control: no-store, no-cache, must-revalidate, max-age=0');
header('Pragma: no-cache');
header('X-Robots-Tag: noindex');
// タイムゾーンを日本標準時(JST)に設定
date_default_timezone_set('Asia/Tokyo');
// メンテナンス開始日時 ※JSTで設定
$maintenance_start = new DateTime('2026-03-01 10:00:00');
// メンテナンス終了日時 ※JSTで設定
$maintenance_end = new DateTime('2026-03-10 06:00:00');
// 終了日時を JST から GMT に変換してRetry-Afterヘッダーに設定
$maintenance_end_gmt = clone $maintenance_end;
$maintenance_end_gmt->setTimezone(new DateTimeZone('GMT'));
header("Retry-After: " . $maintenance_end_gmt->format('D, d M Y H:i:s') . ' GMT');
// 表示用テキストの生成
$week = ['日', '月', '火', '水', '木', '金', '土'];
$start_day_of_week = $week[(int)$maintenance_start->format('w')];
$end_day_of_week = $week[(int)$maintenance_end->format('w')];
$start_str = $maintenance_start->format('n/j(' . $start_day_of_week . ')G時');
$end_str = $maintenance_end->format('n/j(' . $end_day_of_week . ')G時');
?>
<!DOCTYPE html>
<html dir="ltr" lang="ja">
<head>
<meta charset="UTF-8">
<title>現在メンテナンス中です</title>
<meta name="robots" content="noindex">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="format-detection" content="telephone=no">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="現在メンテナンス中です">
<style>
body {
padding: 0;
margin: 0;
}
.maintenance {
box-sizing: border-box;
display: grid;
place-content: center;
height: 100vh;
height: 100svh;
font-size: 1.1em;
font-weight: 700;
text-align: center;
line-height: 1.4;
padding: 1em;
}
.maintenance__title {
font-size: 2em;
}
</style>
</head>
<body>
<main>
<div class="maintenance">
<div>
<h1 class="maintenance__title">現在メンテナンス中です</h1>
<div class="maintenance__text">
<p>メンテナンス期間:<?php echo htmlspecialchars($start_str, ENT_QUOTES, 'UTF-8'); ?> ~ <?php echo htmlspecialchars($end_str, ENT_QUOTES, 'UTF-8'); ?>まで(予定)</p>
</div>
</div>
</div>
</main>
</body>
</html>要所の解説
ステータスコードの設定
http_response_code(503);ステータスコードを503(Service Unavailable )に設定。
補足:なぜ503ステータスを使うのか
メンテナンスページを実装する際、見落としがちな点が HTTPステータスコード。
メンテナンスページに通常の200(正常レスポンス)を返してしまうと、検索エンジンは「正常なコンテンツ」として認識してしまうため、メンテナンスページ自体が検索結果に上書きされ、インデックスされてしまう可能性があります。
そのため、503(Service Unavailable) ステータスを設定し、「一時的にサービスが利用できない」状態だと、検索エンジンに判断させます。
また、後述しますが、さらにRetry-Afterヘッダーを設定することで、メンテナンスの終了日をクローラーに伝達し、「次にいつ再クロールすればよいか」を判断させることができます。
キャッシュの禁止
header('Cache-Control: no-store, no-cache, must-revalidate, max-age=0');
header('Pragma: no-cache');ブラウザやCDNにキャッシュされるのを防ぎます。
メンテナンス終了後もメンテナンス画面が表示されてしまう事故を防ぐための設定です。
検索エンジンのインデックス防止
header('X-Robots-Tag: noindex');メンテナンスページが検索結果にインデックスされるのを防ぎます。
metaタグの方でもnoindexは指定するけど、HTTPヘッダーでも指定しておくとより確実だと考えました。
メンテナンス期間の設定
date_default_timezone_set('Asia/Tokyo');タイムゾーンを日本標準時(JST)に設定。
$maintenance_start = new DateTime('2026-03-01 10:00:00');
$maintenance_end = new DateTime('2026-03-10 06:00:00');メンテナンスの期間を設定。
Retry-Afterヘッダーの設定
$maintenance_end_gmt = clone $maintenance_end;
$maintenance_end_gmt->setTimezone(new DateTimeZone('GMT'));
header("Retry-After: " . $maintenance_end_gmt->format('D, d M Y H:i:s') . ' GMT');先程設定したメンテナンス期間をGMT形式に変換し、headerのRetry-Afterの時刻に設定。
クローラーに、「いつ再アクセスすればよいか」を明示します。
表示用の日付生成
$week = ['日', '月', '火', '水', '木', '金', '土'];
$start_day_of_week = $week[(int)$maintenance_start->format('w')];
$end_day_of_week = $week[(int)$maintenance_end->format('w')];曜日表記を日本語に。
$start_str = $maintenance_start->format('n/j(' . $start_day_of_week . ')G時');
$end_str = $maintenance_end->format('n/j(' . $end_day_of_week . ')G時');最後に文字列を合体。
HTML / CSS / PHP
<meta name="robots" content="noindex">html側にも一応noindexを付与。
.maintenance {
box-sizing: border-box;
display: grid;
place-content: center;
height: 100vh;/* フォールバック */
height: 100svh;
font-size: 1.1em;
font-weight: 700;
text-align: center;
line-height: 1.4;
padding: 1em;
}CSSはお好みでどうぞ。
<div class="maintenance">
<div>
<h1 class="maintenance__title">現在メンテナンス中です</h1>
<div class="maintenance__text">
<p>メンテナンス期間:
<?php echo htmlspecialchars($start_str, ENT_QUOTES, 'UTF-8'); ?> ~
<?php echo htmlspecialchars($end_str, ENT_QUOTES, 'UTF-8'); ?>まで(予定)
</p>
</div>
</div>
</div>メンテナンス期間は、変数で対応。
既にheader側で設定済みなので、いちいちHTML側の表記を書き換える必要なし。
.htaccess
続いて、ウェブサイトをメンテナンス状態にするために、.htaccessを設定
RewriteEngine On
# 503ページを指定
ErrorDocument 503 /maintenance.php
# 除外IP
RewriteCond %{REMOTE_ADDR} !^000\.000\.000\.000$
# maintenance.php自身の除外
RewriteCond %{REQUEST_URI} !^/maintenance\.php$
# その他、除外が必要なディレクトリ・ファイルがあれば追記
RewriteCond %{REQUEST_URI} !^/\.well-known/
RewriteCond %{REQUEST_URI} !^/favicon\.ico$
# ステータスを503に
RewriteRule ^ - [R=503,L]注意。maintenance.phpにリダイレクトさせるのではない
ここが引っかかったポイント。
当初はmaintenance.phpにリダイレクトさせればOKと思っていましたが、ステータスコードが503なので、使用しているサーバーのエラーページに飛んでしまいます。
なので、考え方としてはリダイレクトではなく、503エラーが発生した際に、maintenance.phpをエラーページとして表示させるというのが全体の流れ。
503ページの指定
ErrorDocument 503 /maintenance.php503ページにmaintenance.phpを指定。
自分のIPを除外
RewriteCond %{REMOTE_ADDR} !^000\.000\.000\.000$メンテナンス中でも自分(管理者)はサイトへアクセスできるよう、自分のIPアドレスを除外。
maintenance.phpの除外
RewriteCond %{REQUEST_URI} !^/maintenance\.php$重要。
maintenance.php自身も除外しないと、無限ループに陥るので必須。
その他、除外が必要なディレクトリ・ファイルがあれば追記
RewriteCond %{REQUEST_URI} !^/\.well-known/
RewriteCond %{REQUEST_URI} !^/favicon\.ico$ ステータスを503にする
RewriteRule ^ - [R=503,L]最後にウェブサイト全体を503状態に。
これで完了です。メンテナンスが終了した際は.htaccessの設定を全て解除すればサイトは復帰します。
まとめ
以上、「メンテナンスページの作り方|503ステータスとRetry-After対応(PHP + .htaccess)」でした。
これまでウェブサイトにメンテナンス画面が必要になった場合でも、実際の作業時間は数秒〜数分で終わることが多く、簡易的にリダイレクトページを用意するだけで対応していました。
しかし今回、ある程度長時間のメンテナンス表示が必要だったため、HTTPの仕様も踏まえて作ってみた次第です。
同じようなケースの参考になれば幸いです。







