ngx_mrubyを使って特定ホスト以外からのアクセスをメンテナンス画面にする
こんな感じ。(ほんとはもうちょいifが多い)
error_page 503 /maintenance.html; location = /maintenance.html { internal; } mruby_access_handler_code ' c = Nginx::Connection.new r = Nginx::Request.new Nginx.return -> do if File.exists?("/var/tmp/maint_ignore_office") && c.remote_ip == "192.168.1.3" return Nginx::DECLINED end if !File.exists?("/var/tmp/maint") return Nginx::DECLINED end # 503 return Nginx::HTTP_SERVICE_UNAVAILABLE end.call ';
これで、
/var/tmp/maint
が存在したらメンテナンス画面になって/var/tmp/maint_ignore_office
が存在して、且つアクセス元が192.168.1.3
であれば、そこは通常通りレスポンス
になる。
元々はひろせさんのこの方式で変数をsetしてコントロールしてたんだけど nginxで特定ホスト以外からのアクセスをメンテナンス画面にする方法 (2) - (ひ)メモ
その後ふじわらさんのフラグファイルみて切り替えるのがよいなぁと思って nginxで特定ホスト以外からのアクセスをメンテナンス画面にする方法 - 酒日記 はてな支店
でも特定ホスト(今回だとオフィス)からのみ開放するのもフラグファイルの有る無しでコントロールするとなると、またNginxの「複数条件できん」がネックで、うーんってなって、
あーそうだ!このNginxはngx_mrubyつかえるようになってるからそれでやろーっと。てなって上記のコードのようになった次第。
ちなみに、最初はこんな感じでハンドラのコードを書いたんだけど、これはうまくくいかなくて
if File.exists?("/var/tmp/maint_ignore_office") && c.remote_ip == "192.168.1.3" Nginx.return Nginx::DECLINED end if !File.exists?("/var/tmp/maint") Nginx.return Nginx::DECLINED end Nginx.return Nginx::HTTP_SERVICE_UNAVAILABLE
弊社は、同僚に @matsumotory がいるという便利な環境なので、聞いたら
Nginx.returnはコードからreturnするわけではないので 全部実行されちゃいます。
と教えてもらって、なるほどん!ってなって、次にこんな感じにしたら
if File.exists?("/var/tmp/maint_ignore_office") && c.remote_ip == "192.168.1.3" return Nginx.return Nginx::DECLINED end if !File.exists?("/var/tmp/maint") return Nginx.return Nginx::DECLINED end return Nginx.return Nginx::HTTP_SERVICE_UNAVAILABLE
こんどは、LocalJumpError
が出てしまって、あーなるほどmrubyのハンドラって関数なわけじゃないので途中で抜けれないのねぇってなって、lambdaにしてreturnする冒頭のコードに落ち着いたのでした。
褒めてもらった。
くろださんがngx_mrubyのNginx.returnをシャレオツな感じでreturnしてるのを見た
— MATSUMOTO, Ryosuke (@matsumotory) 2015, 7月 29
このラムダな書き方は、mruby_set
ディレクティブとかでも同様につかえて、なかなかシャレオツ便利です。
尚、今回は大したロジックでもないので、直接nginxの設定にコードを埋め込んでいるけど、複雑なのは、外部ファイルに切り出して、テストも書いた方がいいです。
テストのあたりは@hsbtさんのこれがわかりやすい。
構成管理(puppet)リポジトリでrake mtest
すると全ファイルのテストが実行されるようにしてます。
ngx_mruby大変便利なので、今後もどんどん使っていく所存です。