如何让Docker容器看到真实的用户IP?

31

问题

nginx-proxy Docker容器内(更多信息见下文),每个连接始终显示相同的IP地址:172.18.0.1(即nginx-proxy网络网关)。例如:

nginx.1    | www.my-site.tld 172.18.0.1 - - [28/Nov/2017:17:22:21 +0000] "GET /some/path HTTP/2.0" 200 46576 "https://www.my-site.tld/some/path" "Mozilla/5.0 (Linux; Android 4.4.2; PSP5507DUO Build/KVT49L) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 YaBrowser/17.10.0.446.00 Mobile Safari/537.36"

无论我是从外部网络还是本地机器,甚至从服务器(主机)本身发出请求,IP地址始终为172.18.0.1
我需要看到真实的客户端IP。
尝试修复
我经过大量搜索并尝试了不同的解决方案,但都没有成功。我尝试了以下方法:
  • 禁用firewalld(当然,在这种情况下什么都不起作用,iptables为空);
  • 使用--userland-proxy=false(没有运气);
  • 使用--net=host(根本不是解决方案,也不起作用)。
  • 相关链接:

    那么,有什么想法吗?似乎是iptables路由问题或内部Docker错误。无论如何,它肯定与Docker相关,因为以下内容显示了正确的远程用户IP:

    [root@server]# nc -lv 12345
    
    [user@remote-client]$ nc -vz MY.IP.ADDRESS.HERE 12345
    

    非常奇怪!

    现在我将提供有关系统的完整信息,请耐心等待。:)

    基本

    我安装了Centos 7.4和Docker:

    # cat /etc/centos-release
    CentOS Linux release 7.4.1708 (Core)
    
    # uname -r
    3.10.0-693.5.2.el7.x86_64
    
    # docker version
    Client:
     Version:      17.09.0-ce
     API version:  1.32
     Go version:   go1.8.3
     Git commit:   afdb6d4
     Built:        Tue Sep 26 22:41:23 2017
     OS/Arch:      linux/amd64
    
    Server:
     Version:      17.09.0-ce
     API version:  1.32 (minimum version 1.12)
     Go version:   go1.8.3
     Git commit:   afdb6d4
     Built:        Tue Sep 26 22:42:49 2017
     OS/Arch:      linux/amd64
     Experimental: false
    

    firewalld被用作防火墙。

    网络配置

    接口

    有三个物理接口:

    # ifconfig | grep -A 7 enp
    enp1s0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
            inet6 fe80::1ad6:c7ff:fe00:fc98  prefixlen 64  scopeid 0x20<link>
            ether 18:d6:c7:00:fc:98  txqueuelen 1000  (Ethernet)
            RX packets 11530516  bytes 2220554890 (2.0 GiB)
            RX errors 0  dropped 0  overruns 0  frame 0
            TX packets 24237462  bytes 31702254967 (29.5 GiB)
            TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
    
    enp2s0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
            inet6 fe80::1ad6:c7ff:fe06:ef36  prefixlen 64  scopeid 0x20<link>
            ether 18:d6:c7:06:ef:36  txqueuelen 1000  (Ethernet)
            RX packets 948513  bytes 143294797 (136.6 MiB)
            RX errors 0  dropped 0  overruns 0  frame 0
            TX packets 2371584  bytes 3207775040 (2.9 GiB)
            TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
    
    enp3s0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
            inet 31.172.141.111  netmask 255.255.255.128  broadcast MY.EXTERNAL.IP.HERE
            inet6 fe80::127b:44ff:fe46:c2d1  prefixlen 64  scopeid 0x20<link>
            ether 10:7b:44:46:c2:d1  txqueuelen 1000  (Ethernet)
            RX packets 46772225  bytes 57416420859 (53.4 GiB)
            RX errors 0  dropped 1  overruns 0  frame 0
            TX packets 28814037  bytes 10943786995 (10.1 GiB)
            TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
    

    还有一个虚拟桥接器(enp1s0enp2s0):

    # ifconfig | grep -A 7 virbr
    virbr0: flags=4163<UP,BROADCAST,RUNNING,MULTICAST>  mtu 1500
            inet 192.168.0.1  netmask 255.255.255.0  broadcast 192.168.0.255
            inet6 fe80::1ad6:c7ff:fe00:fc98  prefixlen 64  scopeid 0x20<link>
            ether 18:d6:c7:00:fc:98  txqueuelen 1000  (Ethernet)
            RX packets 11542053  bytes 2042945874 (1.9 GiB)
            RX errors 0  dropped 0  overruns 0  frame 0
            TX packets 26586017  bytes 34919742970 (32.5 GiB)
            TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
    

    防火墙区域

    enp3s0接口连接到互联网 (--zone=public),而virbr0连接到内部本地网络 (--zone=internal)。

    转发和伪装

    IPv4转发已启用:

    # cat /proc/sys/net/ipv4/ip_forward
    1
    

    并且伪装在public区域已经配置了防火墙:

    # firewall-cmd --zone=public --list-all
    success
    

    Docker配置

    Docker有默认配置。

    网络

    我只创建了一个网络:

    # docker network create -d bridge nginx-proxy
    

    这是它的配置:

    # docker network inspect nginx-proxy
    [
        {
            "Name": "nginx-proxy",
            "Id": "192821446c9a5891fd1a7e240533cefb81ba0548033acb605eea805abec83505",
            "Created": "2017-11-24T14:25:10.687199435+02:00",
            "Scope": "local",
            "Driver": "bridge",
            "EnableIPv6": false,
            "IPAM": {
                "Driver": "default",
                "Options": {},
                "Config": [
                    {
                        "Subnet": "172.18.0.0/16",
                        "Gateway": "172.18.0.1"
                    }
                ]
            },
            "Internal": false,
            "Attachable": false,
            "Ingress": false,
            "ConfigFrom": {
                "Network": ""
            },
            "ConfigOnly": false,
            "Containers": {
                "1c563c33a45c9feabee4cb5ec3194464c66bfad1e233dedb797e269649067159": {
                    "Name": "nginxproxy_nginx-proxy_1",
                    "EndpointID": "683ceaced8eb416b485775734ca6828e9eced5ea6e3c7a76960c4eb807b521d9",
                    "MacAddress": "02:42:ac:12:00:02",
                    "IPv4Address": "172.18.0.2/16",
                    "IPv6Address": ""
                }
            },
            "Options": {},
            "Labels": {}
        }
    ]
    

    图片和容器

    我正在使用jwilder/nginx-proxy图像。这是我的docker-compose.yml文件:

    version: '3'
    services:
      nginx-proxy:
        image: jwilder/nginx-proxy:alpine
        labels:
          - 'com.github.jrcs.letsencrypt_nginx_proxy_companion.nginx_proxy=true'
        volumes:
          - /var/run/docker.sock:/tmp/docker.sock:ro
        ports:
          - '80:80'
          - '443:443'
        networks:
          nginx-proxy:
    networks:
      nginx-proxy:
    depends_on:
      - nginx-proxy
    
    networks:
      nginx-proxy:
        external:
          name: nginx-proxy
    

    正如您所看到的,nginx-proxy容器正在所有接口上监听端口80443

    # docker ps | grep nginx-proxy
    1c563c33a45c        jwilder/nginx-proxy:alpine                        "/app/docker-entry..."   8 hours ago         Up 8 hours          0.0.0.0:80->80/tcp, 0.0.0.0:443->443/tcp   nginxproxy_nginx-proxy_1
    

    iptables

    与容器相关的规则

    以下是与容器相关的iptables规则:

    # iptables-save | grep -e br-192821446c9a -e 172.18.0 -e '\*'
    *mangle
    *security
    *raw
    *filter
    -A FORWARD -o br-192821446c9a -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
    -A FORWARD -o br-192821446c9a -j DOCKER
    -A FORWARD -i br-192821446c9a ! -o br-192821446c9a -j ACCEPT
    -A FORWARD -i br-192821446c9a -o br-192821446c9a -j ACCEPT
    -A DOCKER -d 172.18.0.2/32 ! -i br-192821446c9a -o br-192821446c9a -p tcp -m tcp --dport 443 -j ACCEPT
    -A DOCKER -d 172.18.0.2/32 ! -i br-192821446c9a -o br-192821446c9a -p tcp -m tcp --dport 80 -j ACCEPT
    *nat
    -A POSTROUTING -s 172.18.0.0/16 ! -o br-192821446c9a -j MASQUERADE
    -A POSTROUTING -s 172.18.0.2/32 -d 172.18.0.2/32 -p tcp -m tcp --dport 443 -j MASQUERADE
    -A POSTROUTING -s 172.18.0.2/32 -d 172.18.0.2/32 -p tcp -m tcp --dport 80 -j MASQUERADE
    -A DOCKER -i br-192821446c9a -j RETURN
    -A DOCKER ! -i br-192821446c9a -p tcp -m tcp --dport 443 -j DNAT --to-destination 172.18.0.2:443
    -A DOCKER ! -i br-192821446c9a -p tcp -m tcp --dport 80 -j DNAT --to-destination 172.18.0.2:80
    

    完整的iptables规则列表

    以下是iptables-save的完整输出:

    # iptables-save
    # Generated by iptables-save v1.4.21 on Tue Nov 28 19:16:31 2017
    *mangle
    :PREROUTING ACCEPT [9063259:7480026035]
    :INPUT ACCEPT [250719:30179859]
    :FORWARD ACCEPT [8795875:7445096680]
    :OUTPUT ACCEPT [1078071:1430559812]
    :POSTROUTING ACCEPT [9842972:8867742437]
    :FORWARD_direct - [0:0]
    :INPUT_direct - [0:0]
    :OUTPUT_direct - [0:0]
    :POSTROUTING_direct - [0:0]
    :PREROUTING_ZONES - [0:0]
    :PREROUTING_ZONES_SOURCE - [0:0]
    :PREROUTING_direct - [0:0]
    :PRE_internal - [0:0]
    :PRE_internal_allow - [0:0]
    :PRE_internal_deny - [0:0]
    :PRE_internal_log - [0:0]
    :PRE_public - [0:0]
    :PRE_public_allow - [0:0]
    :PRE_public_deny - [0:0]
    :PRE_public_log - [0:0]
    -A PREROUTING -j PREROUTING_direct
    -A PREROUTING -j PREROUTING_ZONES_SOURCE
    -A PREROUTING -j PREROUTING_ZONES
    -A INPUT -j INPUT_direct
    -A FORWARD -j FORWARD_direct
    -A OUTPUT -j OUTPUT_direct
    -A POSTROUTING -j POSTROUTING_direct
    -A PREROUTING_ZONES -i enp3s0 -g PRE_public
    -A PREROUTING_ZONES -i virbr0 -g PRE_internal
    -A PREROUTING_ZONES -g PRE_public
    -A PRE_internal -j PRE_internal_log
    -A PRE_internal -j PRE_internal_deny
    -A PRE_internal -j PRE_internal_allow
    -A PRE_public -j PRE_public_log
    -A PRE_public -j PRE_public_deny
    -A PRE_public -j PRE_public_allow
    COMMIT
    # Completed on Tue Nov 28 19:16:31 2017
    # Generated by iptables-save v1.4.21 on Tue Nov 28 19:16:31 2017
    *security
    :INPUT ACCEPT [207361:25027156]
    :FORWARD ACCEPT [8764800:7437165960]
    :OUTPUT ACCEPT [1078077:1430561824]
    :FORWARD_direct - [0:0]
    :INPUT_direct - [0:0]
    :OUTPUT_direct - [0:0]
    -A INPUT -j INPUT_direct
    -A FORWARD -j FORWARD_direct
    -A OUTPUT -j OUTPUT_direct
    COMMIT
    # Completed on Tue Nov 28 19:16:31 2017
    # Generated by iptables-save v1.4.21 on Tue Nov 28 19:16:31 2017
    *raw
    :PREROUTING ACCEPT [9063267:7480026451]
    :OUTPUT ACCEPT [1078080:1430562828]
    :OUTPUT_direct - [0:0]
    :PREROUTING_ZONES - [0:0]
    :PREROUTING_ZONES_SOURCE - [0:0]
    :PREROUTING_direct - [0:0]
    :PRE_internal - [0:0]
    :PRE_internal_allow - [0:0]
    :PRE_internal_deny - [0:0]
    :PRE_internal_log - [0:0]
    :PRE_public - [0:0]
    :PRE_public_allow - [0:0]
    :PRE_public_deny - [0:0]
    :PRE_public_log - [0:0]
    -A PREROUTING -j PREROUTING_direct
    -A PREROUTING -j PREROUTING_ZONES_SOURCE
    -A PREROUTING -j PREROUTING_ZONES
    -A OUTPUT -j OUTPUT_direct
    -A PREROUTING_ZONES -i enp3s0 -g PRE_public
    -A PREROUTING_ZONES -i virbr0 -g PRE_internal
    -A PREROUTING_ZONES -g PRE_public
    -A PRE_internal -j PRE_internal_log
    -A PRE_internal -j PRE_internal_deny
    -A PRE_internal -j PRE_internal_allow
    -A PRE_public -j PRE_public_log
    -A PRE_public -j PRE_public_deny
    -A PRE_public -j PRE_public_allow
    COMMIT
    # Completed on Tue Nov 28 19:16:31 2017
    # Generated by iptables-save v1.4.21 on Tue Nov 28 19:16:31 2017
    *filter
    :INPUT ACCEPT [0:0]
    :FORWARD ACCEPT [0:0]
    :OUTPUT ACCEPT [1078082:1430564354]
    :DOCKER - [0:0]
    :DOCKER-ISOLATION - [0:0]
    :FORWARD_IN_ZONES - [0:0]
    :FORWARD_IN_ZONES_SOURCE - [0:0]
    :FORWARD_OUT_ZONES - [0:0]
    :FORWARD_OUT_ZONES_SOURCE - [0:0]
    :FORWARD_direct - [0:0]
    :FWDI_internal - [0:0]
    :FWDI_internal_allow - [0:0]
    :FWDI_internal_deny - [0:0]
    :FWDI_internal_log - [0:0]
    :FWDI_public - [0:0]
    :FWDI_public_allow - [0:0]
    :FWDI_public_deny - [0:0]
    :FWDI_public_log - [0:0]
    :FWDO_internal - [0:0]
    :FWDO_internal_allow - [0:0]
    :FWDO_internal_deny - [0:0]
    :FWDO_internal_log - [0:0]
    :FWDO_public - [0:0]
    :FWDO_public_allow - [0:0]
    :FWDO_public_deny - [0:0]
    :FWDO_public_log - [0:0]
    :INPUT_ZONES - [0:0]
    :INPUT_ZONES_SOURCE - [0:0]
    :INPUT_direct - [0:0]
    :IN_internal - [0:0]
    :IN_internal_allow - [0:0]
    :IN_internal_deny - [0:0]
    :IN_internal_log - [0:0]
    :IN_public - [0:0]
    :IN_public_allow - [0:0]
    :IN_public_deny - [0:0]
    :IN_public_log - [0:0]
    :OUTPUT_direct - [0:0]
    -A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
    -A INPUT -i lo -j ACCEPT
    -A INPUT -j INPUT_direct
    -A INPUT -j INPUT_ZONES_SOURCE
    -A INPUT -j INPUT_ZONES
    -A INPUT -m conntrack --ctstate INVALID -j DROP
    -A INPUT -j REJECT --reject-with icmp-host-prohibited
    -A FORWARD -j DOCKER-ISOLATION
    -A FORWARD -o br-828c38e3582b -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
    -A FORWARD -o br-828c38e3582b -j DOCKER
    -A FORWARD -i br-828c38e3582b ! -o br-828c38e3582b -j ACCEPT
    -A FORWARD -i br-828c38e3582b -o br-828c38e3582b -j ACCEPT
    -A FORWARD -o br-7cbbdaf3d8fe -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
    -A FORWARD -o br-7cbbdaf3d8fe -j DOCKER
    -A FORWARD -i br-7cbbdaf3d8fe ! -o br-7cbbdaf3d8fe -j ACCEPT
    -A FORWARD -i br-7cbbdaf3d8fe -o br-7cbbdaf3d8fe -j ACCEPT
    -A FORWARD -o br-92f8d769de0b -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
    -A FORWARD -o br-92f8d769de0b -j DOCKER
    -A FORWARD -i br-92f8d769de0b ! -o br-92f8d769de0b -j ACCEPT
    -A FORWARD -i br-92f8d769de0b -o br-92f8d769de0b -j ACCEPT
    -A FORWARD -o docker0 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
    -A FORWARD -o docker0 -j DOCKER
    -A FORWARD -i docker0 ! -o docker0 -j ACCEPT
    -A FORWARD -i docker0 -o docker0 -j ACCEPT
    -A FORWARD -o br-6a38b645b1c7 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
    -A FORWARD -o br-6a38b645b1c7 -j DOCKER
    -A FORWARD -i br-6a38b645b1c7 ! -o br-6a38b645b1c7 -j ACCEPT
    -A FORWARD -i br-6a38b645b1c7 -o br-6a38b645b1c7 -j ACCEPT
    -A FORWARD -o br-2d90be830c58 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
    -A FORWARD -o br-2d90be830c58 -j DOCKER
    -A FORWARD -i br-2d90be830c58 ! -o br-2d90be830c58 -j ACCEPT
    -A FORWARD -i br-2d90be830c58 -o br-2d90be830c58 -j ACCEPT
    -A FORWARD -o br-192821446c9a -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
    -A FORWARD -o br-192821446c9a -j DOCKER
    -A FORWARD -i br-192821446c9a ! -o br-192821446c9a -j ACCEPT
    -A FORWARD -i br-192821446c9a -o br-192821446c9a -j ACCEPT
    -A FORWARD -o br-b61364bf1724 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
    -A FORWARD -o br-b61364bf1724 -j DOCKER
    -A FORWARD -i br-b61364bf1724 ! -o br-b61364bf1724 -j ACCEPT
    -A FORWARD -i br-b61364bf1724 -o br-b61364bf1724 -j ACCEPT
    -A FORWARD -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
    -A FORWARD -i lo -j ACCEPT
    -A FORWARD -j FORWARD_direct
    -A FORWARD -j FORWARD_IN_ZONES_SOURCE
    -A FORWARD -j FORWARD_IN_ZONES
    -A FORWARD -j FORWARD_OUT_ZONES_SOURCE
    -A FORWARD -j FORWARD_OUT_ZONES
    -A FORWARD -m conntrack --ctstate INVALID -j DROP
    -A FORWARD -j REJECT --reject-with icmp-host-prohibited
    -A OUTPUT -j OUTPUT_direct
    -A DOCKER -d 172.18.0.2/32 ! -i br-192821446c9a -o br-192821446c9a -p tcp -m tcp --dport 443 -j ACCEPT
    -A DOCKER -d 172.18.0.2/32 ! -i br-192821446c9a -o br-192821446c9a -p tcp -m tcp --dport 80 -j ACCEPT
    -A DOCKER -d 172.20.0.2/32 ! -i br-2d90be830c58 -o br-2d90be830c58 -p tcp -m tcp --dport 1194 -j ACCEPT
    -A DOCKER-ISOLATION -j RETURN
    -A FORWARD_IN_ZONES -i enp3s0 -g FWDI_public
    -A FORWARD_IN_ZONES -i virbr0 -g FWDI_internal
    -A FORWARD_IN_ZONES -g FWDI_public
    -A FORWARD_OUT_ZONES -o enp3s0 -g FWDO_public
    -A FORWARD_OUT_ZONES -o virbr0 -g FWDO_internal
    -A FORWARD_OUT_ZONES -g FWDO_public
    -A FWDI_internal -j FWDI_internal_log
    -A FWDI_internal -j FWDI_internal_deny
    -A FWDI_internal -j FWDI_internal_allow
    -A FWDI_internal -p icmp -j ACCEPT
    -A FWDI_public -j FWDI_public_log
    -A FWDI_public -j FWDI_public_deny
    -A FWDI_public -j FWDI_public_allow
    -A FWDI_public -p icmp -j ACCEPT
    -A FWDO_internal -j FWDO_internal_log
    -A FWDO_internal -j FWDO_internal_deny
    -A FWDO_internal -j FWDO_internal_allow
    -A FWDO_public -j FWDO_public_log
    -A FWDO_public -j FWDO_public_deny
    -A FWDO_public -j FWDO_public_allow
    -A FWDO_public_allow -m conntrack --ctstate NEW -j ACCEPT
    -A INPUT_ZONES -i enp3s0 -g IN_public
    -A INPUT_ZONES -i virbr0 -g IN_internal
    -A INPUT_ZONES -g IN_public
    -A IN_internal -j IN_internal_log
    -A IN_internal -j IN_internal_deny
    -A IN_internal -j IN_internal_allow
    -A IN_internal -p icmp -j ACCEPT
    -A IN_internal_allow -p tcp -m tcp --dport 22 -m conntrack --ctstate NEW -j ACCEPT
    -A IN_internal_allow -d 224.0.0.251/32 -p udp -m udp --dport 5353 -m conntrack --ctstate NEW -j ACCEPT
    -A IN_internal_allow -p udp -m udp --dport 137 -m conntrack --ctstate NEW -j ACCEPT
    -A IN_internal_allow -p udp -m udp --dport 138 -m conntrack --ctstate NEW -j ACCEPT
    -A IN_internal_allow -p tcp -m tcp --dport 2049 -m conntrack --ctstate NEW -j ACCEPT
    -A IN_internal_allow -p tcp -m tcp --dport 20048 -m conntrack --ctstate NEW -j ACCEPT
    -A IN_internal_allow -p udp -m udp --dport 20048 -m conntrack --ctstate NEW -j ACCEPT
    -A IN_internal_allow -p tcp -m tcp --dport 111 -m conntrack --ctstate NEW -j ACCEPT
    -A IN_internal_allow -p udp -m udp --dport 111 -m conntrack --ctstate NEW -j ACCEPT
    -A IN_internal_allow -p tcp -m tcp --dport 139 -m conntrack --ctstate NEW -j ACCEPT
    -A IN_internal_allow -p tcp -m tcp --dport 445 -m conntrack --ctstate NEW -j ACCEPT
    -A IN_internal_allow -p tcp -m tcp --dport 58846 -m conntrack --ctstate NEW -j ACCEPT
    -A IN_internal_allow -p tcp -m tcp --dport 8112 -m conntrack --ctstate NEW -j ACCEPT
    -A IN_internal_allow -p tcp -m tcp --dport 53 -m conntrack --ctstate NEW -j ACCEPT
    -A IN_internal_allow -p udp -m udp --dport 53 -m conntrack --ctstate NEW -j ACCEPT
    -A IN_public -j IN_public_log
    -A IN_public -j IN_public_deny
    -A IN_public -j IN_public_allow
    -A IN_public -p icmp -j ACCEPT
    -A IN_public_allow -p tcp -m tcp --dport 22 -m conntrack --ctstate NEW -j ACCEPT
    -A IN_public_allow -p udp -m udp --dport 67 -m conntrack --ctstate NEW -j ACCEPT
    -A IN_public_allow -p tcp -m tcp --dport 80 -m conntrack --ctstate NEW -j ACCEPT
    -A IN_public_allow -p tcp -m tcp --dport 443 -m conntrack --ctstate NEW -j ACCEPT
    -A IN_public_allow -p udp -m udp --dport 1194 -m conntrack --ctstate NEW -j ACCEPT
    -A IN_public_allow -p tcp -m tcp --dport 1195 -m conntrack --ctstate NEW -j ACCEPT
    COMMIT
    # Completed on Tue Nov 28 19:16:31 2017
    # Generated by iptables-save v1.4.21 on Tue Nov 28 19:16:31 2017
    *nat
    :PREROUTING ACCEPT [118631:13941821]
    :INPUT ACCEPT [6147:464301]
    :OUTPUT ACCEPT [18836:1989867]
    :POSTROUTING ACCEPT [2593:197858]
    :DOCKER - [0:0]
    :OUTPUT_direct - [0:0]
    :POSTROUTING_ZONES - [0:0]
    :POSTROUTING_ZONES_SOURCE - [0:0]
    :POSTROUTING_direct - [0:0]
    :POST_internal - [0:0]
    :POST_internal_allow - [0:0]
    :POST_internal_deny - [0:0]
    :POST_internal_log - [0:0]
    :POST_public - [0:0]
    :POST_public_allow - [0:0]
    :POST_public_deny - [0:0]
    :POST_public_log - [0:0]
    :PREROUTING_ZONES - [0:0]
    :PREROUTING_ZONES_SOURCE - [0:0]
    :PREROUTING_direct - [0:0]
    :PRE_internal - [0:0]
    :PRE_internal_allow - [0:0]
    :PRE_internal_deny - [0:0]
    :PRE_internal_log - [0:0]
    :PRE_public - [0:0]
    :PRE_public_allow - [0:0]
    :PRE_public_deny - [0:0]
    :PRE_public_log - [0:0]
    -A PREROUTING -j PREROUTING_direct
    -A PREROUTING -j PREROUTING_ZONES_SOURCE
    -A PREROUTING -j PREROUTING_ZONES
    -A PREROUTING -m addrtype --dst-type LOCAL -j DOCKER
    -A OUTPUT -j OUTPUT_direct
    -A OUTPUT ! -d 127.0.0.0/8 -m addrtype --dst-type LOCAL -j DOCKER
    -A POSTROUTING -s 172.101.0.0/24 ! -o br-828c38e3582b -j MASQUERADE
    -A POSTROUTING -s 172.102.0.0/24 ! -o br-7cbbdaf3d8fe -j MASQUERADE
    -A POSTROUTING -s 172.101.0.0/24 ! -o br-92f8d769de0b -j MASQUERADE
    -A POSTROUTING -s 172.17.0.0/16 ! -o docker0 -j MASQUERADE
    -A POSTROUTING -s 172.102.0.0/24 ! -o br-6a38b645b1c7 -j MASQUERADE
    -A POSTROUTING -s 172.20.0.0/16 ! -o br-2d90be830c58 -j MASQUERADE
    -A POSTROUTING -s 172.18.0.0/16 ! -o br-192821446c9a -j MASQUERADE
    -A POSTROUTING -s 172.19.0.0/16 ! -o br-b61364bf1724 -j MASQUERADE
    -A POSTROUTING -j POSTROUTING_direct
    -A POSTROUTING -j POSTROUTING_ZONES_SOURCE
    -A POSTROUTING -j POSTROUTING_ZONES
    -A POSTROUTING -s 172.18.0.2/32 -d 172.18.0.2/32 -p tcp -m tcp --dport 443 -j MASQUERADE
    -A POSTROUTING -s 172.18.0.2/32 -d 172.18.0.2/32 -p tcp -m tcp --dport 80 -j MASQUERADE
    -A POSTROUTING -s 172.20.0.2/32 -d 172.20.0.2/32 -p tcp -m tcp --dport 1194 -j MASQUERADE
    -A DOCKER -i br-828c38e3582b -j RETURN
    -A DOCKER -i br-7cbbdaf3d8fe -j RETURN
    -A DOCKER -i br-92f8d769de0b -j RETURN
    -A DOCKER -i docker0 -j RETURN
    -A DOCKER -i br-6a38b645b1c7 -j RETURN
    -A DOCKER -i br-2d90be830c58 -j RETURN
    -A DOCKER -i br-192821446c9a -j RETURN
    -A DOCKER -i br-b61364bf1724 -j RETURN
    -A DOCKER ! -i br-192821446c9a -p tcp -m tcp --dport 443 -j DNAT --to-destination 172.18.0.2:443
    -A DOCKER ! -i br-192821446c9a -p tcp -m tcp --dport 80 -j DNAT --to-destination 172.18.0.2:80
    -A DOCKER ! -i br-2d90be830c58 -p tcp -m tcp --dport 1195 -j DNAT --to-destination 172.20.0.2:1194
    -A POSTROUTING_ZONES -o enp3s0 -g POST_public
    -A POSTROUTING_ZONES -o virbr0 -g POST_internal
    -A POSTROUTING_ZONES -g POST_public
    -A POST_internal -j POST_internal_log
    -A POST_internal -j POST_internal_deny
    -A POST_internal -j POST_internal_allow
    -A POST_public -j POST_public_log
    -A POST_public -j POST_public_deny
    -A POST_public -j POST_public_allow
    -A POST_public_allow ! -o lo -j MASQUERADE
    -A PREROUTING_ZONES -i enp3s0 -g PRE_public
    -A PREROUTING_ZONES -i virbr0 -g PRE_internal
    -A PREROUTING_ZONES -g PRE_public
    -A PRE_internal -j PRE_internal_log
    -A PRE_internal -j PRE_internal_deny
    -A PRE_internal -j PRE_internal_allow
    -A PRE_public -j PRE_public_log
    -A PRE_public -j PRE_public_deny
    -A PRE_public -j PRE_public_allow
    COMMIT
    # Completed on Tue Nov 28 19:16:31 2017
    

    1
    172.18.0.1 是一个真实的IP地址。什么是虚假的IP地址,为什么会是虚假的IP地址? - Ron Maupin
    8
    172.18.0.1 是虚拟 Docker 网络网关的 IP 地址。当一个具有 IP 地址(例如 111.222.111.222)的用户连接时,应该将其地址识别为 111.222.111.222,而不是 172.18.0.1(这实际上曾经发生过)。如我在下面回答的那样,这是由于伪装真实 IP 导致的。简单说,iptables 认为从我的外部接口(比如说 1.2.3.4)发来的数据包要去往另一个外部接口(实际上是本地 Docker 虚拟接口),其中的 IP 应该被接口的 IP(172.18.0.1)所替换。 - ololoepepe
    我的观点是172.18.0.1是一个真实的IP地址。这种点分十进制表示法可以被正确地转换为32位IPv4地址。它可以作为IP数据包中的源地址或目标地址出现,并且是可转发的地址。人们随意提到“真实IP地址”之类的短语,但我不明白。如果IP地址不是真实的,其八位组中会有一个大于255(如300.298.407.33)的数字,无法正确转换为32位IPv4地址。 - Ron Maupin
    9
    我理解你的观点,但那更多是术语问题,而不是实际意义。如果您查看https://github.com/jwilder/nginx-proxy/issues/130和https://github.com/jwilder/nginx-proxy/issues/133, 您会发现人们习惯称我们正在谈论的那个东西为“真实IP地址”。无论如何,这与主题无关,既不能澄清任何问题,也不能带来解决方案。编辑:互联网上有这样的网站:http://www.whatsmyrealip.com/,因此我认为我对“真实IP”的理解相当普遍。 - ololoepepe
    我并没有回答问题,而是在澄清术语,这就是为什么我将其作为评论而不是答案的原因。不准确的术语会导致错误。事实上,“172.18.0.1”是一个完全真实的IPv4地址,暗示它不是真实的是不准确和误导性的。 - Ron Maupin
    3个回答

    17

    最终,我回答了自己的问题。

    经过一些研究,我发现是IP伪装导致Docker错误地识别客户端地址。

    原因

    在我的情况下,firewalld被配置为与本地网络中的其他机器共享互联网连接。这是通过将外部接口(enp3s0)的区域设置为public,将本地接口(enp1s0enp2s0)的区域设置为internal,并启用出站数据包的IP伪装来实现的。

    就是这样。伪装也适用于从public网络到docker网络的数据包,就好像该数据包要发送到(另一个)外部接口一样。

    解决方案

    据我所知,基于iptables和Docker的所有内容,有一种可接受的解决方法:将Docker创建的所有虚拟网络接口添加到internal区域,以便不将伪装规则应用于发往相应网络的数据包。例如:

    # firewall-cmd --permanent --zone=internal --change-interface=br-192821446c9a
    
    为使解决方案具有持久性,需要在/etc/sysconfig/network-scripts目录中创建相应的脚本。例如,对于br-192821446c9a接口,应创建一个名为/etc/sysconfig/network-scripts/ifcfg-br-192821446c9a的文件,并包含以下内容:
    DEVICE=br-192821446c9a
    TYPE=Bridge
    BOOTPROTO=none
    IPADDR=172.18.0.1
    PREFIX=16
    DEFROUTE=yes
    IPV4_DNS_PRIORITY=100
    NAME=br-192821446c9a
    ONBOOT=no
    ZONE=internal
    

    希望这个回答能够节省某人的时间。


    4
    你有没有在Windows上解决这个问题的办法? - Jeroen
    @ololoepepe 很棒的解决方案!你能详细说明一下这个“br-192821446c9a”名称是从哪里来的吗? - Kevin Danikowski
    1
    @KevinDanikowski 这些接口是由Docker生成的。您可以使用ifconfig命令列出所有接口。 - ololoepepe

    0

    我遇到了同样的问题,并尝试了@ololoepepe在此线程中提供的答案。但它并没有解决我的Synology NAS上的问题。

    唯一对我有效的解决方案可以在这篇博客文章中找到:

    iptables -t nat -N DOCKER
    iptables -t nat -A PREROUTING -m addrtype --dst-type LOCAL -j DOCKER
    iptables -t nat -A PREROUTING -m addrtype --dst-type LOCAL ! --dst 127.0.0.0/8 -j DOCKER
    

    还与以下内容相关: https://stackoverflow.com/a/62100821/869402

    -1

    要在单个节点上执行此操作,您需要添加

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

    重要的部分是 mode: host,其次重要的事情是... 在 Linux 客户端上使用它,似乎无法从 Windows 上工作。

    这有一个限制,即它不会在任何其他节点中公开端口。


    1
    这可能会引起更多问题,而不是解决它们。 - ololoepepe

    网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接