Nginx WSS(端口 443)到 WS(端口 80)重写规则包含正则表达式 URL
Nginx WSS (port 443) to WS (port 80) rewrite rule containing regex URL
阿帕奇
我在 Apache 网络代理服务器配置中有以下 RewriteRule
:
<IfModule mod_ssl.c>
<VirtualHost *:443>
ServerName myserver.example.com
ServerAdmin admin@myserver.example.com
# Rewrite rule for the WebSocket connection
RewriteEngine On
RewriteCond %{REQUEST_URI} ^/[0-9]+/ws/graph/ [NC]
RewriteRule /(.*) ws://localhost:8000/ [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/ [P,L]
,我没查过)
此配置工作正常,我使用 HTTP 和 WebSockets 成功连接到代理服务器后面的应用程序,具体取决于我使用的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/;
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/;
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;
}
我还尝试将以下 headers 添加到 WebSocket 的 location
:
location ~ ^/[0-9]+/ws/graph/ {
proxy_pass http://localhost:8000/;
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/;
}
对于 nginx
配置的所有上述情况,所有请求在 localhost:8000/
的应用程序中都被视为 HTTP 请求。
我想要实现的是让以下连接正常工作,例如,使用 JavaScript:
从浏览器连接
const ws = new WebSocket(`wss://myserver.example.com/1234123/ws/graph/`);
我不是 Nginx 专家,规则的语法几乎没有记录,或者我找不到。欢迎所有建议。
来源
一位同事帮我解决了这个问题。下面是我post的答案。
解决方案
正确的配置是:
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/;
...
}
两者都不起作用,前者(注意 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/;
}
...
阿帕奇
我在 Apache 网络代理服务器配置中有以下 RewriteRule
:
<IfModule mod_ssl.c>
<VirtualHost *:443>
ServerName myserver.example.com
ServerAdmin admin@myserver.example.com
# Rewrite rule for the WebSocket connection
RewriteEngine On
RewriteCond %{REQUEST_URI} ^/[0-9]+/ws/graph/ [NC]
RewriteRule /(.*) ws://localhost:8000/ [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/ [P,L]
,我没查过)
此配置工作正常,我使用 HTTP 和 WebSockets 成功连接到代理服务器后面的应用程序,具体取决于我使用的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/;
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/;
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;
}
我还尝试将以下 headers 添加到 WebSocket 的 location
:
location ~ ^/[0-9]+/ws/graph/ {
proxy_pass http://localhost:8000/;
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/;
}
对于 nginx
配置的所有上述情况,所有请求在 localhost:8000/
的应用程序中都被视为 HTTP 请求。
我想要实现的是让以下连接正常工作,例如,使用 JavaScript:
从浏览器连接const ws = new WebSocket(`wss://myserver.example.com/1234123/ws/graph/`);
我不是 Nginx 专家,规则的语法几乎没有记录,或者我找不到。欢迎所有建议。
来源
一位同事帮我解决了这个问题。下面是我post的答案。
解决方案
正确的配置是:
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/;
...
}
两者都不起作用,前者(注意 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/;
}
...