原文作者:Timo Stark of F5 和 Sergey Budnevich of F5
原文链接:防止 10 大 NGINX 配置谬误
转载起源:NGINX 官方网站
在帮忙 NGINX 用户解决问题时,咱们常常会发现配置谬误,这种配置谬误也每每呈现在其余用户的配置中,甚至有时还会呈现在咱们的 NGINX 工程师共事编写的配置中!本文介绍了 10 个最常见的谬误,并解释了问题所在以及相应的解决办法。
1. 每个 worker 的文件描述符有余
2.error_log off 指令
3. 未启用与上游服务器的 keepalive 连贯
4. 遗记指令继承的工作机制
5.proxy_buffering off 指令
6.if 指令使用不当
7. 过多的健康检查
8. 不平安地拜访指标
9. 当所有流量都来自同一个 /24 CIDR 块时应用 ip_hash
10. 不采纳上游组
谬误 6:if 指令使用不当
if 指令应用起来很辣手,尤其是在 location{}块中。它通常不会依照预期执行,甚至还会导致呈现段谬误。事实上,在 NGINX Wiki 中有一篇题为“if 问题多多 (If is Evil)”的文章,具体探讨了 if 问题以及如何防止这些问题。
通常,在 if{} 块中,您能够始终平安应用的指令只有 return 和 rewrite。以下示例应用 if 来检测蕴含 X‑Test http 音讯头的申请(能够是您想要测试的任何条件)。NGINX 返回 430 (Request Header Fields Too Large) 谬误,在指定的地位 @error_430 进行拦挡并将申请代理到名为 b 的上游 group。
location / {
error_page 430 = @error_430;
if ($http_x_test) {return 430;}
proxy_pass http://a;
}
location @error_430 {proxy_pass b;}
对于 if 的这个用处及许多其余用处,通常能够完全避免应用该指令。在以下示例中,当申请蕴含 X‑Test 标头时,map{} 块将 $upstream_name 变量设置为 b,并且申请被代理到以 b 命名的上游 group。
map $http_x_test $upstream_name {
default "b";
"""a";
}
# ...
location / {proxy_pass http://$upstream_name;}
谬误 7:过多的健康检查
配置多个虚构服务器将申请代理到同一个上游组非常常见(换句话说,在多个 server{} 块中蕴含雷同的 proxy_pass 指令)。这里的谬误是在每个 server{} 块中都增加一个 health_check 指令。这样做只会减少上游服务器的负载,而不会产生任何额定信息。
显然,解决办法是每个 upstream{} 块只定义一个健康检查。此处,咱们在一个指定地位为名为 b 的上游 group 定义了健康检查,并进行了适当的超时和 http 音讯头设置。
location / {
proxy_set_header Host $host;
proxy_set_header "Connection" "";
proxy_http_version 1.1;
proxy_pass http://b;
}
location @health_check {
health_check;
proxy_connect_timeout 2s;
proxy_read_timeout 3s;
proxy_set_header Host example.com;
proxy_pass http://b;
}
在简单的配置中,它能够进一步简化治理,将所有健康检查地位以及 NGINX Plus API 仪表盘分组到单个虚构服务器中,如本例所示。
server {
listen 8080;
location / {# …}
location @health_check_b {
health_check;
proxy_connect_timeout 2s;
proxy_read_timeout 3s;
proxy_set_header Host example.com;
proxy_pass http://b;
}
location @health_check_c {
health_check;
proxy_connect_timeout 2s;
proxy_read_timeout 3s;
proxy_set_header Host api.example.com;
proxy_pass http://c;
}
location /api {
api write=on;
# directives limiting access to the API (see 'Mistake 8' below)
}
location = /dashboard.html {root /usr/share/nginx/html;}
}
无关 HTTP、TCP、UDP 和 gRPC 服务器的健康检查的更多信息,请参阅《NGINX Plus 管理员指南》。
谬误 8:不平安拜访指标
Stub Status 模块提供了无关 NGINX 操作的根本指标。对于 NGINX Plus,您还能够应用 NGINX Plus API 收集更宽泛的指标集。通过在 server{} 或 location{} 块中别离蕴含 stub_status 或 api 指令来启用指标收集,您随后能够通过拜访 URL 来查看这些指标。(对于 NGINX Plus API,您还须要为要收集指标的 NGINX 实体 —— 虚构服务器、上游 group、缓存等配置共享内存区;请参阅《NGINX Plus 治理指南》中的阐明。)
其中一些指标是敏感信息,可被用来攻打您的网站或 NGINX 代理的利用,咱们有时在用户配置中看到的谬误是未限度对相应 URL 的拜访。此处咱们将介绍一些能够爱护指标的办法。在第一个示例中咱们将应用 stub_status。
通过以下配置,互联网上的任何人都能够拜访 http://example.com/basic_status 上的指标。
server {
listen 80;
server_name example.com;
location = /basic_status {stub_status;}
}
应用 HTTP 根本身份验证爱护指标
采纳 HTTP 根本身份验证相干的形式为指标增加密码保护,蕴含 auth_basic 和 auth_basic_user_file 指令。文件(此处为 .htpasswd)列出了能够登录查看指标的客户端的用户名和明码:
server {
listen 80;
server_name example.com;
location = /basic_status {
auth_basic“closed site”;
auth_basic_user_file conf.d/.htpasswd;
stub_status;
}
}
应用 allow 和 deny 指令爱护指标
如果您不心愿强制受权用户登录,并且您晓得他们用于拜访指标的 IP 地址,另一个选项是应用 allow 指令。您能够指定独自的 IPv4 和 IPv6 地址以及 CIDR 范畴。deny all 指令将阻止来自任何其余地址的拜访。
server {
listen 80;
server_name example.com;
location = /basic_status {
allow 192.168.1.0/24;
allow 10.1.1.0/16;
allow 2001:0db8::/32;
allow 96.1.2.23/32;
deny all;
stub_status;
}
}
两种办法相结合
如果咱们想联合应用这两种办法怎么办?咱们能够容许客户端在没有明码的状况下从特定地址拜访指标,但来自不同地址的客户端依然须要登录。为此,咱们应用 satisfy any 指令。它通知 NGINX 容许应用 HTTP 根本身份验证凭证登录或应用预批准的 IP 地址登录的客户端拜访。为了进步安全性,您能够将 satisfy 设置为 all,要求来自特定地址的人登录。
server {
listen 80;
server_name monitor.example.com;
location = /basic_status {
satisfy any;
auth_basic“closed site”;
auth_basic_user_file conf.d/.htpasswd;
allow 192.168.1.0/24;
allow 10.1.1.0/16;
allow 2001:0db8::/32;
allow 96.1.2.23/32;
deny all;
stub_status;
}
}
对于 NGINX Plus,您能够应用雷同的技术来限度拜访 NGINX Plus API 端点(在以下示例中为 http://monitor.example.com:80…)以及 http://monitor.example.com/da… 上的实时流动监控仪表盘。
在没有明码的状况下,此配置只容许来自 96.1.2.23/32 网络或本地主机的客户端拜访。因为指令是在 server{} 级别定义的,因而雷同的限度同时利用于 API 和仪表板。附带阐明一下,api 的 write=on 参数意味着这些客户端也能够应用 API 进行配置更改。
无关配置 API 和仪表盘的更多信息,请参阅《NGINX Plus 管理员指南》。
server {
listen 8080;
server_name monitor.example.com;
satisfy any;
auth_basic“closed site”;
auth_basic_user_file conf.d/.htpasswd;
allow 127.0.0.1/32;
allow 96.1.2.23/32;
deny all;
location = /api/ {api write=on;}
location = /dashboard.html {root /usr/share/nginx/html;}
}
谬误 9:当所有流量都来自同一个 /24 CIDR 块时应用 ip_hash
ip_hash 算法基于客户端 IP 地址的哈希值,在 upstream{} 块中的服务器间进行流量负载平衡。哈希键是 IPv4 地址或整个 IPv6 地址的前三个八位字节。该办法建设会话持久性,这意味着来自客户端的申请始终传递到同一服务器,除非该服务器不可用。
假如咱们已将 NGINX 部署为虚构专用网络中的反向代理(按高可用性配置)。咱们在 NGINX 前端搁置了各种防火墙、路由器、四层负载均衡器和网关,以承受来自不同起源(外部网络、合作伙伴网络和 Internet 等)的流量,并将其传递给 NGINX 以反向代理到上游服务器。以下是 NGINX 的初始配置:
http {
upstream {
ip_hash;
server 10.10.20.105:8080;
server 10.10.20.106:8080;
server 10.10.20.108:8080;
}
server {# …}
}
但事实证明存在一个问题:所有“拦挡”设施都位于同一个 10.10.0.0/24 网络上,因而对于 NGINX 来说,看起来所有流量都来自该 CIDR 范畴内的地址。请记住,ip_hash 算法会散列 IPv4 地址的前三个八位字节。在咱们的部署中,每个客户端的前三个八位字节都是雷同的(都为 10.10.0),因而它们的哈希值也都是雷同的,没法将流量调配到不同服务器。
解决办法是在哈希算法中应用 $binary_remote_addr 变量作为哈希键。该变量捕捉残缺的客户端地址,将其转换为二进制示意,IPv4 地址为 4 个字节,IPv6 地址为 16 个字节。当初,每个拦挡设施的哈希值都不同,负载平衡可失常进行。
咱们还增加了 consistent 参数以应用 ketama 哈希办法而不是默认值。这大大减少了在服务器集更改时从新映射到不同上游服务器的键的数量,为缓存服务器带来了更高的缓存命中率。
http {
upstream {
hash $binary_remote_addr consistent;
server 10.10.20.105:8080;
server 10.10.20.106:8080;
server 10.10.20.108:8080;
}
server {# …}
}
谬误 10:未采纳上游组
假如您在最简略的用例中应用 NGINX,作为监听端口 3000 的单个基于 NodeJS 的后端利用的反向代理。常见的配置可能如下所示:
http {
server {
listen 80;
server_name example.com;
location / {
proxy_set_header Host $host;
proxy_pass http://localhost:3000/;
}
}
}
非常简单,对吧?proxy_pass 指令通知 NGINX 客户端向哪里发送申请。NGINX 须要做的就是将主机名解析为 IPv4 或 IPv6 地址。建设连贯后,NGINX 将申请转发给该服务器。
这里的谬误是,假设只有一台服务器(因而没有理由配置负载平衡),因而不须要创立 upstream{} 块。事实上,一个 upstream{} 块会解锁几项有助于进步性能的个性,如以下配置所示:
http {
upstream node_backend {
zone upstreams 64K;
server 127.0.0.1:3000 max_fails=1 fail_timeout=2s;
keepalive 2;
}
server {
listen 80;
server_name example.com;
location / {
proxy_set_header Host $host;
proxy_pass http://node_backend/;
proxy_next_upstream error timeout http_500;
}
}
}
zone 指令建设一个共享内存区,主机上的所有 NGINX worker 过程都能够拜访无关上游服务器的配置和状态信息。几个上游组 能够共享该内存区。对于 NGINX Plus,该区域还反对您应用 NGINX Plus API 更改上游组中的服务器和单个服务器的设置,而无需重启 NGINX。无关详细信息,请参阅《NGINX Plus 治理指南》。
server 指令有几个参数可用来调整服务器行为。在本示例中,咱们扭转了 NGINX 用以确定服务器不衰弱,因而没有资格承受申请的条件。此处,只有通信尝试在每个 2 秒期间失败一次(而不是默认的在 10 秒期间失败一次),就会认为服务器不衰弱。
咱们联合应用此设置与 proxy_next_upstream 指令,配置在什么状况下 NGINX 会认为通信尝试失败,在这种状况下,它将申请传递到上游组中的下一个服务器。在默认谬误和超时条件中,咱们增加了 http_500,以便 NGINX 认为来自上游服务器的 HTTP 500 (Internal Server Error)代码示意尝试失败。
keepalive 指令设置每个 worker 过程缓存中保留的上游服务器的闲暇 keepalive 连贯的数量。咱们曾经在“谬误 3:未启用与上游服务器的 keepalive 连贯”中探讨了这样做的益处。
在 NGINX Plus 中,您还能够配置与上游组 无关的其余性能:
-
上文提到了 NGINX 开源版仅在启动时将服务器主机名解析为 IP 地址一次。server 指令的 resolve 参数可能反对 NGINX Plus 监控与上游服务器的域名对应的 IP 地址的变动,并主动批改上游配置而无需重新启动。
service 参数进一步反对 NGINX Plus 应用 DNS SRV 记录,其中包含无关端口号、权重和优先级的信息。这对于通常动态分配服务端口号的微服务环境十分重要。
无关解析服务器地址的更多信息,请参阅咱们的博文“NGINX 和 NGINX Plus 应用 DNS 进行服务发现”。
- server 指令的 slow_start 参数反对 NGINX Plus 逐步减少发送到早先被认为是衰弱且可用于承受申请的服务器的申请量。这能够避免申请激增,防止服务器不堪重负,进而导致再次失败。
- queue 指令容许 NGINX Plus 在无奈抉择上游服务器来解决申请时将申请放入队列中,而不是立刻向客户端返回谬误。
资源
- Gixy,GitHub 上的 NGINX 配置剖析工具
- NGINX Amplify,包含 Analyzer 工具
如欲试用 NGINX Plus,请立刻下载 30 天收费试用版,或与咱们分割以探讨您的用例。
更多资源
想要更及时全面地获取 NGINX 相干的技术干货、互动问答、系列课程、流动资源?
请返回 NGINX 开源社区:
- 官网:https://www.nginx.org.cn/
- 微信公众号:https://mp.weixin.qq.com/s/XV…
- 微信群:https://www.nginx.org.cn/stat…
- B 站:https://space.bilibili.com/62…