Nginxのリバースプロキシ設定は以下の4パターンになる。
パターン | location | proxy_pass |
---|---|---|
1 | /path | /reverse-path |
2 | /path | /reverse-path/ |
3 | /path/ | /reverse-path |
4 | /path/ | /reverse-path/ |
これに対し、4パターンのリクエストを投げて実験を行った。
- http://example.com/path
- http://example.com/path/
- http://example.com/path-test
- http://example.com/path/test
末尾スラッシュ(Trailing Slash)による挙動の違い
結論から先にまとめる。
location
locationの末尾スラッシュがない場合は前方一致、ある場合はURIの完全一致になる。結果は以下のとおり。
- location /path
- http://example.com/path → OK
- http://example.com/path/ → OK
- http://example.com/path-test → OK
- location /path/
- http://example.com/path → 301 Moved Permanently
- http://example.com/path/ → OK
- http://example.com/path-test → 404 Not Found
proxy_pass
proxy_passの末尾スラッシュがない場合はプロキシ先のURIにスラッシュがつかない、ある場合はスラッシュがつく。結果は以下のとおり。
- proxy_pass /reverse-path;
- http://example.com/path/ → /reverse-path
- http://example.com/path/test → /reverse-pathtest
- proxy_path /reverse-path/;
- http://example.com/path/ → /reverse-path/
- http://example.com/path/test → /reverse-path/test
末尾スラッシュの挙動まとめ
- location末尾スラッシュなし、proxy_pass末尾スラッシュなし
- GET /path → GET /reverse-path
- GET /path/ → GET /reverse-path/
- GET /path-test → GET /reverse-path-test
- GET /path/test → GET /reverse-path/test
- location末尾スラッシュなし、proxy_pass末尾スラッシュあり
- GET /path → GET /reverse-path/
- GET /path/ → GET /reverse-path//
- GET /path-test → GET /reverse-path/-test
- GET /path/test → GET /reverse-path//test
- location末尾スラッシュあり、proxy_pass末尾スラッシュなし
- GET /path → 301 Moved Permanently
- GET /path/ → GET /reverse-path/
- GET /path-test → 404 Not Found
- GET /path/test → GET /reverse-pathtest
- location末尾スラッシュあり、proxy_pass末尾スラッシュあり
- GET /path → 301 Moved Permanently
- GET /path/ → GET /reverse-path/
- GET /path-test → 404 Not Found
- GET /path/test → GET /reverse-path/test
結論: locationとproxy_passの末尾スラッシュはつけておいたほうが良い
locationとproxy_passの末尾スラッシュの有無がどのように影響するかわかっていただけたと思う。意図しないリバースプロキシを避けるために、locationとproxy_passの末尾スラッシュはつけておいたほうが安全だろう。以降は、私がリバースプロキシの挙動を理解するために行った実験の手順をまとめる。
リバースプロキシの挙動を確認するための準備
Nginxをインストールする
Nginxの公式イメージを使って、DockerでNginxを起動する。もちろんローカルにインストールしても問題ない。# Nginxのコンテナを起動する
$ docker run --name learn-nginx -d -p 8080:80 nginx
使っているオプションの意味は以下のとおり。
- --name: コンテナに名前をつける
- -d: デタッチモード(バックグラウンド実行)
- -p: ポートフォワード
Nginxのconfigファイルを編集する
起動中のNginxのコンテナにログインする。$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
fa71f41f9ad0 nginx "nginx -g 'daemon of…" 4 seconds ago Up 3 seconds 0.0.0.0:8080->80/tcp learn-nginx
# dockerにログインする
$ docker exec -it learn-nginx /bin/bash
root@fa71f41f9ad0:/#
Nginxのデバッグ用のログ出力と、リバースプロキシの設定を行う。
と、その前にNginxのイメージにはエディタが入っていないので、vimをインストールする。(nanoでもviでもemacsでも可)
container$ apt-get update
container$ apt-get install vim
まずはリバースプロキシのログを出力するために、
/etc/nginx/nginx.conf
を修正する。container$ cd /etc/nginx
container$ vim nginx.conf
container$ cat nginx.conf
# /etc/nginx/nginx.conf
# 省略
http {
# 省略
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
# reverse-proxy用のログを追加
log_format upstreamlog '[$time_local] $remote_addr $host $upstream_addr $request';
access_log /var/log/nginx/upstream.log upstreamlog;
# 省略
}
# Confファイルのチェック
container$ nginx -t
# 設定ファイルを反映させる
container$ nginx -s reload
# ログを表示する(tail -fでファイルが更新されたら自動的に表示される)
container$ cd /var/log/nginx
container$ tail -f upstream.log
# ローカルマシンからcurlしてみる
$ curl localhost:8080
# upstream.logのログ
[08/Mar/2019:09:27:33 +0000] 172.17.0.1 localhost - GET / HTTP/1.1
次にリバースプロキシの設定を行う。
container$ cd /etc/nginx/conf.d
container$ vim reverse-proxy.conf
container$ cat reverse-proxy.conf
# /etc/nginx/conf.d/reverse-proxy.conf
server {
listen 80;
server_name localhost 127.0.0.1;
location /path1 {
resolver 127.0.0.1;
proxy_pass http://host.docker.internal:3000/reverse-path1;
}
location /path2 {
resolver 127.0.0.1;
proxy_pass http://host.docker.internal:3000/reverse-path2/;
}
location /path3/ {
resolver 127.0.0.1;
proxy_pass http://host.docker.internal:3000/reverse-path3;
}
location /path4/ {
resolver 127.0.0.1;
proxy_pass http://host.docker.internal:3000/reverse-path4/;
}
}
# confファイルのチェックをする
container$ nginx -t
# もし以下のようなserver nameがコンフリクトしているという警告が表示されたら
container$ nginx -t
2019/03/11 01:51:13 [warn] 3512#3512: conflicting server name "localhost" on 0.0.0.0:80, ignored
nginx: [warn] conflicting server name "localhost" on 0.0.0.0:80, ignored
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
# default.confのserver_nameをコメントアウトしておく
container$ vim default.conf
これでNginxの設定は終わり。
ローカルにリバースプロキシ先のサーバを立てる
想定通りのパスにプロキシされるか確認するために、Node.jsで簡易APIサーバを立てる。# json-serverのインストール
$ npm i json-server
# json-serverを起動する (api.jsonは実行時に自動生成されるので作成は不要)
$ npx json-server --watch api.json
\{^_^}/ hi!
Loading api.json
Oops, api.json doesn't seem to exist
Creating api.json with some default data
Done
Resources
http://localhost:3000/posts
http://localhost:3000/comments
http://localhost:3000/profile
Home
http://localhost:3000
Type s + enter at any time to create a snapshot of the database
Watching...
これでhttp://localhost:3000にリクエストすることでログが表示される。
json-serverの詳しい使い方は、以下の記事を参照してください。
末尾スラッシュによりリバースプロキシがどのように動作するか確認する
以下の4つのリバースプロキシに対して、4つのリクエストを投げて確認した。
リバースプロキシの設定
パターン | location | proxy_pass |
---|---|---|
1 | /path | /reverse-path |
2 | /path | /reverse-path/ |
3 | /path/ | /reverse-path |
4 | /path/ | /reverse-path/ |
確認用リクエスト
- http://localhost:8080/path
- http://localhost:8080/path/
- http://localhost:8080/path-test
- http://localhost:8080/path/test
パターン1: location末尾スラッシュなし、proxy_pass末尾スラッシュなし
# GET /path1
$ curl localhost:8080/path1
# nginxログ
[11/Mar/2019:04:33:48 +0000] 172.17.0.1 localhost 192.168.65.2:3000 GET /path1 HTTP/1.1
# プロキシ先
GET /reverse-path1 404 4.613 ms
# GET /path1/
$ curl localhost:8080/path1/
# nginxログ
[13/Mar/2019:06:10:25 +0000] 172.17.0.1 localhost 192.168.65.2:3000 GET /path1/ HTTP/1.1
# プロキシ先
GET /reverse-path1/ 404 1.363 ms
# GET /path1-test
$ curl localhost:8080/path1-test
# nginxログ
[13/Mar/2019:05:17:11 +0000] 172.17.0.1 localhost 192.168.65.2:3000 GET /path1-test HTTP/1.1
# プロキシ先
GET /reverse-path1-test 404 1.576 ms
# GET /path1/test
$ curl localhost:8080/path1/test
# nginxログ
[11/Mar/2019:04:33:56 +0000] 172.17.0.1 localhost 192.168.65.2:3000 GET /path1/test HTTP/1.1
# プロキシ先
GET /reverse-path1/test 404 1.820 ms
パターン2: location末尾スラッシュなし、proxy_pass末尾スラッシュあり
# GET /path2
$ curl localhost:8080/path2
# nginxログ
[11/Mar/2019:04:34:14 +0000] 172.17.0.1 localhost 192.168.65.2:3000 GET /path2 HTTP/1.1
# プロキシ先
GET /reverse-path2/ 404 1.883 ms
# GET /path2/
$ curl localhost:8080/path2/
# nginxログ
[13/Mar/2019:06:11:28 +0000] 172.17.0.1 localhost 192.168.65.2:3000 GET /path2/ HTTP/1.1
# プロキシ先
GET /reverse-path2// 404 1.363 ms
# GET /path2-test
$ curl localhost:8080/path2-test
# nginxログ
[13/Mar/2019:05:17:58 +0000] 172.17.0.1 localhost 192.168.65.2:3000 GET /path2-test HTTP/1.1
# プロキシ先
GET /reverse-path2/-test 404 1.357 ms
# GET /path2/test
$ curl localhost:8080/path2/test
# nginxログ
[11/Mar/2019:04:34:18 +0000] 172.17.0.1 localhost 192.168.65.2:3000 GET /path2/test HTTP/1.1
# プロキシ先
GET /reverse-path2//test 404 1.785 ms
パターン3: location末尾スラッシュあり、proxy_pass末尾スラッシュなし
# GET /path3
$ curl localhost:8080/path3
301 Moved Permanently
# nginxログ
[11/Mar/2019:04:34:21 +0000] 172.17.0.1 localhost - GET /path3 HTTP/1.1
# GET /path3/
$ curl localhost:8080/path3/
# nginxログ
[13/Mar/2019:06:12:01 +0000] 172.17.0.1 localhost 192.168.65.2:3000 GET /path3/ HTTP/1.1
# プロキシ先
GET /reverse-path3 404 1.467 ms
# GET /path3-test
$ curl localhost:8080/path3-test
404 Not Found
# nginxログ
[13/Mar/2019:05:18:43 +0000] 172.17.0.1 localhost - GET /path3-test HTTP/1.1
# GET /path3/test
$ curl localhost:8080/path3/test
# nginxログ
[11/Mar/2019:04:34:30 +0000] 172.17.0.1 localhost 192.168.65.2:3000 GET /path3/test HTTP/1.1
# プロキシ先
GET /reverse-path3test 404 1.626 ms
パターン4: location末尾スラッシュあり、proxy_pass末尾スラッシュあり
# GET /path4
$ curl localhost:8080/path4
301 Moved Permanently
# nginxログ
[11/Mar/2019:04:34:37 +0000] 172.17.0.1 localhost - GET /path4 HTTP/1.1
# GET /path4/
$ curl localhost:8080/path4/
# nginxログ
[13/Mar/2019:06:12:45 +0000] 172.17.0.1 localhost 192.168.65.2:3000 GET /path4/ HTTP/1.1
# プロキシ先
GET /reverse-path4/ 404 1.404 ms
# GET /path4-test
$ curl localhost:8080/path4-test
404 Not Found
# nginxログ
[13/Mar/2019:05:19:33 +0000] 172.17.0.1 localhost - GET /path4-test HTTP/1.1
# GET /path4/test
$ curl localhost:8080/path4/test
# nginxログ
[11/Mar/2019:04:34:41 +0000] 172.17.0.1 localhost 192.168.65.2:3000 GET /path4/test HTTP/1.1
# プロキシ先
GET /reverse-path4/test
参考サイト
- Dockerコンテナ内のNginxからホストOSのlocalhostにアクセスする
- json-serverでREST APIモックサーバを立てテスト駆動開発する
- NGINX Docs | Configuring Logging
- logging proxy activity in nginx - Stack Overflow
以上
written by @bc_rikko
0 件のコメント :
コメントを投稿