如何配置反向代理以在不同端口上支持 WSS?

如何配置反向代理以在不同端口上支持 WSS?

我正在使用 vaultwarden docker 容器,它基本上需要反向代理来提供 SSL。

该容器为 Websockets 运行单独的 Web 服务器,因为 Rust 的 rocket 不支持同一端口上的 Web 套接字。

VaultWarden 的说明如下:

  • 将 /notifications/hub 端点路由到 WebSocket 服务器,默认端口为 3012,确保传递 Connection 和 Upgrade 标头
  • 将其他所有内容(包括 /notifications/hub/negotiate)路由到标准 Rocket 服务器,默认端口为 80

我该如何配置我的 nginx 反向代理来支持此设置?

我的配置如下:

docker-compose.yml

version: '3'
services:
    vaultwarden:
      image: vaultwarden/server:1.25.2
      volumes:
        - /srv/vaultwarden/vaultwarden:/data/
      restart: always
      environment:
        - WEBSOCKET_ENABLED=true

    nginx:
      image: nginx:1.23.1
      volumes:
        - /srv/vaultwarden/nginx/templates:/etc/nginx/templates
        - /srv/vaultwarden/nginx/ssl:/etc/nginx/ssl
      ports:
        - "443:443"
      environment:
        - NGINX_PORT=443

nginx的:

server {
    listen       ${NGINX_PORT} ssl http2 default;
    server_name  _;

    # SSL
    ssl_certificate /etc/nginx/ssl/server.crt;
    ssl_certificate_key /etc/nginx/ssl/server.key;

    # Web sockets
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";

    proxy_set_header Host $host;
    proxy_set_header X-Forwarded-Host $host;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

    location / {
        proxy_pass http://vaultwarden;
    }
}

我可以做:

  • 直接在 vaultwarden 容器上公开端口 3012?
    • 那么 nginx 配置是什么样的?
  • 在 nginx 容器上公开端口 3012,并通过 proxy_passing 将其传递到 vaultwarden 容器?
    • 那会是什么样子的?

答案1

经过一番挖掘,我发现了以下内容:

如果您将WEBSOCKET_ENABLED=true环境变量传递给 vaultwarden 容器(如我在上面的docker-compose.yml文件中所做的那样),则容器将启动 2 个服务器:

  1. 端口 80 上的 Web 服务器
  2. 端口 3012 上的 Websocket 服务器

客户端上没有任何东西表明要连接到端口 3012。客户端尝试在上设置 websocket /notifications/hub。与常规 Web 服务器的端口相同。

您无需在docker-compose.yml文件中公开任何容器上的 3012 端口。您只需要在 nginx 配置文件中进行以下操作:

location = /notifications/hub {
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "Upgrade";
    proxy_set_header Host $host;

    proxy_pass http://vaultwarden:3012;
}

这将透明地让 nginx 将所有请求重定向到/notifications/hubvaultwarden 容器上的端口 3012。

由于 nginx 和 vaultwarden 都在同一个docker-compose.yml文件中,因此它们位于同一个内部网络中,并且 nginx 容器已经可以访问 vaultwarden 容器上的所有端口。您无需在任何地方允许此端口。

客户端不知道 Web 套接字内部使用的是不同的端口。端口转换全部在服务器端进行。

答案2

我建议在 nginx 中公开端口 3012:

    nginx:
      image: nginx:1.23.1
      volumes:
        - /srv/vaultwarden/nginx/templates:/etc/nginx/templates
        - /srv/vaultwarden/nginx/ssl:/etc/nginx/ssl
      ports:
        - "443:443"
        - "3012:3012"
      environment:
        - NGINX_PORT=443

nginx 上 WebSockets 的代理传递可能有点棘手。我曾经很难正确设置它(请参阅这个帖子)——我还在那里为 WebSockets 自定义了一个 URL/端点。

通常,WS 代理的工作方式有以下几种:(1) 您有用于 WebSocket 连接的自定义端点,或 (2) WS 通过根/,但使用的端口与 HTTP 不同,或 (3) 它的工作方式更像 socket.io (即,每个端点/URL 也是 WS 连接的单独端点)。文档中写道:

将 /notifications/hub 端点路由到 WebSocket 服务器,默认端口为 3012,确保传递 Connection 和 Upgrade 标头

将其他所有内容(包括 /notifications/hub/negotiate)路由到标准 Rocket 服务器,默认端口为 80

因此我猜测 nginx 配置中应该是这样的:

       # WebSocket support
       location ~ ^/notifications/hub/ {
           proxy_pass http://vaultwarden:3012;
           proxy_http_version 1.1;
           proxy_set_header Upgrade $http_upgrade;
           proxy_set_header Connection "Upgrade";
           proxy_set_header Host $host;
       }

       # HTTP proxy
       location / {
           proxy_pass http://vaultwarden;
       }

但它需要一些测试。

我希望这能对你有所帮助。

相关内容