Nginx 是最常用的网页服务器之一,并已成为现代企业架构的重要组成部分。在这篇文章里,我们会看看简化监控、提高性能和加强安全的配置选项——最终增强您基础设施的韧性。
图片由 Taylor Vick 拍摄,来自 Unsplash
JSON 日志JSON 是 Nginx 日志文件的一个非常好的格式,有以下两个原因。首先,它更易于阅读。其次,将日志传输到 OpenSearch 等系统以进行进一步监控或 SIEM 处理变得更加简单。
这里有一个简单的 nginx.conf 示例:
log_format json-logger escape=json '{
"type": "访问日志条目",
"time": "$time_iso8601",
"远端IP": "$remote_addr",
"X-Forwarded-For": "$proxy_add_x_forwarded_for",
"请求ID": "$request_id",
"请求长度": "$request_length",
"响应字节数": "$bytes_sent",
"响应体大小": "$body_bytes_sent",
"状态码": "$status",
"虚拟主机": "$host",
"协议": "$server_protocol",
"路径": "$uri",
"查询字符串": "$args",
"请求耗时": "$request_time",
"后端响应时间": "$upstream_response_time",
"后端状态码": "$upstream_status",
"请求方法": "$request_method",
"Referer": "$http_referer",
"User-Agent": "$http_user_agent",
"活动连接数": "$connections_active"
}';
access_log /var/log/nginx/access.log json-logger;
这导致了以下内容出现在 access.log 文件中:
{
"type": "访问日志条目",
"time": "2025-02-25T16:02:54+00:00",
"remote-ip": "130.61.78.239",
"x-forward-for": "X-Forwarded-For",
"request-id": "38750f2a1a51b196fa0a76025b0d1be9",
"request-length": "258",
"response-bytes": "353",
"response-body-size": "响应体大小",
"status": "404",
"vhost": "3.69.78.187",
"protocol": "HTTP/1.1",
"path": "/lib/phpunit/Util/PHP/eval-stdin.php",
"query": "",
"duration": "0.016",
"backend-duration": "0.016",
"backend-status": "404",
"method": "GET",
"referer": "",
"user-agent": "Custom-AsyncHttpClient",
"active-connections": "活动连接数"
}
请求参数设置
较大的请求体大小、较长的超时时间和过长的长连接(KeepAlive)设置会显著影响性能。为了优化效率,尽量将这些参数设得小一些——但仍要满足应用程序的需求。
来自nginx.conf
的一个例子:
client_max_body_size 10M; # 设置客户端请求的最大大小为10MB
client_body_timeout 10s; # 设置客户端请求体超时时间为10秒
client_header_timeout 10s; # 设置客户端请求头超时时间为10秒
keepalive_timeout 5s 5s; # 设置keep-alive连接超时时间为5秒,分别针对客户端和服务端
**client_max_body_size**
定义了客户端发送 HTTP 请求正文的最大允许大小。如果超过限制,Nginx 会返回 413 Request Entity Too Large 错误。
**client_body_timeout**
设定Nginx等待完整请求数据的最大时限。如果在此时间内仍未收到完整的请求数据,连接将会被关闭。
**client_header_timeout**
设置Nginx等待客户端发送完整HTTP头的最长等待时间。如果超时,连接将被关闭。
**keepalive_timeout**
定义了在最后一个请求之后,连接保持开启的时间长度。第一个值(例如 5s
)设置了超时时间。并将此建议发送给客户端,建议保持连接开启的时间长度。
如果客户端试图通过发送大量请求来淹没 web 服务器,Nginx 提供了配置“限制请求的数量区域”的选项,可以根据不同的参数限制请求的流量。
这里有个例子(反向代理,并设置了请求速率限制):
限制请求区域 $binary_remote_addr 区域=限制请求区域byaddr:20m 率=15r/s;
限制请求状态 429;
上游 app.localhost {
服务器 localhost:8080;
}
服务器 {
监听 443 ssl;
服务器名称 app.devlab.intern;
位置 / {
限制请求 区域=限制请求区域byaddr 突增=10;
代理传递 http://app.localhost;
}
}
**$binary_remote_addr**
配置一个基于IP地址的请求限制,以限制每个IP地址的请求次数。
**zone=limitreqsbyaddr:20m**
创建一个名为 limitreqsbyaddr
的共享内存区域,大小为 20 MB,。这个区域用来存储不同 IP 地址的限速数据。
**请求速率=15r/s**
限制每个IP每秒最多15个请求。如果客户端超过此限制,超出的请求将被拒绝。
**limit_req_status 429;**
当请求速率超出限制时,返回 429 请求过多 状态码,表示在设定的时间段内请求次数太多。
这种设置有助于防止这些服务遭受恶意使用和过载。
仅限必要的HTTP请求类型,以满足功能需求在我看来,将允许的HTTP方法限制为仅必要的或支持的方法是使得web服务器设置与应用程序(比如REST API)同步的一种干净方式。这不仅有助于防止API滥用或使用不必要的HTTP方法,还还能阻止像TRACE这样的潜在危险HTTP请求。此外,这样还能避免不必要的服务器负载,通过消除不支持或无关的HTTP请求。
# HEAD 隐含
limit_except GET {
拒绝所有;
}
另一个允许所有方法的示例,不过不包括 Trace 和 Patch 方法。
如果 $request_method 相等于 ^(PATCH|TRACE)$ {
则返回 405;
}
简单的防机器人措施
如果发现机器人或者配置不当的扫描器——它们通常带有会话式的用户代理——我们就可以制造最大的混乱,通过返回Nginx的一个内部HTTP状态。要做到这一点,我们会在 /etc/nginx/snippets
目录下创建一个名叫 bot.protection.conf
的文件,并添加以下内容:
# 将一些已知的恶意爬虫工具的User-Agent添加到黑名单中
map $http_user_agent $blacklist_user_agents {
~*wpscan 1;
~*dirbuster 1;
~*gobuster 1;
}
当然可以根据需要随时添加条目。在 VHost 的配置中,可以按照如下方式加载文件:
# 不翻译代码段,保持原样
例如:
include /etc/nginx/snippets/bot.protection.conf; # 包含防爬虫保护配置文件
if ($blacklist_user_agents) { # 如果用户代理在黑名单中
return 444; # 返回444状态码,关闭连接
}
HTTP 444 有时也被认为是“有趣的”,在猜测某些常见文件(例如 .env)时:
# 类型为 <your-domain>/.bash_history 的请求可能返回 HTTP 444。
location ~ /\. {
return 444
}
HTTP 444 究竟是什么意思?
HTTP 444 是一个非标准的状态码,指示 NGINX 服务器在不发送响应头的情况下关闭连接。它最常用于拒绝恶意或格式不正确的请求。使用此状态码的一个有趣副作用是,一些扫描程序无法正确处理此状态码,从而增加了额外的安全防护层。
启用TCP快速连接TCP 快速连接是 Nginx 中的一项重要增强功能,提供了一种更高效的建立 TCP 连接的方法。此功能允许在初始握手阶段传输数据,显著加快了连接速度。它特别有助于减少延迟并优化性能,尤其是在高延迟的网络条件下。
你可以通过运行命令行来验证你的 Linux 内核是否支持这个 tcp_fastopen 选项。
cat /proc/sys/net/ipv4/tcp_fastopen # 查看 tcp 快速打开设置
返回值为1表示已开启,否则直接运行:
echo 1 > /proc/sys/net/ipv4/tcp_fastopen
你现在可以按照以下方式使用这些设置:
通过以下方法:(via)
listen [::]:443 ssl http2 fastopen=500;
监听 443 ssl http2 fastopen=500;
或者更自然的表达可以是:
监听 [::]:443 ssl http2 fastopen=500;
监听 443 ssl http2 fastopen=500;
gZIP 压缩。
GZip是一种数据压缩方法,它通过减小文件大小来实现压缩。通过解压(或称为“解压缩”)压缩文件,可以完全恢复原始数据。
对于网页和网站应用来说,GZip 压缩很重要,因为 HTTP 支持在数据发送前进行压缩。
当 GZip 启用时,提供的文件大小会变小。这意味着带宽使用减少,从而使得网站托管和内容分发的成本降低。访客同样也会受益,因为他们下载的文件较小,页面加载速度会更快。
配置示例:
开启gzip;
设置gzip压缩类型 text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;