Nginx WSS(端口443)到WS(端口80)重写包含正则表达式URL的规则
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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
一位同事帮我解决了这个问题。下面我把答案贴出来。
解决方案
正确的配置是:
我做错了什么
我的错误是我绑定了:
和:
两者都不起作用,而前者(请注意 URL 行末尾的 "/" )导致错误:
另请注意,必须有一个单独的
location
来处理“正常”HTTP 请求,否则请求将无法正确代理:A colleague helped me with this one. Below I post the answer.
The solution
The proper configuration is:
What I did wrong
My mistake was that I tied:
and:
both of which will not work, with the former (note the "/" at the end of the URL line) resulting in an error:
Also note that a separate
location
must be there to handle "normal" HTTP requests, else the requests won't be proxied properly: