はじめに
dockerコンテナでwebサーバを公開する際、いくつかのリバースプロキシを経由することになります。その際、正しくアクセス元のIP(remote_addr)を最後段のバックエンドまで伝えるために、各リバースプロキシとバックエンドの設定(主にproxy_set_header)を整理してみました。
参考↓
こんな感じを想定
インターネットからのアクセス元(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コンテナに転送
5.dockerコンテナの内部のrevproxy1で受けrevproxy2に転送
6.最終的にrevproxy2はbackendに転送
IPの流れ
各リバースプロキシの設定
※全てnginxとします。
- revproxy0(192.168.1.1)
ルータのポートフォワードを受けdocker host pc(192.168.1.100)に転送する最初のリバースプロキシ
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での多段リバースプロキシ環境構築はこちら
- revproxy1(172.16.0.10)
dockerコンテナの1番目のリバースプロキシ、revproxy2に転送する。
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コンテナの2番目のリバースプロキシ、backendに転送する。
revproxy1とはproxy_passが異なるだけ。
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の記述が無い。
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先のみ。
X-Forwarded-For "$http_x_forwarded_for,$realip_remote_addr”;
このようにすると、経由したリバースプロキシがわかる。
↓参考
3. 最終的なbackendには、前段まで経由した各リバースプロキシをset_real_ip_fromで記述する。
docker内のリバースプロキシはdockerホスト名で良いが、最初のリバースプロキシはdocker内でホスト名の解決ができないため、IPアドレスで指定する。
real_ip_recursive onにすることで、remote_addrがバックエンドに伝わる。
#経由するリバースプロキシをすべて記載
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;