Webサイトのメンテナンス中画面を出す正しい作法と.htaccessの書き方
今回は、Webサイトやサービスをメンテナンス中にする場合に、どのURLにアクセスしても「メインテナンス中です」の画面を出す正しいやり方を、人間にも検索エンジンにも適切にする作法を主眼に解説します。
この週末の土曜深夜~日曜早朝にかけて、データセンターの設備メインテナンスのため、Web担を含むインプレスグループのほとんどのWebサイトが、どのURLにアクセスしても「メンテ中です」という表示になっていました。
なのですが、その実装がちょっと気になったので、「正しいメンテナンス画面の出し方」を説明してみます。
※2010-01-16 Retry-Afterを指定するHeaderの指定を修正しました(コメント参照)
※2009-06-17 RewriteCondから [NC] 条件を削除しました(コメント参照)
※2009-06-16 Retry-Afterの記述をGMTに変更しました(コメント参照)
※2009-06-16 記事タイトルのミススペル.httaccessを.htaccessに修正しました
メンテ中画面を出す正しいApacheの設定
結論としては、正しいやり方は次の2ステップになります。
- メンテ中画面を出すWebサーバーに/maintenance.htmlというファイルを作り、人間に対して表示するメッセージをHTMLで書く。
- .htaccess(またはhttpd.conf)で、次のどちらかのように設定する。
ErrorDocument 503 /maintenance.html <IfModule mod_rewrite.c> RewriteEngine On RewriteCond %{REQUEST_URI} !=/maintenance.html RewriteRule ^.*$ - [R=503,L] </IfModule>
ErrorDocument 503 /maintenance.html <IfModule mod_rewrite.c> RewriteEngine On RewriteCond %{REQUEST_URI} !=/maintenance.html RewriteCond %{REMOTE_ADDR} !=192.168.0.4 RewriteCond %{REMOTE_ADDR} !=192.168.0.5 RewriteRule ^.*$ - [R=503,L] </IfModule> <IfModule mod_headers.c> Header set Retry-After "Sun, 14 Jun 2009 6:00:00 GMT" </IfModule>
- /maintenance.htmlの部分には、メンテ中であることを示すHTMLのパスを指定します。
- 192.168.0.4や192.168.0.5の部分には、管理者のIPアドレスを書きます。管理者IPアドレスがさらにある場合は行をコピーして増やせばOKですし、わからない場合は必要ない場合は行を削除してしまいましょう。
- Sun, 14 Jun 2009 06:00:00 GMTの部分には、メンテ終了予定時刻を指定します(メンテ終了までの秒数でも出せますが、終了時刻をRFC1123形式で示すほうが楽でしょう、GMTにする必要がありますが)。ただし、ここに指定する値は人間のユーザーには基本的に示されませんし、あくまでも参考データです。
これで、どのURLにアクセスしても、ブラウザに表示されるURLはそのままで、メンテ中を示すページが表示され、しかも、HTTPレスポンスコード503(過負荷/メンテで一時的に利用不可)が返るので、検索エンジンに対しても一時的なメンテだと理解され、メンテ画面がインデックスされることはありません。
また、管理者が使っている一部のIPアドレスからのアクセスに対してはメンテ中を表示せず通常の処理/表示をします。メンテということは必ず状態をチェックするはずですから、自分たちはいつもの状態で確認できる仕組みが必要になるわけですね。
どういった設定だとまずいのか
メンテ中画面を出す悪い例としては、次のようなものがあります。
全URLへのアクセスにRewriteでメンテ中画面を表示
ブラウザのURL自体はアクセスしようとしたURLのままで、メンテ中画面のHTMLが表示されます。ステータスコードは200。
実は、検索エンジンへの対応としては最悪のパターン。検索エンジンがメンテ中の内容をその時点のコンテンツとして取得してキャッシュしてしまいます。
全URLへのアクセスを302リダイレクトでメンテ中画面のURLに転送
ブラウザの表示自体が転送先のページに変わり、しかもそのページはステータスコード200。
ブラウザの表示URLが変わっているので、ブラウザのリロードでメンテが終わったか確認できませんし、検索エンジンのロボットにも通常のリダイレクトだと判断され、リダイレクト先のコンテンツをインデックスされる可能性があります。
そもそも、検索エンジンが302リダイレクトを適切に処理できることは期待しないほうがいいでしょう。過去にも302リダイレクトに関するトラブルは頻発していますから。
503でApacheの「Service Temporarily Unavailable」を表示
あなたのサイトのユーザーが、英語のメッセージ(しかもいつ復旧するのかの情報ナシ)を見て不安に思わないのでしたら問題ないでしょう。ErrorDocument 503に文字列を指定すればこのメッセージを変更できますが、それならHTMLファイルでわかりやすく作るほうがいいですよね。
最初の2つは、レスポンスコード200が返るため、人間に対しては問題ないのですが、検索エンジンのロボットは、それがメンテ中の特別な処理だと認識できず、メンテ中画面をインデックスしてしまう可能性があります。NOT FOUNDなのにステータスコード200を返す「ソフト404」問題と同様ですね(ただし、上記の設定でも、/maintenance.htmlに直接アクセスがあると200が返ります)。
メンテ中もアクセスがあることを前提に、人間にはメンテ中であることをメンテ終了予定時刻とともにHTMLで示し、検索エンジンにはステータスコード503で一時的な状態であることを示す、その両方をちゃんとやるようにしましょう。
ちなみに、この設定はApache 2.2系でしか試していません。また、私はサーバーエンジニアではないので、もっと簡単な良い方法があるのかもしれません。良い方法をご存じの方や、Apache 1.3系や2.0系でどうかなど、コメントで教えていただけると助かります。
この記事は、メールマガジン「Web担ウィークリー」やINTERNET Watchの「週刊 Web担当者フォーラム通信」に掲載されたコラムをWeb担サイト 上に再掲したものです。
コメント
.httaccess → .htaccess
タイトルが「.httaccess」になっていたので、「.htaccess」に変更しました。うううぅ。
YAKさんのご指摘に感謝です。
ケータイは……常識で考えると仕様で定められているものは理解してくれ……ます……かね……うーん。
有用な記事をありがとうございます!
誤植を見つけました。最後にダブルクウォートが洩れているようです。
> Header set Retry-After "Sun, 14 Jun 2009 6:00:00 GMT
修正しました
まつぼっくりさん、ご指摘ありがとうございます。
修正しました。
Apacheでは行末まですべて文字列として扱う場合は閉じダブルクオーテーションを入れないルールだと思いこんでいたのですが、それはApache 1.3時代のErrorDocument 403だけなんですね。たしか、閉じダブルクオーテーションを入れると、それも文字列として表示されるというおかしなルールなので、印象に残っていました。
確認すると、そもそもHeaderディレクティブの場合は閉じるのが正しいルールでしたし、いまはどんな文字列でも閉じダブルクオーテーションが必要なことになっていました。調査不足で失礼いたしました。実は、いまでも行末までを文字列として扱う場合は、閉じなくても動作するんですね。ですので、最初の記述で大丈夫なのだと思いこんでいました。勉強になりました!
勉強不足にてすみま
勉強不足にてすみません。質問させてください。
最低限バージョンにて記載されている「-」の意味は何でしょうか。
以下のように解釈しているのですが、「-」がどういった意味のコマンド(?)なのかがわかりません。
それ自体に意味をもっていないように感じるのですが、どういった場合に「-」は使えるのでしょうか。
ErrorDocument 503 /maintenance.html
#ステータスコードが503の場合、/maintenance.htmlというファイルを探せ
RewriteCond %{REQUEST_URI} !=/maintenance.html
#/maintenance.html以外のURLをリクエストしてきたら、以下の記述に従いなさい
RewriteRule ^.*$ - [R=503,L]
#任意のURLに対し、「-」へリダイレクトし、503ステータスコードを返しなさい
RewriteRuleの「-」はリライトなし
こんにちは。
RewriteRuleのリライト後URLとして「-」を指定すると、「URLを変更しない」指示になります。
つまり、
RewriteRule ^.*$ - [R=503,L]
は、
^.*$ どんなURLでも
- URLを変えずに
[R=503,L] レスポンスコードに503を返してRewrite処理を終了
という意味になります。
http://httpd.apache.org/docs/1.3/mod/mod_rewrite.html#RewriteRule
> '-' と呼ばれる特殊な置き換え文字列があります。
> これは、置換禁止! の意味です。
> 変でしょ? いいえ、これは URL のマッチングだけを行ない、
> 置換を行なわないという機能を提供してくれるものです。
Retry-AfterはGMTで
安田です。
さらに修正。Retry-Afterに日付を指定する場合は、JSTや+0900ではなく、GMTで指定する必要がありました(MUST be)。本文で+0900やJSTと書いていた部分があったので、修正しました。
HTTP-dateはGMT必須なんですね。知りませんでした。yoheiさんのご指摘に感謝です。
RewriteCondで[NC]を設定
RewriteCondで[NC]を設定していますが、これだと/Maintenance.htmlにアクセスした場合に404 Not Foundになりませんか?[NC]なしのほうがベターではないでしょうか?
Re: RewriteCondで[NC]を設定
安田です。コメントありがとうございます。
なるほど、たしかに。わざわざ[NC]する必要ないですね。ご指摘ありがとうございます。本文も修正しました。
Apache 1.3系や2.0系の場合のやり方
安田です。
RewriteRuleでR=503を指定するのは2.2系でしか使えないようですね。
2.0系とか1.3系では、別途PHPやPerlでレスポンスコードとして503を返す仕組みを作る必要があるのですが、そのあたりのわかりやすい解説がありましたので、1.3系とか2.0系のApacheを使っている人はこちらを参考にしてください。
http://www.shifft.in/blog/development/maintenance-mode/
ちょっと話がずれますが、
これも重要です。
ということがもう一つあります。
/maintenance.html
をクローラが読まないように
robots.txt
で読まないように指定した方がよいですよ。
私の作っているサービスで、
/maintenance.html
この画面のタイトル名をクロールされてしまって、
全部の記事がメンテナンス中です。
になったことがあります。。。。。
Re: ちょっと話がずれますが、
ここで紹介した手法は、503(メンテナンス画面)を検索エンジンにクロールさせないための手法ですから、/maintenance.htmlのクロール避けは必要ないですね。
503を使わずに/maintenance.htmlにリダイレクトするような手法でメンテ画面を出している場合はクロール避けをしておくべきですが。
UAをオリジナルにする
以前調べていた時に見かけたのですが、
オリジナルのUSER AGENTにするのは
どうでしょうか?
それ以外は、503を出すようにするとか。
まずいですか?