如何读取 Nginx 访问日志
当出现问题时,访问日志会讲述一个故事。谁访问了网站。他们请求了什么。哪些 URL 失败了。何时开始出现高峰。我在一个真实项目上使用了这些步骤,它们很有效。下面的示例可以安全地复制和运行,然后根据您的设置进行调整。
什么是 Nginx 访问日志?
Nginx 访问日志是文本文件,记录您的 Web 服务器收到的每个 HTTP 请求。每一行代表一个请求,并包含客户端 IP 地址、时间戳、HTTP 方法、URL 路径、状态码、响应大小等详细信息。
这些日志由 Nginx 在处理请求时自动生成。每次有人访问您的网站、点击链接、提交表单,甚至访问损坏的 URL 时,Nginx 都会向访问日志写入一行。这是实时发生的,因此日志文件会不断增长。
访问日志如何工作
Nginx 使用在 nginx.conf 文件中定义的、可配置的日志格式。默认格式如下所示:
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent"';
这将创建如下日志条目:
192.168.1.100 - - [20/Aug/2025:10:30:45 +0000] "GET /blog/post HTTP/1.1" 200 1234 "https://example.com/" "Mozilla/5.0..."
许多现代设置使用更详细的类似 JSON 的格式,其中包含键值对,这正是本文示例所假设的。
CDN 与源站:在哪里查找日志
如果您正在使用 CDN(如 Cloudflare、CloudFront 或 Fastly),则需要考虑两组不同的日志:
CDN 边缘日志:显示实际用户访问 CDN 的请求。这些日志包含真实的客户端 IP、用户代理和地理位置。
源站服务器日志(本文涵盖的内容):显示通过 CDN 到达您的 Nginx 服务器的请求。这些日志通常显示 CDN 的 IP 地址作为客户端,而不是最终用户的 IP。
对于故障排除,您通常首先需要 CDN 日志。仅当您需要查看实际到达服务器的内容或调试服务器端问题时,才应检查源站日志。
所有示例都假定使用键值日志(字段如 status="404" 和 request="GET /path HTTP/1.1"),并且文件位于 /var/log/nginx/ 下。请根据需要调整名称。
您将学到什么
- 如何一次性读取实时和压缩的日志
- 如何查找热门 IP 和热门失败 URL
- 如何提取单个 IP 的所有内容
- 如何缩放到一个短时间窗口
- 如何将访问日志与 WAF 阻止关联起来
- 如何保持结果快速且有用
快速入门
读取所有内容,无论文件是 .log 还是 .gz:
zgrep -h . /var/log/nginx/ssl-*.access.log*
这个 zgrep 技巧可以处理普通文件和轮换压缩的文件。之后添加过滤器。
您将使用的工具
zgrep:类似于 grep,但适用于普通文件和压缩(.gz)文件。非常适合轮换和压缩的日志文件。
awk:一个强大的文本处理工具,可以按分隔符分割行并提取特定字段。非常适合解析结构化的日志格式。
cut:从文本中提取特定的列或字段。使用 -d 指定分隔符(如引号或逗号),使用 -f 选择您想要的字段编号。
查找 404 风暴背后的热门 IP
当编辑报告“大量损坏的链接”时,从这里开始。
zgrep -h . /var/log/nginx/ssl-*.access.log* \
| awk -F'status="' '$2 ~ /^404"/' \
| awk -F'x_forwarded_for="' '{print $2}' \
| cut -d'"' -f1 | cut -d',' -f1 \
| LC_ALL=C sort | uniq -c | sort -nr | head
为什么它有帮助。您首先看到最严重的违规者。如果一个 IP 在扫描随机路径,您会很快发现它。
查看单个 IP 的所有操作
当您需要解释一个 IP 的阻止或高峰时很有用。
IP="112.134.209.112"
zgrep -h . /var/log/nginx/ssl-*.access.log* \
| grep -F 'x_forwarded_for="'$IP
提示。在某些堆栈中,客户端 IP 可能位于 src 或 src_ip 中。如果是这样,请在 grep 中交换字段名称。
该 IP 访问的热门 URL(忽略查询字符串)
IP="112.134.209.112"
zgrep -h . /var/log/nginx/ssl-*.access.log* \
| grep -F 'x_forwarded_for="'$IP \
| awk -F'request="' '{print $2}' | cut -d'"' -f1 \
| awk '{print $2}' | cut -d'?' -f1 \
| LC_ALL=C sort | uniq -c | sort -nr | head
为什么它有帮助。删除查询字符串会将“具有不同参数的相同页面”分组在一起,从而使模式显而易见。
按状态查找热门失败 URL
404:
zgrep -h . /var/log/nginx/ssl-*.access.log* \
| awk -F'status="' '$2 ~ /^404"/' \
| awk -F'request="' '{print $2}' | cut -d'"' -f1 \
| awk '{print $2}' | cut -d'?' -f1 \
| LC_ALL=C sort | uniq -c | sort -nr | head
5xx:
zgrep -h . /var/log/nginx/ssl-*.access.log* \
| awk -F'status="' '{split($2,a,"\""); if (a[1] ~ /^5[0-9][0-9]$/) print}' \
| awk -F'request="' '{print $2}' | cut -d'"' -f1 \
| awk '{print $2}' | cut -d'?' -f1 \
| LC_ALL=C sort | uniq -c | sort -nr | head
为什么它有帮助。这为您提供了一个问题路径的排名列表。修复前五个通常可以解决大部分问题。
缩放到一个短时间窗口
当已知时间出现高峰时,您需要查看之前和之后的情况。
简单快捷(足以查看同一小时内的 10 分钟窗口):
# 示例:09/Aug/2025 23:15–23:25
zgrep -h 'time_local="' /var/log/nginx/ssl-*.access.log* \
| egrep '09/Aug/2025:23:1[5-9]|09/Aug/2025:23:2[0-5]'
将结果通过管道传递到上面的任何计数命令中。
为什么它有帮助。您可以比较事件发生前后的流量,这通常是您需要了解发生了什么变化的所有信息。
表单提交和大型请求体
向表单发送大型 POST 请求可能会触发 WAF 规则。测量它们。
PATH_RE="/about/.*speaker-request-form"
zgrep -h . /var/log/nginx/ssl-*.access.log* \
| awk -F'request="' -v r="$PATH_RE" '
{ split($2,a,"\""); split(a[1],b," "); m=b[1]; u=b[2];
if (m=="POST" && u ~ r) print }' \
| awk -F'request_length="' '{print $2}' | cut -d'"' -f1 \
| awk '{sum+=$1; c++} END{print "POST count="c, "avg_request_length=" (c?sum/c:0)}'
为什么它有帮助。如果平均请求大小很高,您的 WAF 可能会阻止检查。现在您有了证据和数字。
将访问日志与 WAF 阻止关联起来
- 从您的 WAF 事件中获取确切的时间和规则。
- 使用“时间窗口”技巧过滤该窗口内的访问日志。
- 查找相同的路径、相同的 IP 或大型 request_length。
- 如果 WAF 规则涉及请求体大小或检查限制,请使用上面的 POST 分析进行确认。
这可以闭环。您可以说明发生了什么以及为什么会发生。
重要的速度提示
- 尽早过滤。在排序之前添加 grep 'status="404"'。
- 使用 LC_ALL=C sort 进行更快、更稳定的排序。
- 删除查询字符串以按路径对页面进行分组。
- 先采样。在管道上运行 head 以检查您是否切片了正确的字段。
- 在存储库中记录您的 log_format。未来的您会感谢您。
常见陷阱
- 当您的应用程序位于代理后面时,按 remote_addr 进行计数。使用 x_forwarded_for 或您的真实客户端 IP 字段。
- 假设所有日志文件都使用相同的格式。在解析之前检查您的 nginx.conf log_format。
- 忘记轮换的日志(.gz 文件)需要 zgrep,而不是 grep。
- 使用复杂的正则表达式模式,这些模式在日志格式更改时会中断。保持简单。
要点
日志可以快速回答实际问题。从一个清晰的问题开始,只通过您需要的内容,然后计数。将您在 Nginx 中看到的内容与您的 WAF 报告的内容联系起来。您将从“感觉有点慢”转变为“此 URL 在十分钟内从一个 IP 失败了 2,379 次,这是修复方法。”