首页 > 系统相关 >nginx412常见错误porxy_ssl_name

nginx412常见错误porxy_ssl_name

时间:2022-12-05 20:12:08浏览次数:71  
标签:aa nginx412 porxy name xx api proxy pass location

Nginx 反向代理问题汇总

    7月 18, 2022

Nginx 反向代理问题汇总

作者 Zgao 在安全运维

使用Nginx反向代理中出现的多类问题统一汇总分析并给出解决思路。

文章目录

Nginx 反代提示421 misdirected request

在一次反向代理某星球网站时出现了421的问题。

https://www.zsxq.com/ 以该网站为例。

使用最简单反代配置。

server { listen 88; server_name localhost; location /api/ { proxy_pass https://api.zsxq.com/; proxy_set_header Host api.zsxq.com; } }

返回421的状态码。

是什么导致“421 错误定向请求”错误?

客户端需要为此请求建立新连接,因为请求的主机名与用于此连接的服务器名称指示 (SNI) 不匹配。

Misdirected Request

当一个 TLS 证书在多个域之间共享时,该证书要么具有通配符名称,例如“*.example.org”,要么带有多个备用名称。使用 HTTP/2 的浏览器会识别这一点,并为此类主机重用已打开的连接。
但是当在同一个 TLS 连接上有多个主机的多个请求时,重新协商就变得不可能了。然后它可能会向客户端触发错误“421 Misdirected Request”。

上面的配置报错也是这种情况。*.zsxq.com使用了通配符的域名证书。nginx 不知道具体要访问哪一个网站,所以需要指定对应的 proxy_ssl_name 。

正确的配置如下,指定ssl_name多个参数:

server { listen 88; server_name localhost; location /api/ { proxy_ssl_server_name on; proxy_ssl_name api.zsxq.com; proxy_ssl_verify off; proxy_pass https://api.zsxq.com/; proxy_set_header Host api.zsxq.com; proxy_set_header Accept-Encoding ''; proxy_set_header Cookie 'xxxx'; } }

反代成功!

反向代理解决图片等资源防盗链

还是以zsxq.com为例,该网站的图片资源会检测referer头,如果不是从自己网站过去的就会返回403,但直接用浏览器打开图片链接就能正常显示。

区别在于前者的request请求header中是带有referer头,浏览器访问时默认会带上。

这里有两种解决思路:

  1. 将图片等静态资源也进行代理,但比较占用反代服务器的带宽资源。
  2. 让浏览器发起请求时,不带上referer头。

解决方法:
在反代的页面中插入meta标签。

<meta name="referrer" content="no-referrer">

虽然Nginx没有直接插入的指令来实现,但可以用sub_filter替换的方式曲线救国。

添加配置如下:

sub_filter_once off; sub_filter_types *; sub_filter '</head>' '<meta name="referrer" content="no-referrer"></head>';

通过替换实现在head标签中插入meta标签。此时浏览器在请求资源时就不会携带referer头。

图片资源加载成功!

反向代理视频资源

设置反向代理缓冲大小。之前文章有写过,参考:

反向代理sub_filter字符替换不生效

通常有以下两种原因:

  1. 源站点启用了gzip压缩。
  2. 需替换的MIME类型为text/html之外的字符串,比如server端返回json格式的内容,sub_filter是不会进行替换的。

第一种的解决方案如下:

proxy_set_header Accept-Encoding "";

如果增加这行代码后问题依旧存在,大概率是源站点启用了强制gzip压缩。nginx反代替换关键字前并不会自动解压缩,所以无法执行替换内容。

解决思路:
反代2次。第一次反代时增加gzip off;设置项,以输出无压缩的内容,第二次反代本机地址,实现关键字替换。

location /unzip/ { # 负责解压缩内容 proxy_set_header Host target.com; #目标域名 proxy_pass https://target.com/; #目标域名 }   location / { proxy_set_header Host my.target.com; #自己的域名   proxy_set_header Accept-Encoding '';   gzip off; sub_filter_types *; #替换所有类型 sub_filter 'xxxxx' 'xxxxxxx'; #替换内容 sub_filter_once off; #所有匹配到的都替换 proxy_pass http://127.0.0.1/unzip/; #多走一次转发, 让/go先解压缩gzip }

第二种的解决方案如下:

sub_filter_types *; #替换所有类型

Location 和 proxy_pass 加不加斜杠的区别?

proxy_pass 指令后面的参数有讲究,但在实际的应用中就分为两种情况。

proxy_pass 后面不带路径,就原封不动传给后端。
proxy_pass 后面带路径,就去掉 Location 的匹配再传给后端。

proxy_pass 后面url只有host没有路径

这里指不包含 $uri ,如:

  • http://host  ✅
  • https://host  ✅
  • http://host:port  ✅
  • https://host:port  ✅
  • http://host/  ❌
  • http://host:port/  ❌

这时候 location 匹配的完整路径将直接透传给后端,如:

// 访问: / 后端: / // 访问: /api/xx 后端: /api/xx // 访问: /api/xx?aa 后端: /api/xx?aa location / { proxy_pass http://node:8080; }   // 访问: /api/ 后端: /api/ // 访问: /api/xx 后端: /api/xx // 访问: /api/xx?aa 后端: /api/xx?aa // 访问: /api-xx?aa 后端: location /api/ { proxy_pass http://node:8080; }   // 访问: /api/ 后端: /api/ // 访问: /api/xx 后端: /api/xx // 访问: /api/xx?aa 后端: /api/xx?aa // 访问: /api-xx?aa 后端: /api-xx?aa location /api { proxy_pass http://node:8080; }

proxy_pass 后面的url中带有路径

注意,这里的路径哪怕只是一个 / 也是存在的,如:

  • http://host  ❌
  • https//host/  ✅
  • http://host:port  ❌
  • https://host:port/  ✅
  • http://host/api  ✅
  • http://host/api/  ✅

当 proxy_pass url 的 url 包含路径时,匹配时会根据 location 的匹配后的链接透传给 url ,注意匹配后是下面这样。

location 规则访问的原始链接匹配之后的路径
location / /  
location / /a a
location / /a/b/c?d a/b/c?d
location /a/ /a/  
location /a/ /a/b/c?d b/c?d
// 访问: / 后端: / // 访问: /api/xx 后端: /api/xx // 访问: /api/xx?aa 后端: /api/xx?aa location / { proxy_pass http://node:8080/; }   // 访问: /api/ 后端: / // 访问: /api/xx 后端: /xx // 访问: /api/xx?aa 后端: /xx?aa // 访问: /api-xx?aa 未匹配 location /api/ { proxy_pass http://node:8080/; }   // 访问: /api 后端: / // 访问: /api/ 后端: // // 访问: /api/xx 后端: //xx // 访问: /api/xx?aa 后端: //xx?aa // 访问: /api-xx?aa 后端: /-xx?aa location /api { proxy_pass http://node:8080/; }   // 访问: /api/ 后端: /v1 // 访问: /api/xx 后端: /v1xx // 访问: /api/xx?aa 后端: /v1xx // 访问: /api-xx?aa 未匹配 location /api/ { proxy_pass http://node:8080/v1; }   // 访问: /api/ 后端: /v1/ // 访问: /api/xx 后端: /v1/xx // 访问: /api/xx?aa 后端: /v1/xx // 访问: /api-xx?aa 未匹配 location /api/ { proxy_pass http://node:8080/v1/; }

可以看出,当 proxy_pass url 中包含路径时,结尾的 / 最好同 location 匹配规则一致。

alias指定返回某个文件

alias使用注意两点:

  1. Windows使用绝对路径一定要用反斜杠 \ 。
  2. 使用相对路径注意将文件放到默认路径下面,直接指定文件名。
location = /api/v2/groups { default_type application/json; alias C:\phpstudy_pro\Extensions\Nginx1.15.11\groups.json; #alias groups.json; #使用相对路径 }

这里测试发现使用alias默认会拼接路径导致报错。可以通过error.log进行debug。

比如我是用绝对路径,但是注意一定要用 \ ,不然会出现下面的 failed (3: The system cannot find the path specified) 的报错。

root与alias的区别?

root与alias主要区别在于nginx如何解释location后面的uri,这会使两者分别以不同的方式将请求映射到服务器文件上。

root的处理结果是:root路径+location路径
alias的处理结果是:使用alias路径替换location路径
alias是一个目录别名的定义,root则是最上层目录的定义。

还有一个重要的区别是alias后面必须要用“/”结束,否则会找不到文件的,而root则可有可无。

location ^~ /path/ { root /www/root/html/; }

如果一个请求的URI是/path/a.html时,web服务器将会返回服务器上的/www/root/html/path/a.html的文件。

location ^~ /path/ { alias /www/root/html/new_path/; }

如果一个请求的URI是/path/a.html时,web服务器将会返回服务器上的/www/root/html/new_path/a.html的文件。注意这里是new_path,因为alias会把location后面配置的路径丢弃掉,把当前匹配到的目录指向到指定的目录。

注意:
1. 使用alias时,目录名后面一定要加”/”。
3. alias在使用正则匹配时,必须捕捉要匹配的内容并在指定的内容处使用。
4. alias只能位于location块中。(root可以不放在location中)

标签:aa,nginx412,porxy,name,xx,api,proxy,pass,location
From: https://www.cnblogs.com/cheyunhua/p/16953343.html

相关文章