返回博客

如何读取 Nginx 访问日志

2025-08-2012 min read

当出现问题时,访问日志会讲述一个故事。谁访问了网站。他们请求了什么。哪些 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 阻止关联起来

  1. 从您的 WAF 事件中获取确切的时间和规则。
  2. 使用“时间窗口”技巧过滤该窗口内的访问日志。
  3. 查找相同的路径、相同的 IP 或大型 request_length。
  4. 如果 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 次,这是修复方法。”

保持更新

在您的收件箱中获取最新的文章和见解。

Unsubscribe anytime. No spam, ever.