介绍
前几天墙又双叒叕发威了,小白一直ws裸奔的一台小鸡也被墙了,就又看了下文档,发现里面提到这么一点:
if ($http_upgrade != "websocket") { # WebSocket协商失败时返回404 return 404; }
那也就是说,在不不使用TLS协议的前提下(当然你应该使用……),ws路径是透明的,没有任何加密的,我们直接使用浏览器访问IP/域名+路径时会返回404错误代码,如下图所示:
根据小白的观察,大多数人要么时连nginx都没有直接返回Bad Request,或者时前置了一个nginx,则返回404,那如果我们不返回404,而返回一个真实的网页,或者返回一个反代的网页,是否会看起来更正常,我也不知道这个想法对不对,就顺着往下写了。
返回404错误代码
if ($http_upgrade != "websocket") { # WebSocket协商失败时返回404 return 404; }
这是一个 Nginx 配置片段,用于处理 WebSocket 请求。让我们来逐行解释:
if ($http_upgrade != "websocket") {
:这行代码检查 HTTP 请求头中的Upgrade
字段是否等于 “websocket”。$http_upgrade
是一个变量,代表 HTTP 请求头中的Upgrade
字段。如果该字段的值不是 “websocket”,则满足条件,执行括号中的代码。return 404;
:当满足if
条件时,这行代码会使 Nginx 返回一个 404 状态码,表示请求的资源未找到。换句话说,如果请求不是 WebSocket 请求,服务器将返回 404 错误。}
:结束if
语句块。
总结一下,这个 Nginx 配置片段的意思是:如果请求的协议不是 WebSocket(即请求头中的 Upgrade
字段不等于 “websocket”),则返回 404 错误。这可以确保仅处理 WebSocket 请求,而忽略其他类型的请求。
返回其他值
在 Nginx 配置中,你可以使用 return
指令返回其他的 HTTP 状态码和相应的信息。以下是一些示例:
- 返回 403 禁止访问:
if ($http_upgrade != "websocket") { return 403; }
- 返回 400 错误请求:
if ($http_upgrade != "websocket") { return 400; }
- 返回 500 服务器内部错误:
if ($http_upgrade != "websocket") { return 500; }
- 返回自定义状态码和消息:
if ($http_upgrade != "websocket") { return 418 "I'm a teapot"; }
在这些示例中,你可以将 403、400、500 或 418 等状态码替换为你想要的任何有效的 HTTP 状态码。同样,你可以自定义返回的消息,只需将其放在双引号中即可。
需要注意的是,在实际应用中,应当根据实际情况选择合适的状态码。例如,如果请求格式不正确,可以返回 400(错误请求);如果请求被拒绝,可以返回 403(禁止访问)等。
返回一个网页
当然可以。在 Nginx 配置中,你可以使用 error_page
指令来指定一个自定义的错误页面。这样,当满足某个条件时,Nginx 将返回指定的错误页面。下面是一个示例:
首先,在 Nginx 配置文件的 server
块中添加以下配置:
error_page 418 /custom_error_page.html; location = /custom_error_page.html { root /path/to/your/error_pages; internal; } if ($http_upgrade != "websocket") { return 418; }
这个配置的说明如下:
error_page 418 /custom_error_page.html;
:为 HTTP 状态码 418 指定一个自定义错误页面,该页面的 URI 为/custom_error_page.html
。location = /custom_error_page.html { ... }
:定义一个location
块来处理/custom_error_page.html
路径的请求。root /path/to/your/error_pages;
:指定自定义错误页面所在的目录。你需要将/path/to/your/error_pages
替换为实际的目录路径。internal;
:这个指令表明此location
块仅用于内部处理,不能直接通过外部请求访问。if ($http_upgrade != "websocket") { ... }
:这部分和之前的配置相同,用于检查请求是否为 WebSocket 请求。当满足条件时,执行括号中的代码。return 418;
:如果请求不是 WebSocket 请求,返回 418 状态码。由于我们之前为状态码 418 指定了自定义错误页面,Nginx 将返回该错误页面。
请确保创建一个名为 custom_error_page.html
的 HTML 文件,并将其放在你指定的错误页面目录(/path/to/your/error_pages
)中。当请求不是 WebSocket 请求时,Nginx 将返回这个自定义错误页面。你可以根据需要修改状态码和错误页面的文件名。
返回一个反代的网站
你可以在 Nginx 配置中设置反向代理,当满足特定条件时(如本例中的非 WebSocket 请求),将请求代理到另一个网站。以下是一个配置示例:
upstream backend { server backend.example.com; } if ($http_upgrade != "websocket") { rewrite ^(.*)$ /proxy$1 last; } location /proxy { proxy_pass http://backend; 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; }
这个配置的说明如下:
upstream backend { ... }
:定义一个名为backend
的上游服务器组。server backend.example.com;
:将backend.example.com
作为上游服务器。你可以将其替换为你要代理的目标服务器地址。if ($http_upgrade != "websocket") { ... }
:这部分和之前的配置相同,用于检查请求是否为 WebSocket 请求。当满足条件时,执行括号中的代码。rewrite ^(.*)$ /proxy$1 last;
:如果请求不是 WebSocket 请求,将 URI 重写为以/proxy
开头,并将原始 URI 附加在其后,然后跳转到下一个location
块进行处理。location /proxy { ... }
:定义一个location
块,用于处理以/proxy
开头的请求。proxy_pass http://backend;
:将请求代理到之前定义的backend
上游服务器组。proxy_set_header ...
:这些指令用于设置代理请求的 HTTP 头。这里设置了Host
、X-Real-IP
、X-Forwarded-For
和X-Forwarded-Proto
头,以便后端服务器能获取正确的客户端信息。
当请求不是 WebSocket 请求时,Nginx 将请求反向代理到指定的后端服务器。请注意,这个配置仅作为示例,你可能需要根据实际需求调整配置。
比方说我们要返回 http://209.222.11.49:2333 这个网页。要将非 WebSocket 请求反向代理到 http://209.222.11.49:2333
,请按照以下示例配置 Nginx:
if ($http_upgrade != "websocket") { rewrite ^(.*)$ /proxy$1 last; } location /proxy { proxy_pass http://209.222.11.49:2333; 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 前缀去掉,避免向后端服务器传递这个前缀 rewrite ^/proxy(/.*)$ $1 break; }
这个配置的说明如下:
if ($http_upgrade != "websocket") { ... }
:这部分和之前的配置相同,用于检查请求是否为 WebSocket 请求。当满足条件时,执行括号中的代码。rewrite ^(.*)$ /proxy$1 last;
:如果请求不是 WebSocket 请求,将 URI 重写为以/proxy
开头,并将原始 URI 附加在其后,然后跳转到下一个location
块进行处理。location /proxy { ... }
:定义一个location
块,用于处理以/proxy
开头的请求。proxy_pass http://209.222.11.49:2333;
:将请求代理到指定的 IP 地址和端口(209.222.11.49:2333)。proxy_set_header ...
:这些指令用于设置代理请求的 HTTP 头。这里设置了Host
、X-Real-IP
、X-Forwarded-For
和X-Forwarded-Proto
头,以便后端服务器能获取正确的客户端信息。rewrite ^/proxy(/.*)$ $1 break;
:将请求中的/proxy
前缀去掉,以避免向后端服务器传递这个前缀。
当请求不是 WebSocket 请求时,Nginx 将请求反向代理到指定的 IP 地址和端口。请注意,这个配置仅作为示例,你可能需要根据实际需求调整配置。
要将非 WebSocket 请求反向代理到 https://www.kernel.org
,请按照以下示例配置 Nginx:
if ($http_upgrade != "websocket") { rewrite ^(.*)$ /proxy$1 last; } location /proxy { proxy_pass https://www.kernel.org; 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 前缀去掉,避免向后端服务器传递这个前缀 rewrite ^/proxy(/.*)$ $1 break; # 添加 SSL 代理设置 proxy_ssl_server_name on; proxy_ssl_protocols TLSv1 TLSv1.1 TLSv1.2; proxy_ssl_session_reuse on; }
这个配置的说明如下:
if ($http_upgrade != "websocket") { ... }
:这部分和之前的配置相同,用于检查请求是否为 WebSocket 请求。当满足条件时,执行括号中的代码。rewrite ^(.*)$ /proxy$1 last;
:如果请求不是 WebSocket 请求,将 URI 重写为以/proxy
开头,并将原始 URI 附加在其后,然后跳转到下一个location
块进行处理。location /proxy { ... }
:定义一个location
块,用于处理以/proxy
开头的请求。proxy_pass https://www.kernel.org;
:将请求代理到指定的 HTTPS 网址(https://www.kernel.org
)。proxy_set_header ...
:这些指令用于设置代理请求的 HTTP 头。这里设置了Host
、X-Real-IP
、X-Forwarded-For
和X-Forwarded-Proto
头,以便后端服务器能获取正确的客户端信息。rewrite ^/proxy(/.*)$ $1 break;
:将请求中的/proxy
前缀去掉,以避免向后端服务器传递这个前缀。proxy_ssl_server_name on;
:启用 SNI(Server Name Indication)扩展,以便在 SSL 握手期间发送正确的服务器名称。proxy_ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
:设置允许的 SSL 协议版本。这里允许 TLSv1、TLSv1.1 和 TLSv1.2。proxy_ssl_session_reuse on;
:启用 SSL 会话复用,以提高性能。
当请求不是 WebSocket 请求时,Nginx 将请求反向代理到指定的 HTTPS 网址。请注意,这个配置仅作为示例,你可能需要根据实际需求调整配置。
要将非 WebSocket 请求反向代理到 https://kernel.ubuntu.com/~kernel-ppa
,请按照以下示例配置 Nginx:
if ($http_upgrade != "websocket") { rewrite ^(.*)$ /proxy$1 last; } location /proxy { proxy_pass https://kernel.ubuntu.com/~kernel-ppa; 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 前缀去掉,避免向后端服务器传递这个前缀 rewrite ^/proxy(/.*)$ $1 break; # 添加 SSL 代理设置 proxy_ssl_server_name on; proxy_ssl_protocols TLSv1 TLSv1.1 TLSv1.2; proxy_ssl_session_reuse on; }
这个配置的说明如下:
if ($http_upgrade != "websocket") { ... }
:这部分和之前的配置相同,用于检查请求是否为 WebSocket 请求。当满足条件时,执行括号中的代码。rewrite ^(.*)$ /proxy$1 last;
:如果请求不是 WebSocket 请求,将 URI 重写为以/proxy
开头,并将原始 URI 附加在其后,然后跳转到下一个location
块进行处理。location /proxy { ... }
:定义一个location
块,用于处理以/proxy
开头的请求。proxy_pass https://kernel.ubuntu.com/~kernel-ppa;
:将请求代理到指定的 HTTPS 网址(https://kernel.ubuntu.com/~kernel-ppa
)。proxy_set_header ...
:这些指令用于设置代理请求的 HTTP 头。这里设置了Host
、X-Real-IP
、X-Forwarded-For
和X-Forwarded-Proto
头,以便后端服务器能获取正确的客户端信息。rewrite ^/proxy(/.*)$ $1 break;
:将请求中的/proxy
前缀去掉,以避免向后端服务器传递这个前缀。proxy_ssl_server_name on;
:启用 SNI(Server Name Indication)扩展,以便在 SSL 握手期间发送正确的服务器名称。proxy_ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
:设置允许的 SSL 协议版本。这里允许 TLSv1、TLSv1.1 和 TLSv1.2。proxy_ssl_session_reuse on;
:启用 SSL 会话复用,以提高性能。
当请求不是 WebSocket 请求时,Nginx 将请求反向代理到指定的 HTTPS 网址。请注意,这个配置仅作为示例,你可能需要根据实际需求调整配置。
结语
小白不知道这样的设置有没有用,是否属于掩耳盗铃,还有懂得大佬不吝赐教。