我正在尝试为 Web 应用程序(特别是 JupyterLab,但这个问题是通用的)编写 Nginx 反向代理配置。
Web 应用程序在多个不相交的 URL 层次结构中使用多个 WebSockets 端点。例如,
/jupyter/api/yjs/...
/jupyter/terminals/...
/jupyter/api/collaboration/room/...
- (和别的)
都是 WebSockets 端点。我写了一个临时配置,如下所示:
location /jupyter/ {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Host $host;
client_max_body_size 0;
proxy_pass http://jupyter;
}
location ~ ^/jupyter/api/yjs/ {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Host $host;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
proxy_pass http://jupyter;
}
<repeated sections for other WebSockets endpoints>
但是,完整的 WebSockets 端点列表并没有记录下来。我尝试分析 nginx 和应用程序日志,推断哪些 URL 需要代理为 WebSockets,但这显然不可靠。
有没有办法编写一个 nginx 配置,以便将所有传入的 WebSocket 请求代理为 WebSockets,并将纯 HTTP 请求代理为纯 HTTP,无需在 nginx 配置中对 WebSockets 位置进行硬编码?
答案1
答案2
这可以通过使用映射变量和一些有关 WebSocket 的知识来实现。
WebSocket 连接是使用带有两个标头的 HTTP 1.1 请求发起的:Connection: Upgrade
和Upgrade: WebSocket
,两者都是逐跳的(因此通常不使用代理)。
我们只需在后端连接上启用 HTTP 1.1,并使用和proxy_http_version 1.1
代理两个标头。但是,我们仍需要在常规(非 WebSocket)请求上提供,以与 NGINX 默认值保持一致。因此:proxy_set_header Connection $http_connection
proxy_set_header Upgrade $http_upgrade
Connection: close
# in http context
map $http_upgrade $proxy_connection {
'' 'close';
default 'upgrade';
}
<...>
# in server context
location /jupyter/ {
# WebSocket support
proxy_http_version 1.1;
proxy_set_header Connection $proxy_connection;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Host $host;
client_max_body_size 0;
proxy_pass http://jupyter;
}