BLOG

【実務メモ】CPIサーバーでメンテナンス画面を安全に出す方法(IP許可+503対応)

サイトのリニューアルや重作業の前に、メンテナンス画面を一時的に出してアクセスを制御したいことがあります。
今回は、CPIサーバーで実際に行ったIP許可制+HTTP 503の実装方法をまとめます。
結論としては、共通パーツ(例:head.php)にガードを入れる方法が安定・確実でした。


なぜ .htaccess リダイレクトがうまくいかなかった?

環境によっては、.htaccess の RewriteRule で全体転送しようとしても、
サーバー側の既定設定やアプリのフロントコントローラ(WordPress等)との優先順位で意図通りに効かないことがあります。
また、静的ファイルやサブディレクトリ配下の挙動を完全に揃えるのが難しく、想定外の抜け道が残ることも。
そこで今回は、「PHPで早期に判定して配信を止める」アプローチを採用しました。


実装:共通パーツでIP許可+503を返す

サイト全ページで必ず読み込まれる共通パーツ(例:head.phpheader.php など)の先頭に、
以下のガードを置いて「許可IP以外はメンテナンス画面」を返します。


// maintenance-guard.php (共通パーツの冒頭で require するのも可)

// メンテナンス ON/OFF フラグ(存在したらON)
$flagFile = __DIR__ . '/../maintenance.flag';
$maintenanceMode = file_exists($flagFile);

// 許可IP(自分の回線・オフィス・VPNなど)
$allowed_ips = [
  'ipアドレス1',
  'ipアドレス2',
  'ipアドレス3',
];

// プロキシ越し対策(必要に応じて)
// $clientIp = $_SERVER['HTTP_X_FORWARDED_FOR'] ?? $_SERVER['REMOTE_ADDR'];
$clientIp = $_SERVER['REMOTE_ADDR'] ?? '';

if ($maintenanceMode && !in_array($clientIp, $allowed_ips, true)) {
    // 正しいメンテナンス応答(検索エンジンにも優しい)
    header('HTTP/1.1 503 Service Temporarily Unavailable');
    header('Retry-After: 3600'); // 1時間後の再訪を案内(秒)
    header('Content-Type: text/html; charset=UTF-8');

    // メンテ画面を静的HTMLで返す
    readfile(__DIR__ . '/../maintenance.html');
    exit;
}

ポイントはHTTP 503を返すこと。
単なる302/200ではなく503にすることで、検索エンジンに「一時的に利用不可」である旨が正しく伝わり、評価の悪化やインデックス問題を避けやすくなります。
また、Retry-Afterヘッダで再訪タイミングを示すのもベターです。


運用を楽にする小技(フラグファイル方式)

「コードを書き換えてON/OFF」は事故の元。
上記のように maintenance.flag の有無で切り替えると、FTPやSSHでファイルを置く/消すだけで切替できます。


# メンテ開始(ON)
touch /path/to/your/app/maintenance.flag

# メンテ終了(OFF)
rm /path/to/your/app/maintenance.flag

※ WordPressなら mu-plugins にガードを入れてもOKですが、
テーマ切替やプラグイン順序で漏れが出ないよう、必ず全ページで最初に実行される箇所に置くのが安心です。


maintenance.html の最低限テンプレート

<!doctype html>
<html lang="ja">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <meta name="robots" content="noindex, nofollow">
  <title>メンテナンス中</title>
  <style>
    html,body{height:100%;margin:0}
    body{display:flex;align-items:center;justify-content:center;font:16px/1.6 -apple-system, BlinkMacSystemFont, "Segoe UI", "Hiragino Kaku Gothic ProN", Meiryo, sans-serif;background:#fafafa;color:#333}
    .box{max-width:640px;padding:24px;border:1px solid #eee;background:#fff;border-radius:12px;text-align:center}
    h1{font-size:20px;margin:0 0 8px}
    p{margin:8px 0}
  </style>
</head>
<body>
  <div class="box">
    <h1>メンテナンス中です</h1>
    <p>只今サイトの更新作業を行っています。しばらくしてから再度アクセスしてください。</p>
  </div>
</body>
</html>

noindex を入れておくと、メンテ中ページがインデックスされるリスクをさらに下げられます。
画像・CSS・JSなどを読み込みたければ相対パスに注意(例:/assets/... ではなく ./assets/...)して、静的ファイルだけで完結させます。


IPまわりの注意(社内/自宅回線/VPN)

許可IPは固定IPか、当日使う回線のグローバルIPを登録します。モバイル回線はIPが変わりやすいので要注意。
プロキシやCDN経由の場合は HTTP_X_FORWARDED_FOR を見る実装も検討します(セキュリティと相談)。


よくあるハマり所

  • キャッシュが効いて切り替わらない: ブラウザキャッシュ/CDN/WPキャッシュをクリア。503はCDNが独自扱いすることも。
  • 一部URLだけ素通り: 共通パーツが通らない直リンク(静的ファイル直参照等)。.htaccessで静的配信も塞ぐか、公開ディレクトリの構成を見直す。
  • 管理画面だけ開きたい: /wp-admin/ は別扱いにするなど、パス条件で許可例外を足す。

まとめ

CPIサーバーでのメンテ画面は、.htaccessリダイレクトが環境次第で不安定なとき、
共通パーツにIP許可+503の早期判定を入れると堅実です。
さらに フラグファイル で運用をシンプルにし、Retry-Afterやnoindex も忘れずに。
これだけで「安全に止める/安全に戻す」がグッと楽になります。


ご相談ください

札幌拠点リモートでも全国案件対応OK。
WordPressフルカスタマイズや運用設計、メンテナンス運用の仕組み化のご相談は
山キノコロリ WEB事業部 まで!