我的机器上设置了两个 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-IP
和X-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 代理配置的行。