torutkのブログ

ソフトウェア・エンジニアのブログ

Redmineのアップデート作業時にNginxでメンテナンス中のメッセージを出したい

Redmineにはバナープラグインがあって、メンテナンス作業の予告を利用者に通知するのに活用しています。
https://github.com/akiko-pusu/redmine_banner

しかし、いざメンテナンス作業でRedmineを止めてしまうと、Webサーバーへのアクセスが内部エラー表示となってしまいます。Nginx + UnicornRedmineを動かしている場合、Unicornを停止するとNginxは、「Internal error」を表示します。

これは、メンテナンス作業中であることや終了予定日時を示すページを表示したいところです。

そこで、試行錯誤を始めました。Nginxでメンテナンスページ表示を検索すると、方法を紹介するページが多数ヒットしますが、それぞれ微妙に方法が異なります。見よう見真似で試してみますがどうもうまくいきません。

最小限の措置: 503エラーページを強制表示

とりあえず、/etc/nginx/conf.d/redmine.conf に無理やり1行追加で503エラーとしました。

server {
    listen 80;
    server_name _;
    root /var/lib/redmine/public;
    client_max_body_size 1G;

    return 503;

このように、return 503を有無を言わせず入れたら、

503 Service Temporarily Unavailable
------------------------------------
          nginx/1.11.1

という表示が出ました。

if文でファイル存在をチェックする方法が機能せず
server {
    listen 80;
    server_name _;
    root /var/lib/redmine/public;
    client_max_body_size 1G;

    if (-e /var/tmp/do_maintenance) {
        return 503;
    }

と、/var/tmp/do_maintenance ファイルがあるかをチェックして、あれば503エラーとするようにしたのですが、このif文がなぜか機能しませんでした。
うーむ。

maintenance.htmlがあるときはそれを表示、なければ通常通り

次のブログに、「ファイルがあれば表示、なければbackendに流す」という例がありました。
mod_rewriteをnginxに移植するコツはifを使わないコト! - インフラエンジニアway - Powered by HEARTBEATS

それを見て

    root /var/lib/redmine/public;
      :
    location / {
        try_files $uri/index.html $uri.html $uri @app;
    }

    root /var/lib/redmine/public;
      :
    location / {
        try_files /maintenance.html $uri/index.html $uri.html $uri @app;
    }

に修正し、/var/lib/redmine/public/maintenance.html を作成すると、maintenance.htmlの内容が表示されました。

これでいけそうです。