前提
- docker-composeでnginxとphp-fpmを立ち上げる
- nginxがリバースプロキシ、php-fpmがバックエンドアプリケーション
- nginxはphp-fpmのport 9000にproxy_passしている
というものを作ったらnginxのアクセスログのremote_addrがdockerのブリッジネットワークのhostのもの(172.18.0.1)になってしまった。
172.18.0.1 - - [29/Aug/2020:15:42:36 +0000] "GET / HTTP/2.0" 200 1125 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:80.0) Gecko/20100101 Firefox/80.0"
composeファイルはこんな感じ
version: "3" services: nginx: image: nginx:1.19.2-alpine restart: always ports: - 80:80 - 443:443 depends_on: - php-fpm php-fpm: image: php:7.4.9-fpm-alpine restart: always
これを防ぐため色々試してみたのだが、どうやらnginxを network_mode: host
で起動すると良さそうだ。
services: nginx: image: nginx:1.19.2-alpine restart: always depends_on: - php-fpm network_mode: host
ただ、この設定ではバックエンドアプリとの通信設定を見直す必要がある。nginxコンテナのネットワークはホストOSのものがそのまま使われているため、dockerネットワークを通したコンテナ間通信ができない。よってサービス名での接続先指定もできない。fastcgi_pass php-fpm:9000;
みたいな設定はNG
nginxコンテナのネットワークはホストOSのものということは、nginxコンテナは127.0.0.1でホストにアクセスできるということ。よってphp-fpmのportをホストに晒して127.0.0.1でアクセスすれば良い。
version: "3" services: nginx: image: nginx:1.19.2-alpine restart: always depends_on: - php-fpm network_mode: host php-fpm: image: php:7.4.9-fpm-alpine restart: always ports: - 127.0.0.1:9000:9000
nginxのproxy設定は
location ~ \.php$ { fastcgi_pass 127.0.0.1:9000; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; include fastcgi_params; }
今回はphp-fpmに外部からアクセスされたくないので127.0.0.1でバインドしている。portの設定を以下のようにすると外部から自由にアクセスできてしまうので注意。
php-fpm: image: php:7.4.9-fpm-alpine restart: always ports: - 9000:9000 # 危険、0.0.0.0でバインドされるので外部からアクセス可能
追記
IPv6でアクセスすると172.18.0.1になってしまうようだ。
nginxは外向きにはIPv6でもlistenしている。しかしdocker networkではv6がオフになっているのでホスト-nginx間の通信がv4にフォールバックし、その過程でv6のremote addrが失われているのだろう。
であれば、おそらくdocker networkのIPv6をオンにすればbridgeモードでも正しいremote addrがログに残るようになると思われる。
php-fpmは一切関係ない。まあproxyされる前のnginxの話なので関係あるわけがなかった。