Web 服务器日志分析实战:GoAccess 与命令行

Web 服务器日志分析是每一个运维和开发者都绕不开的基本功。每天你的 Nginx、Apache 都在默默记录着每一次请求:谁来了、看了什么、返回了什么状态码、花了多久。本文用 GoAccess 与一行行的命令行,带你把原始日志变成可执行的洞察——看清流量、揪出异常、拦住攻击。

一、为什么日志分析是运维基本功

日志是系统最诚实的”监控摄像头”。访问量暴涨时,它能告诉你哪个接口被刷;安全事件发生时,它能还原攻击者踩点的路径;性能抖动时,它能定位最慢的那 1% 请求。与其等用户投诉,不如每天花十分钟看一眼日志。本文聚焦 Web 访问日志(access log)的分析,不展开采集管道——如果你需要统一采集多台机器,可以回顾 Fluentd 日志采集实战。

二、先认识 Nginx 的默认日志格式

Nginx 默认使用 combined 格式,每一行包含 9 个字段。理解字段含义是后续一切分析的前提。如果你用的是反向代理,建议参考 Nginx 反向代理完整配置 把真实客户端 IP($http_x_forwarded_for)也记下来。

log_format  main  '$remote_addr - $remote_user [$time_local] '
                  '"$request" '
                  '$status $body_bytes_sent '
                  '"$http_referer" "$http_user_agent" '
                  '$request_time $upstream_response_time';

其中 $request_time 是请求总耗时,$upstream_response_time 是后端处理耗时,两者差值能暴露网络或代理开销。下面所有命令行示例都假设日志位于 /var/log/nginx/access.log。

三、命令行三板斧:awk / grep / sort

在装任何工具之前,先掌握三条命令。它们零依赖、随取随用,适合写进排障脚本。

3.1 找出访问最频繁的 IP

awk '{print $1}' /var/log/nginx/access.log \
  | sort | uniq -c | sort -nr | head -20

3.2 统计状态码分布

awk '{print $9}' /var/log/nginx/access.log \
  | sort | uniq -c | sort -nr

3.3 列出最慢的 10 个请求

awk '{print $NF, $7, $1}' /var/log/nginx/access.log \
  | sort -nr | head -10

下表是日常最常用的一组成熟命令,建议存进 dotfiles 或脚本库随时调用。

目标核心命令说明
Top IPawk '{print $1}' | sort | uniq -c | sort -nr识别爬虫与刷量
404 清单awk '$9==404 {print $7}' | sort | uniq -c | sort -nr排查死链
5xx 趋势awk '$9>=500 {print $7}'后端报错定位
爬虫 UAawk -F'"' '{print $6}' | sort | uniq -c分析搜索引擎

四、用 GoAccess 做实时可视化

命令行适合一次性排查,但要看趋势、做汇报,还是需要可视化。GoAccess 是一个单文件、零外部依赖的实时日志分析器,能直接在终端显示面板,也能导出成自包含的 HTML 仪表盘。

4.1 安装与终端实时面板

# Debian / Ubuntu
sudo apt-get install -y goaccess

# 实时跟踪日志(终端交互面板)
goaccess /var/log/nginx/access.log \
  --log-format=COMBINED \
  --real-time-html

4.2 生成可分享的 HTML 报告

goaccess /var/log/nginx/access.log \
  --log-format=COMBINED \
  --output=report.html \
  --ignore-panel=GEO_LOCATION

生成的 report.html 自带访客地图、热门页面、操作系统、浏览器、状态码、小时维度趋势等面板,发给团队或贴到内网即可。注意:报告含原始访问数据,不要公开到公网。

五、从日志里抓异常与攻击

攻击者通常会先用自动化工具扫描漏洞。这些行为在日志里特征极其明显:大量 404、奇奇怪怪的 URL、可疑的 User-Agent。下面几条命令能快速筛出高危信号。

# 1. 路径遍历 / SQL 注入 探测
grep -Ei '(\.\./|union select|or 1=1|/etc/passwd|\$&|<script)' \
  /var/log/nginx/access.log | awk '{print $1, $7}'

# 2. 单 IP 短时间高频 404(疑似扫描器)
awk '$9==404 {print $1}' /var/log/nginx/access.log \
  | sort | uniq -c | sort -nr | awk '$1>200'

# 3. 异常 User-Agent(空 UA、sqlmap、nmap、nikto 等)
awk -F'"' '$6 ~ /(sqlmap|nikto|masscan|^-?$|python-requests)/ {print $1}' \
  /var/log/nginx/access.log
攻击特征日志中的表现应对
目录遍历URL 含 ../、/etc/passwdNginx 拒绝、WAF 规则
SQL 注入含 union select、or 1=1参数化查询 + 限流
扫描器UA 为 sqlmap/nikto,单 IP 海量 404Fail2ban 封禁
CC 攻击单 IP QPS 异常高Nginx 限流

六、慢请求与性能洞察

性能问题往往藏在长尾里。配合前面开启的 $request_time,可以找出拖慢整体体验的接口,再结合 PostgreSQL 慢查询优化 一起定位是网络、代理还是数据库慢。

# 找出 request_time 大于 1 秒、且占比较高的请求
awk '$NF > 1.0 {print $NF, $7, $1}' /var/log/nginx/access.log \
  | sort -nr | head -30

# 统计各接口平均耗时(需要 gawk 支持数组)
awk '{url[$7]+=$NF; cnt[$7]++} END \
  {for (u in url) printf "%.3f %s\n", url[u]/cnt[u], u}' \
  /var/log/nginx/access.log | sort -nr | head -15

七、把日志分析写进自动化

手动看日志不可持续。把分析脚本放进定时任务或 CI,每天自动产出报告,才是”可运营”的做法。下面用一段 cron 脚本每天生成并归档报告,容器化部署时日志路径参考 Docker 编排实战 的 volume 挂载。

#!/usr/bin/env bash
# /usr/local/bin/daily_log_report.sh
LOG=/var/log/nginx/access.log
OUT=/var/www/reports/$(date +%F).html

goaccess "$LOG" --log-format=COMBINED --output="$OUT"

# 找出当日高危 IP,写入告警文件
awk '$9==404 {print $1}' "$LOG" \
  | sort | uniq -c | sort -nr | awk '$1>500' \
  > /tmp/suspect_ips.txt

[ -s /tmp/suspect_ips.txt ] && \
  mail -s "Nginx 日志告警 $(date +%F)" admin@example.com < /tmp/suspect_ips.txt

在 crontab 中加入 0 8 * * * /usr/local/bin/daily_log_report.sh 即可每天早 8 点自动跑。需要把报告推送到对象存储或内网看板时,也可封装成 GitHub Actions 工作流 触发。

八、落地清单

阶段动作产出
接入确认 log_format 含 $request_time、X-Forwarded-For可分析日志
日常awk/grep 三板斧排查异常即时洞察
可视GoAccess 生成 HTML 报告趋势看板
防护Fail2ban + Nginx 限流拦截扫描降低风险
自动cron / CI 每日报告可持续运营

八、日志轮转与归档(logrotate)

日志不是只增不减。如果不做轮转,单文件会无限膨胀直至打满磁盘,而磁盘满又会让 Nginx、数据库连锁故障。Linux 自带 logrotate,按天或按大小切割、压缩、保留 N 份。下面是一段可直接落地的 Nginx 配置。

/var/log/nginx/*.log {
    daily
    missingok
    rotate 14
    compress
    delaycompress
    notifempty
    create 0640 www-data adm
    sharedscripts
    postrotate
        [ -f /var/run/nginx.pid ] && kill -USR1 $(cat /var/run/nginx.pid)
    endscript
}

daily 表示每天轮转,rotate 14 保留 14 天,compress 启用 gzip 压缩以省空间。关键是用 kill -USR1 通知 Nginx 重新打开日志文件,否则它会一直写已被改名、实则已删除的旧文件。磁盘与 inode 相关排障可参考磁盘空间耗尽实战。

九、容器与云原生环境的日志

到了 Docker 与 Kubernetes,日志从”文件”变成了”标准输出”。容器引擎默认用 json-file 驱动把 stdout/stderr 写成 JSON 文件,位置在 /var/lib/docker/containers/。查看某个容器日志:

# 查看容器最近 100 行日志
docker logs --tail 100 <container_id>

# 跟随实时日志
docker logs -f <container_id>

# 限制日志体积,避免打满磁盘(daemon.json)
{
  "log-driver": "json-file",
  "log-opts": { "max-size": "10m", "max-file": "3" }
}

9.1 Kubernetes 下的日志聚合

在 K8s 里 Pod 会漂移、会重建,本地日志不可靠,必须集中收集。常用方案是 DaemonSet 形式的采集器(如 Fluent Bit)把每个节点上的容器日志转发到 Elasticsearch 或 Loki。排障时先用 kubectl logs 看单 Pod,再上聚合平台看全局趋势。

# 查看 Pod 当前日志
kubectl logs <pod-name> -n <namespace> --tail=200

# 查看上一个已崩溃容器的日志(排障必备)
kubectl logs <pod-name> -p -n <namespace>

容器化部署与日志挂载的完整实践见 Docker 编排实战。把”本地看一眼”升级为”平台统一看”,是日志分析从手工迈向工程化的关键一步。

十、小结

Web 服务器日志分析不需要昂贵的平台,从一行 awk 到 GoAccess 仪表盘,再到定时自动化,是一条平滑的进阶路线。关键是养成”每天看一眼日志”的习惯——绝大多数线上故障和安全事件,都能在日志里找到最早的征兆。把今天的命令存进你的工具箱,下次排障你会感谢现在的自己。

上一篇 SSH 连接故障排查实战:超时、拒绝与 host key 变更
下一篇 Java AQS 实战:用 AbstractQueuedSynchronizer 手写可重入锁
最新评论
Docker 网络模式详解:bridge/host 生产选型 - FSData
Docker 网络模式详解:bridge/host 生产选型 - FSData
8月20日
[…] 注意最后那条:把端口绑定到 127.0.0.1,再由宿主机上的 Nginx 反代进来,比直接 -p 80:80 暴露安全得多,也方便统一做
Vue3 + TypeScript 工程化:类型安全的前端架构 - FSData
Vue3 + TypeScript 工程化:类型安全的前端架构 - FSData
8月20日
[…] Pinia 的工程化用法,可以参考我们之前的实战文章 《Vue3 组合式 API + Pinia:状态管理从入门到实战》,那里覆盖了 Sto
2026 年最值得装的 10 个 VS Code 插件(AI/前端/后端/效率全覆盖) - FSData
2026 年最值得装的 10 个 VS Code 插件(AI/前端/后端/效率全覆盖) - FSData
8月19日
[…] 状态,点一下就能起停容器,配合我们讲过的 Docker Compose 编排 […]
Redis 缓存设计:穿透、击穿、雪崩与最佳实践 - FSData
Redis 缓存设计:穿透、击穿、雪崩与最佳实践 - FSData
8月19日
[…] 缓存三大坑的本质都是”缓存失效导致请求穿透到数据库”。记住口诀:穿透用布隆、击穿用锁、雪崩用错峰。配合合理的过期策略
GitHub Actions 实战:从零搭建 CI/CD 流水线 - FSData
GitHub Actions 实战:从零搭建 CI/CD 流水线 - FSData
8月19日
[…] Docker 镜像部署。结合我们之前写的 Docker Compose 一键编排实战,可以在 CI […]