Docker NGINX代理无法转发Websockets

11

NGINX代理将HTTP GET请求传递给我的Django应用程序,而不是WebSocket握手。

事实:

  • 除websocket代理外,其余的django应用程序代理工作得非常好。
  • 如果直接连接到django应用程序容器,则可以使WebSockets正常工作。(下面是相关的日志条目。)
  • nginx配置在我的开发机(未经容器化处理)上本地主机上运行良好。(以下是日志示例。)

相关日志:

通过容器化的NGINX代理连接时的Daphne日志:

`xxx.xxx.xxx.xxx:40214 - - [24/May/2017:19:16:03] "GET /flight/all_flight_updates" 404 99`

当绕过容器化代理直接连接服务器时,Daphne会记录日志:

xxx.xxx.xxx.xxx:6566 - - [24/May/2017:19:17:02] "WSCONNECTING /flight/all_flight_updates" - -
xxx.xxx.xxx.xxx:6566 - - [24/May/2017:19:17:02] "WSCONNECT /flight/all_flight_updates" - -

本地测试nginx(非容器化)配置可行:

[2017/05/24 14:24:19] WebSocket HANDSHAKING /flight/all_flight_updates [127.0.0.1:65100]
[2017/05/24 14:24:19] WebSocket CONNECT /flight/all_flight_updates [127.0.0.1:65100]

配置文件:

我的 docker-compose.yml 文件:

version: '3'
services:
  db:
    image: postgres
  redis:
    image: redis:alpine
  web:
    image: nginx
    ports:
     - '80:80'
    volumes:
     - ./deploy/proxy.template:/etc/nginx/conf.d/proxy.template
    links:
     - cdn
     - app
    command: /bin/bash -c "envsubst '' < /etc/nginx/conf.d/proxy.template > /etc/nginx/conf.d/default.conf && nginx -g 'daemon off;'"
  cdn:
    image: nginx
    volumes:
     - ./cdn_static:/usr/share/nginx/static
     - ./deploy/cdn.template:/etc/nginx/conf.d/cdn.template
    command: /bin/bash -c "envsubst '' < /etc/nginx/conf.d/cdn.template > /etc/nginx/conf.d/default.conf && nginx -g 'daemon off;'"
  app:
    build: .
    image: app
    ports:
     - '8000:8000'
    links:
     - redis
     - db
    volumes:
     - ./cdn_static:/var/static

这是我的proxy.template NGINX配置模板:

  upstream cdn_proxy {
    server cdn:80;
  }

  upstream daphne {
    server app:8000;
    keepalive 100;
  }

  map $http_upgrade $connection_upgrade {
      default upgrade;
      ''      close;
  }

  server {
    location /static {
      proxy_pass http://cdn_proxy;
    }

    location / {
      proxy_buffering off;
      proxy_pass http://daphne;
      proxy_read_timeout     300;
      proxy_connect_timeout  300;

      proxy_http_version 1.1;
      proxy_set_header Upgrade $http_upgrade;
      proxy_set_header Connection $connection_upgrade;

      proxy_redirect     off;
      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-Host $server_name;

    }
  }

更新

我已经使用NGINX网站上的教程构建了一个更紧凑的问题示例,并将其放在github上,地址为https://github.com/c0yote/nginx-websocket-issue

你会得到一个426而不是404错误,但我认为这是因为简单服务器不知道如何处理NGINX发送的GET请求。从浏览器直接对8000端口发出GET请求(例如)时,你会得到相同的426错误,这也加强了我的想法。

因此,核心问题仍然是NGINX正在发送GET请求。

更多信息:

tcpdump显示websocket服务器的GET请求具有Upgrade字段,但针对NGINX的GET请求却没有。这很令人困惑,因为wscat命令除了目标端口以外完全相同。

巨大的更新:

如果我将NGINX代理从80端口改为8080端口,则可以正常工作。我的唯一猜测是js客户端对80端口做出了某些假设。如果有人知道原因,请告诉我。


在运行envsubst之后,您能否从容器中输出/etc/nginx/conf.d/default.conf文件? - Andy Shinn
我通过在正在运行的容器上执行 docker exec 到 bash 来检查它,并且它是完全相同的。 - Präriewolf
你的 Github 链接显示 404。 - Souradeep Nanda
1个回答

1

这是我的组织的防火墙。

它将端口80上GET请求头中的连接升级去除。当我改用其他端口时,它就正常工作了。


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