Nginx 的 access log 天天在写,多数人从来不看。其实攻击、爬虫、慢接口全在里面,只是没解析而已。这篇用手册的方式讲怎么从日志里快速捞出有用的东西,命令都是直接能跑的。
先确认日志在哪
默认路径是 /var/log/nginx/access.log,但很多站按域名拆了,看 nginx.conf 里 access_log 指令指向哪:
grep -r "access_log" /etc/nginx/ | grep -v "#"
如果日志被 logrotate 切了,目录里会有 access.log.1、access.log.2.gz 这类历史文件,分析长周期数据时记得一起带上。
日志字段先认全
| 字段 | 含义 | 重点看什么 |
|---|---|---|
| IP | 访客来源地址 | 同 IP 高频访问=爬虫或攻击 |
| 时间 | 请求时刻 | 半夜集中=非真人行为 |
| 状态码 | 200/404/5xx 等 | 大量 4xx=扫描,5xx=后端问题 |
| 请求行 | 方法+路径 | wp-admin、.env 等敏感路径 |
| 响应时间 | $request_time | 慢请求定位唯一依据 |
注意:默认日志格式不一定带响应时间,需要确认 http_log_format 里有没有 $request_time,没有的话手动加上再 reload。
三分钟定位恶意爬虫
爬虫最明显的特征是单 IP 请求量爆表、UA 千篇一律、路径高度重复。一条命令看访问量前 10 的 IP:
awk '{print $1}' /var/log/nginx/access.log | sort | uniq -c | sort -rn | head -10
再看这些 IP 都在刷什么路径,如果集中打 wp-login.php、xmlrpc.php、.env 这类敏感文件,基本可以确认是扫描器。处理方式:Nginx 层直接 return 403,或上 fail2ban 按 IP 封禁,之前写过完整的 Fail2ban 配置指南,可以对照着来。
揪出拖慢网站的慢接口
日志格式里带 $request_time 的话,慢请求一秒定位:
awk '{print $(NF-1), $0}' /var/log/nginx/access.log | sort -rn | head -20
把前 20 条里的路径归类,通常你会发现就那么两三个接口在拖后腿——要么是没加索引的 SQL,要么是上游慢。比对着 MySQL 慢查询日志一起看,根因就出来了。
状态码分布一眼扫
awk '{print $9}' /var/log/nginx/access.log | sort | uniq -c | sort -rn
正常站 200 占比 90% 以上。如果 404 特别多,检查是不是有人拿扫描器在探路径;如果 502/504 扎堆,那是后端 PHP-FPM 或上游服务的问题,往那个方向查。
慢请求与攻击的特征对比
| 特征 | 正常流量 | 爬虫/攻击 |
|---|---|---|
| 请求频率 | 分散,符合人浏览习惯 | 单 IP 每秒几十上百 |
| 路径 | 文章页、首页为主 | wp-login、.env、后台接口 |
| 状态码 | 200 为主 | 403/404/5xx 密集 |
| 请求时间 | 白天均匀 | 凌晨集中 |
常见问题
Q:日志太大,awk 跑不动?
A:先 gzip 的历史日志不用解压,用 zcat 直接读:zcat access.log.2.gz | awk …。再不行就按时间段切小再分析。
Q:发现扫描 IP 怎么处理最快?
A:Nginx 加一段 location 直接拒绝,或者装 fail2ban 让它自动封。手封 IP 记得写进白名单,别把自己封了。
Q:日志里看不到响应时间?
A:默认 combined 格式没有 $request_time,去 nginx.conf 里加一个自定义 log_format,把 $request_time 放进去,reload 之后新日志就有。
日志分析是排查问题最快的一条路,有任何命令或字段看不懂的,欢迎来 fenij.com 留言。