Nginx日志格式自定义,记录访客UA与IP
Nginx默认的combined日志格式虽然包含了$remote_addr和$http_user_agent,但字段顺序固定、可读性一般,也不方便后续用脚本或日志系统提取分析。
通过log_format指令自定义格式,你可以把访客IP、UA、请求时间、状态码等关键信息按自己的需求排列,让日志更直观、更好用。
下面从配置到验证一步步说明。
先搞清楚要记录哪些字段
在动手改配置前,先确认你真正需要哪些变量。
Nginx内置了大量日志变量,常用的有:
$remote_addr:直接连接Nginx的客户端IP,存在CDN或反向代理时可能是代理IP$http_x_forwarded_for:经过代理时,记录原始客户端IP的请求头$http_user_agent:访客浏览器或客户端的User-Agent字符串$time_local:本地时间,格式如10/Oct/2024:14:30:00 +0800$request:完整的请求行,包含方法、URI和协议版本$status:HTTP响应状态码$body_bytes_sent:发送给客户端的响应体字节数$request_time:Nginx处理请求的总耗时,单位秒
如果你的网站前面套了CDN或负载均衡,$remote_addr拿到的会是CDN节点IP,此时需要结合$http_x_forwarded_for使用,具体在避坑部分会展开。
编辑Nginx配置文件定义日志格式
log_format指令必须写在http块内,不能写在server块里。
下面是宝塔面板和手动编译安装两种环境的操作路径。
宝塔面板环境:
- 登录宝塔后台,左侧菜单点击“网站”
- 找到目标站点,点击“设置”
- 选择“配置文件”,在
http段或server段之前插入log_format定义 - 修改
access_log指令引用新格式名
手动编译或apt/yum安装环境:
打开主配置文件,通常路径是/etc/nginx/nginx.conf,在http {}块内添加:
log_format detailed '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" '
'UA:"$http_user_agent" '
'XFF:"$http_x_forwarded_for"';
然后在站点的server块中,把原来的access_log改成引用这个格式:
server {
listen 80;
server_name example.com;
access_log /www/wwwlogs/example.com.log detailed;
location / {
root /www/wwwroot/example.com;
index index.html;
}
}
注意格式名detailed可以自定义,但必须与log_format定义的名字完全一致,大小写敏感。
让配置生效并验证日志输出
改完配置后,先测试语法再重载:
nginx -t
如果输出syntax is ok和test is successful,说明语法没问题,执行重载:
nginx -s reload
# 或使用 systemctl reload nginx
重载不会中断现有连接,可以放心操作。
随后触发一次访问,然后查看日志文件尾部:
tail -n 5 /www/wwwlogs/example.com.log
你应该能看到类似这样的记录:
203.0.113.45 - - [10/Oct/2024:15:20:31 +0800] "GET /index.html HTTP/1.1" 200 1024 "-" UA:"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36" XFF:"-"
如果UA:后面是-,说明请求头里没有User-Agent,常见于curl或脚本请求,属于正常现象。
几个容易踩的坑
坑一:log_format位置放错。 如果写在server块内,Nginx会报directive "log_format" is not allowed here。
必须放在http块内,且要在使用它的server块之前定义。
坑二:CDN场景下IP记录不准。 当网站接入CDN后,$remote_addr记录的是CDN回源IP,不是访客真实IP。
此时应优先使用$http_x_forwarded_for,但要注意这个头可以被伪造。
更稳妥的做法是在Nginx中配置set_real_ip_from和real_ip_header,让$remote_addr直接变成真实IP,具体以你使用的CDN厂商文档为准。
坑三:日志文件权限或路径问题。 如果重载后日志文件没有生成,检查access_log指定的目录是否存在、Nginx运行用户是否有写权限。
宝塔环境下日志目录通常是/www/wwwlogs/,手动安装可能是/var/log/nginx/。
坑四:格式字符串中的引号转义。 在Nginx配置里,格式字符串用单引号包裹,内部如果要用双引号,直接写"即可,不需要额外转义。
写成\"反而会多出反斜杠。
日志量大了怎么处理
自定义格式增加了UA和XFF字段后,单行日志会变长,磁盘占用和IO压力会上升。
如果站点访问量大,建议配合日志切割策略,比如logrotate每天轮转并压缩历史文件,同时评估是否需要把UA字段拆到独立日志或采样记录。
对于绝大多数中小站点,直接使用上述格式不会有明显负担,但定期清理旧日志仍然是必要的运维习惯。
常见疑问
修改后需要重启Nginx吗?
不需要。nginx -s reload即可平滑重载,新配置对后续请求立即生效。
为什么日志里UA字段显示为-?
说明该请求没有携带User-Agent头。用curl测试时默认会带UA,如果显示-,检查请求是否人为去掉了该头,或客户端本身是脚本工具。
可以在同一个server块里同时用两种日志格式吗?
可以。你可以在server块中写多条access_log指令,分别指向不同格式和不同文件,但要注意每条都会产生写入开销。
自定义格式会影响已有日志分析脚本吗?
会。字段顺序和内容变了,依赖固定列位置的awk或正则脚本需要同步调整。建议先在测试环境验证,再应用到生产。