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

Docker Swarm集群中Nginx获取客户端真实IP的解决方案咨询

解决Docker Swarm中PHP获取客户端真实IP的问题

我来帮你搞定这个问题——这个坑我之前部署Swarm栈的时候也踩过,根源是Docker Swarm的Ingress网络默认会做SNAT(源地址转换),导致后端拿到的是Swarm内部节点的IP,而不是客户端的真实外部IP。咱们从Swarm端口配置和Nginx配置两方面入手解决:

1. 修改docker-compose.yml的端口发布规则

首先,你需要调整负责接收外部请求的服务(如果是Nginx当入口,就改Nginx的配置;如果是PHP直接对外,就改PHP服务)的端口发布方式,关闭SNAT,让Swarm直接把客户端IP透传给后端。

比如如果Nginx是你的入口服务,修改后的docker-compose.yml里的Nginx服务配置应该是这样:

version: '3'
services:
  nginx:
    image: nginx:alpine
    ports:
      - target: 80
        published: 80
        protocol: tcp
        mode: host  # 关键:用host模式绑定端口,避免Swarm做SNAT
    deploy:
      mode: global  # 因为host模式下每个节点只能跑一个实例,用global让每个节点都部署
      placement:
        constraints:
          - node.role == worker  # 可选,指定只部署到worker节点
  php:
    # 你的PHP服务配置...

注意:用mode: host的话,每个节点上只能运行该服务的一个实例,因为端口会直接绑定到节点的物理网卡,所以deploy模式建议用global,或者用replicated并设置max_replicas_per_node: 1。

2. 配置Nginx把真实IP传递给PHP

即使Swarm透传了IP,Nginx还需要正确配置才能把真实IP传给PHP。在你的Nginx配置文件(比如default.conf)的server块里添加这些内容:

server {
    # 你的其他Nginx配置,比如root、location等...

    # 启用真实IP解析,处理Swarm代理层的IP转换
    real_ip_header X-Forwarded-For;
    real_ip_recursive on;
    # 信任Swarm内部的IP段,根据你的Swarm实际网络调整
    set_real_ip_from 10.255.0.0/16;  # 默认Ingress网络的子网
    set_real_ip_from 172.17.0.0/16;  # Docker默认桥接网络,按需添加

    # 把真实IP传递给PHP-FPM
    location ~ \.php$ {
        # 你的fastcgi_pass等配置...
        fastcgi_param REMOTE_ADDR $remote_addr;
        fastcgi_param HTTP_X_FORWARDED_FOR $http_x_forwarded_for;
    }
}

解释一下:real_ip_header告诉Nginx从X-Forwarded-For头里取真实IP,set_real_ip_from指定哪些IP是可信的代理(比如Swarm的内部节点),这样Nginx就会把这些代理发来的请求里的客户端真实IP提取出来。最后通过fastcgi_param把真实IP传给PHP,这样PHP就能通过$_SERVER['REMOTE_ADDR']或者$_SERVER['HTTP_X_FORWARDED_FOR']拿到真实的客户端IP了。

3. 验证配置是否生效

重新部署你的Swarm栈:

docker stack deploy -c docker-compose.yml your-stack-name

然后在PHP里新建一个测试文件info.php:

<?php
echo "真实IP(REMOTE_ADDR):" . $_SERVER['REMOTE_ADDR'] . "<br>";
echo "X-Forwarded-For:" . $_SERVER['HTTP_X_FORWARDED_FOR'] . "<br>";
?>

访问这个文件,就能看到客户端的真实外部IP了。

补充小提示

  • 如果你的PHP服务是直接对外暴露端口(没有Nginx反向代理),那只需要把PHP服务的ports配置改成mode: host,就能直接拿到真实IP。
  • 不确定Swarm的内部IP段的话,可以用docker network inspect ingress查看Subnet字段,把对应的网段添加到set_real_ip_from里。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.20 11:50:01