nginxの多段リバースプロキシ環境での各proxy_set_headerの設定

# はじめに
dockerコンテナでwebサーバを公開する際、いくつかのリバースプロキシを経由することになります。その際、正しくアクセス元のIP(remote_addr)を最後段のバックエンドまで伝えるために、各リバースプロキシとバックエンドの設定（主にproxy_set_header)を整理してみました。

###### 参考↓
https://www.serotoninpower.club/archives/780/

# こんな感じを想定
![多段プロキシ環境でのnginx設定_a.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/82975/4f64052e-7e5d-8f27-53d0-3c566684db98.png)

インターネットからのアクセス元（remote_addr)
1\.ルータのWAN（グローバルIP:153.153.153.153)にhttp://www.hoge.com/でアクセス
2\.ルータはポート80を最初のリバースプロキシ(revproxy0）にポートフォワード
3\.revproxy0はまずdocker host pcにproxy_pass
4\.docker host pcは内部のdockerコンテナに転送
５\.dockerコンテナの内部のrevproxy1で受けrevproxy2に転送
6\.最終的にrevproxy2はbackendに転送
### IPの流れ
![図２_a.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/82975/5c507032-1ace-4b52-e3d4-4cde8f58a31e.png)


# 各リバースプロキシの設定
※全てnginxとします。
+ revproxy0(192.168.1.1)
ルータのポートフォワードを受けdocker host pc（192.168.1.100）に転送する最初のリバースプロキシ
```conf:
server {
	server_name xxx.hoge.com;
	listen 80;
	location / {
	  proxy_set_header    Host    $host;
	  proxy_set_header    X-Forwarded-Host       $host;
	  proxy_set_header    X-Real-IP    $remote_addr;
	  proxy_set_header    X-Forwarded-For    $remote_addr;
	  proxy_pass	http://192.168.1.100/;
	}
}

```
+ docker host pc(192.168.1.100)
 dockerを起動していればrevproxy1に転送される。
 ↓dockerでの多段リバースプロキシ環境構築はこちら
 
 https://qiita.com/devzooiiooz/items/b8b5162dafc1b9059e57
 
+ revproxy1(172.16.0.10)
dockerコンテナの１番目のリバースプロキシ、revproxy2に転送する。
```conf:
server {
    server_name  _;
    listen       80;
    location / {
      proxy_set_header Host                   $host;
      proxy_set_header X-Forwarded-Host       $host;
      proxy_set_header X-Real-IP              $remote_addr;
      proxy_set_header X-Forwarded-For        "$http_x_forwarded_for, $realip_remote_addr";
      proxy_pass                              http://revproxy2;
    }
}

```
+ revproxy2(172.16.0.20)
dockerコンテナの２番目のリバースプロキシ、backendに転送する。
revproxy1とはproxy_passが異なるだけ。
```conf:
server {
    server_name _;
    listen      80;
    location / {
      proxy_set_header Host                   $host;
      proxy_set_header X-Forwarded-Host       $host;
      proxy_set_header X-Real-IP              $remote_addr;
      proxy_set_header X-Forwarded-For        "$http_x_forwarded_for, $realip_remote_addr";
      proxy_pass                              http://backend;
    }
}

```
+ backend(172.16.1.100)
最終的にWEBページを表示させるwebサーバ。運用ではwebアプリ（railsなど）になると思うが、検証環境なのでここもdockerコンテナのnginx。
revproxyと異なるのは後段にproxyする必要がないのでproxy_set_headerの記述が無い。
```conf:
  server {
    server_name _;
    listen       80;
    set_real_ip_from 192.168.1.1;
    set_real_ip_from proxy1;
    set_real_ip_from proxy2;
    real_ip_header    X-Forwarded-For;
    real_ip_recursive on;
    location / {
      root  /usr/share/nginx/html;
      index index.html;
    }
  }
```
# まとめ
1\.　ルータから受け取る最初のリバースプロキシ(revproxy0)のX-Forwarded-Forは「$remote_addr」

2\.　前段からデータを受け取って後段に流す各リバースプロキシ(revproxy1,revproxy2）のproxy_set_headerはどちらも同じ設定でよい。異なるのはproxy_pass先のみ。
```sh:
X-Forwarded-For "$http_x_forwarded_for,$realip_remote_addr”;
```
このようにすると、経由したリバースプロキシがわかる。

↓参考

https://www.serotoninpower.club/archives/790/#%E5%95%8F%E9%A1%8C2-real-ip-header%E3%81%AA%E3%81%A8%E3%82%99%E3%81%A6%E3%82%99-remote-addr%E3%81%8B%E3%82%99%E5%A4%89%E6%9B%B4%E3%81%95%E3%82%8C%E3%81%A6%E3%81%84%E3%82%8B%E5%A0%B4%E5%90%88%E3%80%81%E6%AD%A3%E3%81%97%E3%81%8F%E4%B8%8A%E6%B5%81%E3%83%95%E3%82%9A%E3%83%AD%E3%82%AD%E3%82%B7%E3%81%AEip%E3%82%A2%E3%83%88%E3%82%99%E3%83%AC%E3%82%B9%E3%82%92xff%E3%81%AB%E8%BF%BD%E5%8A%A0%E3%81%A6%E3%82%99%E3%81%8D%E3%81%AA%E3%81%84

3\.　最終的なbackendには、前段まで経由した各リバースプロキシをset_real_ip_fromで記述する。
docker内のリバースプロキシはdockerホスト名で良いが、最初のリバースプロキシはdocker内でホスト名の解決ができないため、IPアドレスで指定する。
real_ip_recursive onにすることで、remote_addrがバックエンドに伝わる。
```sh:
    #経由するリバースプロキシをすべて記載
    set_real_ip_from 192.168.1.1;
    set_real_ip_from proxy1;
    set_real_ip_from proxy2;

    real_ip_header    X-Forwarded-For;
    real_ip_recursive on;
```