dockerでnginxを立ち上げたらログのremote_addrがbridgeのアドレスになってしまった件

前提

  • 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の話なので関係あるわけがなかった。