LoginSignup
5

More than 5 years have passed since last update.

posted at

Organization

備忘録: nginx でアクセス元 IP レンジに応じて Web アプリケーションを切り替える

あるイントラネット用の Web アプリケーションのアップグレードを試していて、次のようなことをしたい場合があった。

  1. 特定の IP からのアクセスでは次バージョンのサイトに接続する (試験ユーザ)
  2. それ以外の IP からのアクセスは現バージョンのサイトに接続する (通常ユーザ)

ローカルホストで試験するという手段もあるが、

A. ホスト名に依存する処理がある (外部の認証機構からリダイレクトする、など)
B. HTTPS 限定のサイトである (このために証明書等をローカルホストに移すのは手間かつセキュアでない)
C. 複数人のアクセスを想定している (ので人数分の /etc/hosts を書き換えるのも容易ではない)

といった条件もあり「リバースプロキシ側 (nginx) でアクセス元の IP レンジに応じて Web アプリケーションを切り替える」という方針で進めることにした。なおかつ、なるべく手軽にやりたかった。

内容はとてもシンプルだけど、すぐ忘れそうなので、備忘録として残しておく。

こう書いた

今回の要旨と関係のないディレクティブは全て省略した。
登場人物は 3 つ。

普通のユーザに見せたい方のサイトを usual_server, 試験者のサイトを testing_server と定義した。

/etc/ngnix/sites-available/site.example.com.conf
upstream usual_server {
  server 127.0.0.1:8080;
}

upstream testing_server {
  server 127.0.0.1:8081;
}

geo $maintenance {
  default 0;
  # 許可したい IP レンジ
  192.168.100.105/32 1;
}

server {
  if ($maintenance = 0) {
    set $target_proxy_server "usual_server";
  }

  if ($maintenance = 1) {
    set $target_proxy_server "testing_server";
  }

  location / {
    proxy_pass http://$target_proxy_server;
  }
}

あとは

$ sudo service nginx configtest && sudo service nginx reload

なぜこのような書き方にするか

If Is Evil にも書かれているように、 nginx では location context 内での if はうまく処理できない問題がある。

下記は動作しない。

だめな例
if ($maintenance = 1) {
  location / {
    proxy_pass http://$testing_server;
  }
}
if ($maintenance = 0) {
  location / {
    proxy_pass http://$usual_server;
  }
}

また、 nginx の if には else に対応するものがない。
「複雑なことは if で制御しようとせず、なるべくなら使わない、使っても set くらいにする」と捉えておけば問題ないはず。

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
What you can do with signing up
5