Nginx 访问日志分析:用几行命令看懂流量
访问日志不只是「记录下来」,稍微配一下格式,再用几行 awk,就能看出站点的大部分问题。
一、先把格式配好
默认的 combined 格式信息不够,建议加上耗时:
log_format main escape=json
'{
"time":"$time_iso8601",
"remote_addr":"$remote_addr",
"request":"$request",
"status": "$status",
"body_bytes_sent":"$body_bytes_sent",
"request_time":"$request_time",
"upstream_response_time":"$upstream_response_time",
"http_referrer":"$http_referer",
"http_user_agent":"$http_user_agent",
"http_x_forwarded_for":"$http_x_forwarded_for"
}';
access_log /var/log/nginx/access.log main;JSON 格式的好处是能用 jq 精确处理:
tail -1 /var/log/nginx/access.log | jq .
# 找出所有超过 1 秒的请求
jq -select(.request_time > 1) /var/log/nginx/access.log不想改格式的话,用默认的也能分析,只是字段位置要数一下。
二、默认格式的字段位置
# combined 格式:
# 1.2.3.4 - - [19/Feb/2026:10:00:01 +0800] "GET /path HTTP/1.1" 200 1234 "-" "Mozilla/5.0"
# $1 $2 $3 $4 $5 $6 $7 $8 $9 $10 $11...用 awk 时:
| 内容 | awk 变量 |
|---|---|
| IP | $1 |
| 请求行 | $6 $7 $8(合并后) |
| 状态码 | $9 |
| 字节数 | $10 |
三、常用统计
LOG=/var/log/nginx/access.log
# 总 PV
wc -l < $LOG
# 独立 IP 数(UV 近似)
awk '{print $1}' $LOG | sort -u | wc -l
# TOP 20 IP
awk '{print $1}' $LOG | sort | uniq -c | sort -rn | head -20
# TOP 20 被请求的 URL
awk '{print $7}' $LOG | sort | uniq -c | sort -rn | head -20
# 状态码分布
awk '{print $9}' $LOG | sort | uniq -c | sort -rn
# 只看 4xx/5xx
awk '$9 >= 400 {print $9, $7}' $LOG | sort | uniq -c | sort -rn | head -20
# 404 有哪些(找出坏链接)
awk '$9 == 404 {print $7}' $LOG | sort | uniq -c | sort -rn | head -20
# 流量总量(字节)
awk '{s += $10} END {print s/1024/1024 " MB"}' $LOG
# 按小时看请求量
awk '{print substr($4, 14, 2)}' $LOG | sort | uniq -c四、找慢请求
如果用了带 $request_time 的格式:
# 最慢的 20 个请求
awk '{print $NF, $7}' $LOG | sort -rn | head -20
# 超过 1 秒的请求数占比
awk '{if ($NF > 1) slow++; total++} END {print slow "/" total}' $LOG
# 按 URL 平均耗时
awk '{t[$7] += $NF; c[$7]++} END {for (u in t) printf "%.3f %s\n", t[u]/c[u], u}' $LOG \
| sort -rn | head -20JSON 格式的话更清晰:
jq -r "select(.request_time > 1) | [.request_time, .status, .request] | @tsv" $LOG \
| sort -rn | head -20五、识别异常访问
# 单 IP 请求数异常高(可能是爬虫或攻击)
awk '{print $1}' $LOG | sort | uniq -c | sort -rn | awk '$1 > 1000'
# 扫目录的特征:大量 404 且路径含敏感词
awk '$9 == 404 {print $1}' $LOG | sort | uniq -c | sort -rn | head -10
grep -E "wp-login|phpmyadmin|\.env|adminer|xmlrpc" $LOG | awk '{print $1}' | sort | uniq -c
# 看 User-Agent 有没有可疑的扫描器
awk -F\" '{print $6}' $LOG | sort | uniq -c | sort -rn | head -20
# 找 SQL 注入尝试的特征
grep -iE "union.*select|information_schema|sleep\(" $LOG | head -10发现异常 IP 后:
sudo ufw deny from 1.2.3.4
sudo fail2ban-client set sshd banip 1.2.3.4六、按天切割日志做对比
logrotate 已经按天切了,直接对比:
ls /var/log/nginx/access.log*
# 昨天 vs 今天的 PV
wc -l < /var/log/nginx/access.log.1
wc -l < /var/log/nginx/access.log
# 解压看更早的
zcat /var/log/nginx/access.log.2.gz | wc -l七、实时看
# 实时看请求(只看 URL 和状态码,清爽)
tail -f /var/log/nginx/access.log | awk '{print $7, $9}'
# 实时看非 200 的请求
tail -f /var/log/nginx/access.log | awk '$9 != 200 {print $1, $7, $9}'八、日志不用自己分析也行
如果嫌命令麻烦,这些工具能直接出图表:
| 工具 | 特点 |
|---|---|
| goaccess | 命令行实时 + 生成 HTML 报告,装上就能用 |
| Cloudflare Analytics | 零配置,看趋势够用 |
| Plausible / Umami | 自托管统计,注重隐私 |
sudo apt install -y goaccess
goaccess /var/log/nginx/access.log --log-format=COMBINED
# 生成一份 HTML 报告慢慢看
goaccess /var/log/nginx/access.log -o /tmp/report.html --log-format=COMBINED我自己的做法是:日常看 Cloudflare 面板,要排查具体问题时再上 awk。两个都备着最好用。
