Nginx WSS(端口443)到WS(端口80)重写包含正则表达式URL的规则

发布于 2025-01-11 03:53:15 字数 5002 浏览 0 评论 0原文

Apache

我在 Apache Web 代理服务器配置中有以下 RewriteRule :(

<IfModule mod_ssl.c>
<VirtualHost *:443>
        ServerName myserver.example.com
        ServerAdmin [email protected]
 
        # Rewrite rule for the WebSocket connection
        RewriteEngine On
        RewriteCond %{REQUEST_URI}  ^/[0-9]+/ws/graph/            [NC]
        RewriteRule /(.*)           ws://localhost:8000/$1 [P,L]
 
        # Logs for connections at port 443 (HTTPS/WSS)
        ErrorLog ${APACHE_LOG_DIR}/myserver.example.com-SSL-error.log
        CustomLog ${APACHE_LOG_DIR}/myserver.example.com-SSL-access.log combined
 
        # HTTPS => HTTP redirect for requests to the application
        ProxyPass / http://localhost:8000/
        ProxyPassReverse / http://localhost:8000/
 
        # Alias and certificate configuration
        ServerAlias myserver.example.com
        SSLCertificateFile /etc/letsencrypt/live/myserver.example.com/fullchain.pem
        SSLCertificateKeyFile /etc/letsencrypt/live/myserver.example.com/privkey.pem
        Include /etc/letsencrypt/options-ssl-apache.conf
</VirtualHost>
</IfModule>

也许它甚至可以简化为 RewriteRule ^/[0-9]+/ws/graph/ ws:// localhost:8000/$1 [P,L],我没有检查。)

此配置工作正常,我使用 HTTP 和 WebSocket 成功连接到代理服务器后面的应用程序,具体取决于我使用的 URL。


Nginx

现在,我尝试使用 Nginx 重新创建相同的行为。

我尝试过:

server {

       server_name myserver.example.com;

       access_log /var/log/nginx/myserver.example.com_SSL-access.log;
       error_log  /var/log/nginx/myserver.example.com_SSL-error.log;

       rewrite ^/[0-9]+/ws/graph/ ws://localhost:8000/$1;

       location / {
           proxy_pass http://localhost:8000/;
       }


       listen [::]:443 ssl;
       listen 443 ssl;
       ssl_certificate /etc/letsencrypt/live/myserver.example.com/fullchain.pem;
       ssl_certificate_key /etc/letsencrypt/live/myserver.example.com/privkey.pem;
       include /etc/letsencrypt/options-ssl-nginx.conf;
       ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;

}

并且:

server {

       server_name myserver.example.com;

       access_log /var/log/nginx/myserver.example.com_SSL-access.log;
       error_log  /var/log/nginx/myserver.example.com_SSL-error.log;

       location ~ ^/[0-9]+/ws/graph/ {
            proxy_pass http://localhost:8000/$1;

            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection "Upgrade";
            proxy_set_header Host $host;
       }

       location / {
           proxy_pass http://localhost:8000/;
       }


       listen [::]:443 ssl;
       listen 443 ssl;
       ssl_certificate /etc/letsencrypt/live/myserver.example.com/fullchain.pem;
       ssl_certificate_key /etc/letsencrypt/live/myserver.example.com/privkey.pem;
       include /etc/letsencrypt/options-ssl-nginx.conf;
       ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;

}

我还尝试将以下标头添加到 WebSocket 的 location

       location ~ ^/[0-9]+/ws/graph/ {
            proxy_pass http://localhost:8000/$1;
            
            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-Proto $scheme;

            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection "Upgrade";
            proxy_set_header Host $host;
       }

以及此重写规则子句:

      if ($request_uri ~ ^/[0-9]+/ws/graph/) {       
           rewrite (.*)  ws://localhost:8000/$1;
       }

对于 nginx 配置的所有上述情况,所有请求都被视为应用程序中的 HTTP 请求位于 localhost:8000/

我想要实现的是让以下连接正常工作,例如,使用 JavaScript 从浏览器连接:

const ws = new WebSocket(`wss://myserver.example.com/1234123/ws/graph/`);

我不是 Nginx 专家,规则的语法几乎没有记录,或者我找不到它。欢迎所有建议。


来源

Apache

I have the following RewriteRule in the Apache web proxy server configuration:

<IfModule mod_ssl.c>
<VirtualHost *:443>
        ServerName myserver.example.com
        ServerAdmin [email protected]
 
        # Rewrite rule for the WebSocket connection
        RewriteEngine On
        RewriteCond %{REQUEST_URI}  ^/[0-9]+/ws/graph/            [NC]
        RewriteRule /(.*)           ws://localhost:8000/$1 [P,L]
 
        # Logs for connections at port 443 (HTTPS/WSS)
        ErrorLog ${APACHE_LOG_DIR}/myserver.example.com-SSL-error.log
        CustomLog ${APACHE_LOG_DIR}/myserver.example.com-SSL-access.log combined
 
        # HTTPS => HTTP redirect for requests to the application
        ProxyPass / http://localhost:8000/
        ProxyPassReverse / http://localhost:8000/
 
        # Alias and certificate configuration
        ServerAlias myserver.example.com
        SSLCertificateFile /etc/letsencrypt/live/myserver.example.com/fullchain.pem
        SSLCertificateKeyFile /etc/letsencrypt/live/myserver.example.com/privkey.pem
        Include /etc/letsencrypt/options-ssl-apache.conf
</VirtualHost>
</IfModule>

(Maybe it can be even simplified to RewriteRule ^/[0-9]+/ws/graph/ ws://localhost:8000/$1 [P,L], I didn't check that.)

This configuration works fine and I successfully connect with the application behind the proxy server using HTTP and WebSockets, depending on which URL I use.


Nginx

Now, I am trying to recreate the same behavior using Nginx.

I tried:

server {

       server_name myserver.example.com;

       access_log /var/log/nginx/myserver.example.com_SSL-access.log;
       error_log  /var/log/nginx/myserver.example.com_SSL-error.log;

       rewrite ^/[0-9]+/ws/graph/ ws://localhost:8000/$1;

       location / {
           proxy_pass http://localhost:8000/;
       }


       listen [::]:443 ssl;
       listen 443 ssl;
       ssl_certificate /etc/letsencrypt/live/myserver.example.com/fullchain.pem;
       ssl_certificate_key /etc/letsencrypt/live/myserver.example.com/privkey.pem;
       include /etc/letsencrypt/options-ssl-nginx.conf;
       ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;

}

and:

server {

       server_name myserver.example.com;

       access_log /var/log/nginx/myserver.example.com_SSL-access.log;
       error_log  /var/log/nginx/myserver.example.com_SSL-error.log;

       location ~ ^/[0-9]+/ws/graph/ {
            proxy_pass http://localhost:8000/$1;

            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection "Upgrade";
            proxy_set_header Host $host;
       }

       location / {
           proxy_pass http://localhost:8000/;
       }


       listen [::]:443 ssl;
       listen 443 ssl;
       ssl_certificate /etc/letsencrypt/live/myserver.example.com/fullchain.pem;
       ssl_certificate_key /etc/letsencrypt/live/myserver.example.com/privkey.pem;
       include /etc/letsencrypt/options-ssl-nginx.conf;
       ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;

}

I also tried adding the following headers to the WebSocket's location:

       location ~ ^/[0-9]+/ws/graph/ {
            proxy_pass http://localhost:8000/$1;
            
            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-Proto $scheme;

            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection "Upgrade";
            proxy_set_header Host $host;
       }

and this rewrite rule clause:

      if ($request_uri ~ ^/[0-9]+/ws/graph/) {       
           rewrite (.*)  ws://localhost:8000/$1;
       }

For all above cases of the nginx configuration all requests are treated as HTTP requests in the application at localhost:8000/.

What I am trying to achieve is to get the following connection working, e.g., connecting from the browser using JavaScript:

const ws = new WebSocket(`wss://myserver.example.com/1234123/ws/graph/`);

I am not an expert on Nginx and the syntax for the rules is hardly documented, or I cannot find it. All suggestions are welcomed.


Sources

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

分開簡單 2025-01-18 03:53:15

一位同事帮我解决了这个问题。下面我把答案贴出来。

解决方案

正确的配置是:

server {

       server_name myserver.example.com;

       access_log /var/log/nginx/myserver.example.com_SSL-access.log;
       error_log  /var/log/nginx/myserver.example.com_SSL-error.log;

       # WebSocket support
       location ~ ^/[0-9]+/ws/graph/ {
           proxy_pass http://localhost:8000;
           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://localhost:8000/;
       }


       listen [::]:443 ssl;
       listen 443 ssl;
       ssl_certificate /etc/letsencrypt/live/myserver.example.com/fullchain.pem;
       ssl_certificate_key /etc/letsencrypt/live/myserver.example.com/privkey.pem;
       include /etc/letsencrypt/options-ssl-nginx.conf;
       ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;

}

我做错了什么

我的错误是我绑定了:

       location ~ ^/[0-9]+/ws/graph/ {
           proxy_pass http://localhost:8000/;
           ...
       }

和:

       location ~ ^/[0-9]+/ws/graph/ {
           proxy_pass http://localhost:8000/$1;
           ...
       }

两者都不起作用,而前者(请注意 URL 行末尾的 "/" )导致错误:

    "proxy_pass" cannot have URI part in location given by regular expression, or inside named location, or inside "if" statement, or inside "limit_except" block in /etc/nginx/sites-enabled/vhost-myserver.example.com.conf:10

另请注意,必须有一个单独的 location 来处理“正常”HTTP 请求,否则请求将无法正确代理:

       ...

       # WebSocket support
       location ~ ^/[0-9]+/ws/graph/ {
           proxy_pass http://localhost:8000;
           ...
       }

       # HTTP proxy
       location / {
           proxy_pass http://localhost:8000/;
       }

       ...

A colleague helped me with this one. Below I post the answer.

The solution

The proper configuration is:

server {

       server_name myserver.example.com;

       access_log /var/log/nginx/myserver.example.com_SSL-access.log;
       error_log  /var/log/nginx/myserver.example.com_SSL-error.log;

       # WebSocket support
       location ~ ^/[0-9]+/ws/graph/ {
           proxy_pass http://localhost:8000;
           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://localhost:8000/;
       }


       listen [::]:443 ssl;
       listen 443 ssl;
       ssl_certificate /etc/letsencrypt/live/myserver.example.com/fullchain.pem;
       ssl_certificate_key /etc/letsencrypt/live/myserver.example.com/privkey.pem;
       include /etc/letsencrypt/options-ssl-nginx.conf;
       ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;

}

What I did wrong

My mistake was that I tied:

       location ~ ^/[0-9]+/ws/graph/ {
           proxy_pass http://localhost:8000/;
           ...
       }

and:

       location ~ ^/[0-9]+/ws/graph/ {
           proxy_pass http://localhost:8000/$1;
           ...
       }

both of which will not work, with the former (note the "/" at the end of the URL line) resulting in an error:

    "proxy_pass" cannot have URI part in location given by regular expression, or inside named location, or inside "if" statement, or inside "limit_except" block in /etc/nginx/sites-enabled/vhost-myserver.example.com.conf:10

Also note that a separate location must be there to handle "normal" HTTP requests, else the requests won't be proxied properly:

       ...

       # WebSocket support
       location ~ ^/[0-9]+/ws/graph/ {
           proxy_pass http://localhost:8000;
           ...
       }

       # HTTP proxy
       location / {
           proxy_pass http://localhost:8000/;
       }

       ...
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文