You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Docker环境下Nginx访问日志无法显示真实远程IP的求助

Docker容器中Nginx访问日志显示内部IP的问题

我在Docker容器中部署了Nginx,但访问日志里的远程地址一直是Docker内部网络IP,试了谷歌前两页的方案都没解决。我需要日志显示真实远程IP,这样fail2ban才能正常拦截恶意请求IP。

以下是我的配置文件:

docker-compose.yml

version: "3"

services:
  web:
    build:
      context: ./
      dockerfile: Dockerfile-test
    volumes:
      - ./api:/var/www/html/app/api
      - ./frontend:/var/www/html/app/frontend
    ports:
      - "80:80"
    networks:
      - app

  mysql:
    image: 'mysql:8.0'
    volumes:
      - mysql_conf:/etc/mysql/conf.d
      - db_data:/var/lib/mysql
      - mysql_logs:/var/log/mysql
    ports:
      - "3306:3306"
    environment:
      MYSQL_ROOT_PASSWORD: '${MYSQL_ROOT_PASSWORD}'
      MYSQL_USER: '${DB_USERNAME}'
      MYSQL_DATABASE: '${DB_DATABASE}'
      MYSQL_PASSWORD: '${DB_PASSWORD}'
    networks:
      - app

  mailhog:
    image: 'mailhog/mailhog:latest'
    ports:
      - "1025:1025"
      - "8025:8025"
    networks:
      - app
volumes:
  mysql_conf:
  mysql_logs:
  db_data:
    driver: local

networks:
  app:
    driver: bridge

"web"服务包含Nginx、Laravel应用和前端应用,基于php:8.0-fpm构建镜像

Nginx配置(conf.d文件夹内)

upstream frontend {
    server localhost:3000;
}

upstream api {
    server localhost:9000;
}

server {
    listen 80;
    server_name localhost;

    error_log stderr;
    error_log /var/log/nginx/error.log;

    access_log stdout;
    access_log /var/log/nginx/access.log;

    # don't send the nginx version number in error pages and Server header
    server_tokens off;
    # config to don't allow the browser to render the page inside an frame or iframe
    # and avoid clickjacking http://en.wikipedia.org/wiki/Clickjacking
    # if you need to allow [i]frames, you can use SAMEORIGIN or even set an uri with ALLOW-FROM uri
    # https://developer.mozilla.org/en-US/docs/HTTP/X-Frame-Options
    # when serving user-supplied content, include a X-Content-Type-Options: nosniff header along with the Content-Type: header,
    # to disable content-type sniffing on some browsers.
    # https://www.owasp.org/index.php/List_of_useful_HTTP_headers
    # currently suppoorted in IE > 8 http://blogs.msdn.com/b/ie/archive/2008/09/02/ie8-security-part-vi-beta-2-update.aspx
    # http://msdn.microsoft.com/en-us/library/ie/gg622941(v=vs.85).aspx
    # 'soon' on Firefox https://bugzilla.mozilla.org/show_bug.cgi?id=471020
    add_header X-Content-Type-Options nosniff;

    add_header X-Frame-Options SAMEORIGIN;

    location / {
        proxy_pass http://frontend;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For    $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto  $scheme;
        proxy_read_timeout          1m;
        proxy_connect_timeout       1m;
        proxy_redirect off;
    }

    location /api/v1 {
        root /var/www/html/app/api/public;
        include fastcgi_params;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
        fastcgi_buffers 16 16k;
        fastcgi_buffer_size 32k;
        fastcgi_intercept_errors off;
        fastcgi_pass 127.0.0.1:9000;
        fastcgi_param SCRIPT_FILENAME $document_root/index.php;
        fastcgi_param DOCUMENT_ROOT $realpath_root;
    }

    # Deny .ht* access
    location ~ /\.ht {
            deny all;
    }
}

我还尝试过给web服务添加以下host模式配置,但也没有效果:

ports:
  - mode: host
    protocol: tcp
    published: 80
    target: 80
  - mode: host
    protocol: tcp
    published: 443
    target: 80

解决方案

核心问题梳理

Docker默认桥接网络会做端口转发,导致Nginx拿到的$remote_addr是Docker网关IP而非真实客户端IP;同时你的Nginx配置存在冗余参数,且未配置信任代理来源,无法正确解析真实IP头。

具体修复步骤

1. 调整Docker配置,确保IP传递

在docker-compose.yml的web服务中添加信任网段环境变量(或直接改用host模式):

services:
  web:
    # 其他配置不变
    environment:
      - TRUSTED_PROXIES=172.17.0.0/16 # 替换为你的Docker桥接实际网段

若改用host模式,删除networks: - app和ports配置,添加network_mode: host即可

2. 修改Nginx全局配置(nginx.conf的http块中)

添加真实IP解析规则,信任Docker内部网段:

# 信任Docker网关网段,从X-Forwarded-For头提取真实IP
set_real_ip_from 172.17.0.0/16;
real_ip_header X-Forwarded-For;
real_ip_recursive on;

3. 优化server块配置

  • 前端反向代理(location /):保留现有proxy_set_header配置即可
  • API的fastcgi配置(location /api/v1):删除冗余的proxy_set_header,改用fastcgi参数传递真实IP:
location /api/v1 {
    root /var/www/html/app/api/public;
    include fastcgi_params;
    fastcgi_buffers 16 16k;
    fastcgi_buffer_size 32k;
    fastcgi_intercept_errors off;
    fastcgi_pass 127.0.0.1:9000;
    fastcgi_param SCRIPT_FILENAME $document_root/index.php;
    fastcgi_param DOCUMENT_ROOT $realpath_root;
    # 传递真实IP给PHP
    fastcgi_param REMOTE_ADDR $realip_remote_addr;
    fastcgi_param HTTP_X_FORWARDED_FOR $realip_remote_addr;
}

4. 修改访问日志格式,记录真实IP

调整access_log配置,用$realip_remote_addr替代默认的$remote_addr:

access_log /var/log/nginx/access.log '$realip_remote_addr - $remote_user [$time_local] "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent"';

5. 验证生效

重启web容器:docker-compose restart web,访问服务后查看access.log,确认显示真实客户端IP,再测试fail2ban拦截功能。

额外注意事项

  • 若使用CDN或外部反向代理,需将对应IP段加入set_real_ip_from
  • 可关闭Docker的userland-proxy避免干扰:在/etc/docker/daemon.json中添加{"userland-proxy": false},然后重启Docker服务

内容的提问来源于stack exchange,提问作者DGregory

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 09:15:22