【问题标题】:ipv4 https request not forwarded to docker containeripv4 https 请求未转发到 docker 容器
【发布时间】:2019-02-10 06:45:12
【问题描述】:

Docker 和我的 ovh 服务器 (ubuntu xenial) 有一个烦人的问题。 我在我的服务器上运行 NGINX 官方 docker 映像 (15.x),并将一些端口从我的服务器转发到我的 docker 映像(以在线托管服务器服务)。

所有从外部完成的 HTTP 请求(使用 IPV4 或 IPV6)都设法到达 NGINX。 但是,使用 IPV4 完成的 HTTPS 请求无法到达 NGINX(IPV6 HTPPS 就像一个魅力)。

我使用 tcdump tcpdump -i any port 443 -s0 -n 在我的服务器和 NGINX docker 容器中监听了端口 443

结果:我在我的服务器和 NGINX 容器中都看到了 IPV6 HTTPS 请求。 我只在我的服务器上看到了 IPV4 https 请求,但在 NGINX 容器中没有。 => 看来,这不是“开放端口”问题,因为我设法在我的服务器上看到了 IPV4 请求(我检查了 IPTables,443 被转发到 docker 代理)。 我认为这是我的服务器和 Docker 代理之间的端口转发 pb,仅适用于使用 IPV6 完成的 HTTPS 请求。

这是我的容器配置:

nginx:
depends_on:
  - my_php7
image: nginx:latest
volumes:
  - "../:/usr/share/nginx/html:rw"
  - "./nginx/var/log:/var/log/nginx:rw"
  - "./nginx/nginx.template.conf:/etc/nginx/conf.d/nginx.template:rw"
  - "./nginx/sites-available:/etc/nginx/sites-available:rw"
  - "./nginx/sites-enabled:/etc/nginx/sites-enabled:rw"
links:
  - my_php7:webstack_php
ports:
  - "8080:8080"
  - "8090:90"
  - "8091:91"
  - "8083:8083"
  - "80:80"
  - "443:443"
restart: always
command: /bin/bash -c "cp /etc/nginx/conf.d/nginx.template /etc/nginx/conf.d/nginx.conf && nginx -c /etc/nginx/conf.d/nginx.conf"

我还检查了 net.ipv6.bindv6only:
#> sysctl net.ipv6.bindv6only net.ipv6.bindv6only = 0

这是我的 nat 信息:

Proto Recv-Q Send-Q Adresse locale          Adresse distante        Etat       PID/Program name
tcp        0      0 0.0.0.0:8081            0.0.0.0:*               LISTEN      19671/node
tcp        0      0 91.121.101.165:914      0.0.0.0:*               LISTEN      1696/openvpn-openss
tcp        0      0 91.121.101.165:915      0.0.0.0:*               LISTEN      1724/openvpn-openss
tcp        0      0 0.0.0.0:8084            0.0.0.0:*               LISTEN      22633/node
tcp        0      0 91.121.101.165:916      0.0.0.0:*               LISTEN      1751/openvpn-openss
tcp        0      0 91.121.101.165:917      0.0.0.0:*               LISTEN      1779/openvpn-openss
tcp        0      0 127.0.0.1:53            0.0.0.0:*               LISTEN      929/named
tcp        0      0 0.0.0.0:21              0.0.0.0:*               LISTEN      947/vsftpd
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      943/sshd
tcp        0      0 127.0.0.1:953           0.0.0.0:*               LISTEN      929/named
tcp        0      0 127.0.0.1:4040          0.0.0.0:*               LISTEN      4765/ngrok
tcp6       0      0 :::8082                 :::*                    LISTEN      12095/docker-proxy
tcp6       0      0 :::8083                 :::*                    LISTEN      12837/docker-proxy
tcp6       0      0 :::2003                 :::*                    LISTEN      12058/docker-proxy
tcp6       0      0 :::9300                 :::*                    LISTEN      12006/docker-proxy
tcp6       0      0 :::85                   :::*                    LISTEN      12070/docker-proxy
tcp6       0      0 ::1:53                  :::*                    LISTEN      929/named
tcp6       0      0 :::22                   :::*                    LISTEN      943/sshd
tcp6       0      0 :::3000                 :::*                    LISTEN      12544/docker-proxy
tcp6       0      0 ::1:953                 :::*                    LISTEN      929/named
tcp6       0      0 :::8090                 :::*                    LISTEN      12861/docker-proxy
tcp6       0      0 :::443                  :::*                    LISTEN      12885/docker-proxy
tcp6       0      0 :::8091                 :::*                    LISTEN      12849/docker-proxy
tcp6       0      0 :::92                   :::*                    LISTEN      12082/docker-proxy
tcp6       0      0 :::4000                 :::*                    LISTEN      12532/docker-proxy
tcp6       0      0 :::9000                 :::*                    LISTEN      12521/docker-proxy
tcp6       0      0 :::5000                 :::*                    LISTEN      12106/docker-proxy
tcp6       0      0 :::3306                 :::*                    LISTEN      12119/docker-proxy
tcp6       0      0 :::80                   :::*                    LISTEN      12897/docker-proxy
tcp6       0      0 :::8080                 :::*                    LISTEN      12873/docker-proxy
tcp6       0      0 :::9200                 :::*                    LISTEN      12035/docker-proxy
tcp6       0      0 :::4400                 :::*                    LISTEN      28319/node
udp6    3072      0 :::40195                :::*                                1081/collectd
udp6       0      0 :::8124                 :::*                                12046/docker-proxy
udp6       0      0 ::1:53                  :::*                                929/named
udp6       0      0 ff18::efc0:4a42:25826   :::*                                1081/collectd

对于那些想知道为什么 443 只显示 IPV6 转发的人:

在linux上,默认情况下net.ipv6.bindv6only是0,所以ipv4包可以 也可以从具有 ipv4 映射的 ipv6 地址的 ipv6 套接字接收。因此 您只需要监听 tcp6 套接字,我们可以同时支持 ipv4 和 ipv6。

如果你想明确地只监听 ipv4 端口,你将不得不使用 net.Listen("tcp4", "0.0.0.0:3000") 然后将监听器传递给 http.Serve。

我尝试重建容器但没有成功。 我还尝试在另一个 docker 中打开 443 端口 => 它无法获取 IPV4 HTTPS 请求。

继续:

  • 所有 HTTP 请求 (IPV4/IPV6) 都有效

  • 只有 IPV6 HTTPS 有效,IPV4 似乎没有被转发到 Docker

  • IPtables、Docker conf 和 net stats 都可以。

有什么想法吗? :)

[编辑]

@leodotcloud

确定在这里(我用xxxx隐藏了服务器名称)

虚拟主机配置

server {
    listen 443 ssl http2;

    server_name www.xxx.com;

    error_log /var/log/nginx/error.log;
    access_log /var/log/nginx/access.log;

   ssl_certificate    /etc/letsencrypt/live/xxx.com/fullchain.pem;
   ssl_certificate_key  /etc/letsencrypt/live/xxxx.com/privkey.pem;
   ssl_ciphers ECDHE-RSA-AES256-GCM-SHA512:DHE-RSA-AES256-GCM-SHA512:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-SHA384;
   ssl_session_timeout  10m;
   ssl_session_cache shared:SSL:10m;
   ssl_prefer_server_ciphers on;

    charset utf-8;

    location / {
        proxy_pass http://node;
        proxy_set_header X-Real-IP  $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $host;
    }

} 

SSL 的 nginx 配置

http {
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;

    ##
    # SSL Settings
    ##

    ssl_protocols TLSv1 TLSv1.1 TLSv1.2; # Dropping SSLv3, ref: POODLE

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

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

    sendfile        on;
    #tcp_nopush     on;

    keepalive_timeout  65;

....

}

[编辑 2] 我试图将我的 docker-compose 配置从“443:443”更改为“0.0.0.0:443:443”以强制 ipv4 绑定。

我收到了这个错误:Bind for 0.0.0.0:443 failed: port is already allocated

所以我有一些东西在 443 上使用我的 IPV4 连接。

当我使用“443:443”语法绑定IPV6和IPV4时,docker绑定IPV6但不检查IPV4(可能是系统也关心绑定IPV4)。

现在我必须找到这项服务。问题:我使用 netstat 无处可寻。有没有办法强制关闭套接字?

[编辑] 我尝试停止容器并直接在服务器上启动 nginx,绑定 443 +SSL IPV4/IPV6 并提供“hello”文件。 => IPV6 有效,IPV4 无效 => 我将端口从 443 更改为 444 => IPV4 和 IPV6 工作 => 我清除了 IPTABLE 并在所有内容上配置了 ACCEPT => IPV4 443 仍然存在同样的问题 :(

因为 Nginx 设法在 0.0.0.0:443 上绑定,我想套接字是“免费的”。所以有些东西正在阻止或过滤从 IPV4 443 传入的数据

[编辑] 最后这是一个 IPTABLE 问题。我将我的答案标记为在 IPV4 中重新打开端口 443 的解决方案。我将在我的 NAT 表中查找导致此问题的规则,如果需要,我将打开一个新主题。 感谢大家的帮助!

【问题讨论】:

  • 你能分享一下与 SSL/https 相关的 nginx 配置的相关部分吗?这些方面的内容:nginx.org/en/docs/http/configuring_https_servers.html
  • 我用 nginx conf 更新了我的帖子。但似乎有些东西只在 IPV4 上收听......我必须找到哪一个 :(
  • 端口 443 已被使用,容器是否已使用之前的 compose 文件启动?您是否有机会删除所有容器并检查 netstat?然后用 0.0.0.0:443:443 启动容器?由于在主机上看到了请求数据包,我将继续调试主机设置。你检查net.bridge.bridge-nf-call-iptables了吗?
  • 是的。我做了一个新测试(参见我的新编辑)=> 我停止了所有容器,并且在 443 上没有显示任何连接。我尝试在 docker 文件之外直接配置 NGINX 服务器 => 同样的问题.. sysctl net.bridge.bridge-nf-call-iptables = > net.bridge.bridge-nf-call-iptables = 1我什至尝试清除我的IPtable,我真的不明白发生了什么:(

标签: docker nginx


【解决方案1】:

我终于找到了让它工作的方法。只需 FLUSHED nat 使用以下命令:

iptables -t nat -F

现在一切正常。 :)

我不太明白这个命令的作用。它刷新了NAT 规则,但我看不出我的IPTABLE 有什么不同。

如果有人能告诉我这个“刷新”是否有风险(我从未更改过 IPTABLE 中的某些内容,只有 docker 更改它)。

【讨论】:

  • flush 删除该特定表 (nat) 中的所有规则。
  • 好的,谢谢您的解释。我会查看我的 nat 表,看看是否有什么东西会阻塞我的 443 端口。
  • 对我来说这很有帮助,因为(在刷新之前)我正在使用/etc/docker/daemon.json ipv6 设置,并且需要刷新才能正确地重新创建路由规则。重要提示:仅仅重启 docker 是不够的
  • 哇!无论如何,我无法达到这个解决方案。这解决了我的问题谢谢!!!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-02-07
  • 2020-02-23
  • 2017-03-18
  • 2016-05-19
  • 1970-01-01
  • 2013-12-09
  • 1970-01-01
相关资源
最近更新 更多