NGINX 双代理不允许 websocket 连接

NGINX 双代理不允许 websocket 连接

我的机器上设置了两个 nginx 代理,一个用于解包 SSL,另一个用于执行特定于应用程序的代理(只有第二个是版本控制的)。当我只有一个代理时,我能够成功建立 websocket 连接,但移动到两个代理后,所有 websocket 升级请求都会响应 502 Bad Gateway 错误。我可以确认正常的 http/https 请求在我的双代理设置下可以正常工作。这是我当前的配置。

代理 1

server {

        # SSL configuration
        #
        # listen 443 ssl default_server;
        # listen [::]:443 ssl default_server;
        #
        # Note: You should disable gzip for SSL traffic.
        # See: https://bugs.debian.org/773332
        #
        # Read up on ssl_ciphers to ensure a secure configuration.
        # See: https://bugs.debian.org/765782
        #
        # Self signed certs generated by the ssl-cert package
        # Don't use them in a production server!
        #
        # include snippets/snakeoil.conf;

        server_name staging.ambitx.io;

        location / {
                proxy_pass http://127.0.0.1:81;
                include proxy_params;
        }

    listen [::]:443 ssl ipv6only=on; # managed by Certbot
    listen 443 ssl; # managed by Certbot
    ssl_certificate /etc/letsencrypt/live/staging.ambitx.io/fullchain.pem; # managed by Certbot
    ssl_certificate_key /etc/letsencrypt/live/staging.ambitx.io/privkey.pem; # managed by Certbot
    include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot

}
server {
    if ($host = staging.ambitx.io) {
        return 301 https://$host$request_uri;
    } # managed by Certbot

        listen 80 default_server;
        listen [::]:80 default_server;

        server_name staging.ambitx.io;
    return 404; # managed by Certbot

}

代理参数

proxy_set_header Host $http_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;

代理 2

(在docker上运行,主机上的端口81绑定到容器上的端口80)

resolver 127.0.0.11 ipv6=off;

server {
  listen       80;
  listen  [::]:80;

  location / {
    root /var/www/staticfiles;
    index  index.html index.htm;
    try_files $uri /index.html =404;
  }
  
  location /ws {
    access_log off;

    proxy_pass       http://wsserver;

    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
  }

  location /api {
    proxy_pass http://apiserver;
  }
}

location /ws我最初在代理 2 的配置块中有下面的语句......

proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

但我删除了它们,因为它们会覆盖代理 1 设置的标头。

有什么想法吗?如果您需要更多信息,请告诉我。

答案1

当然,你不应该放弃任何中间代理服务器对 WebSocket 代理的支持。WebSocket 代理是一种非常特殊任务,为了允许协议切换并保持 WebSocket 连接建立并处于活动状态,您还应该将其支持返回到您的第一个 nginx 代理:

...
location / {
    proxy_pass http://127.0.0.1:81;
    include proxy_params;
}
location /ws {
    proxy_pass http://127.0.0.1:81;
    include proxy_params;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
}
...

从第二个 nginx 代理中删除所有三个proxy_set_header指令也是一个坏主意。虽然X-Real-IPX-Forwarded-For标头将完全按照第一个代理的设置传递给您的 WebSocket 应用程序,但Host标头是一个特殊标头。除非明确设置,否则它将被传递到指令中使用的上游名称proxy_pass,即Host: wsserver。正如您可以从proxy_set_header指令中读到的那样文档

默认情况下,仅重新定义两个字段:

proxy_set_header Host $proxy_host;
proxy_set_header Connection close;

(第二种方法也肯定会破坏任何建立 WebSocket 连接的尝试)。因此,要保留Host来自客户端请求的原始标头(通常是一个好主意,您可以阅读有关此标头的更多信息这里),返回

proxy_pass Host $http_host;

location / { ... }和添加到location /ws { ... }你的第二个 nginx 代理配置的行。

相关内容