Nginx 日志配置与管理
Logging Configuration and Management
概述
日志是监控Nginx服务器状态、分析访问模式、调试问题和安全审计的重要工具。Nginx提供了灵活的日志配置选项,包括访问日志、错误日志和自定义日志格式。本文将详细介绍Nginx日志系统的配置和管理方法。
1. 日志类型和基础概念
1.1 日志类型
Nginx日志类型:
├── 访问日志 (Access Log)
│ ├── HTTP请求记录
│ ├── 响应状态码
│ └── 请求处理时间
├── 错误日志 (Error Log)
│ ├── 系统错误
│ ├── 配置错误
│ └── 运行时错误
└── 自定义日志
├── 安全日志
├── 性能日志
└── 业务日志
1.2 日志级别
# 错误日志级别(从高到低)
debug # 调试信息(最详细)
info # 信息性消息
notice # 通知信息
warn # 警告信息
error # 错误信息
crit # 严重错误
alert # 需要立即处理的警报
emerg # 系统不可用(最严重)
2. 访问日志配置
2.1 基本访问日志配置
http {
# 默认日志格式
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
# 全局访问日志
access_log /var/log/nginx/access.log main;
server {
listen 80;
server_name example.com;
# 服务器级别的访问日志
access_log /var/log/nginx/example.com.access.log main;
location /api {
# 位置级别的访问日志
access_log /var/log/nginx/api.access.log main;
}
location /static {
# 禁用访问日志
access_log off;
}
}
}
2.2 自定义日志格式
http {
# 详细的访问日志格式
log_format detailed '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent" '
'$request_time $upstream_response_time '
'$upstream_addr $upstream_status '
'"$http_x_forwarded_for" "$http_x_real_ip"';
# JSON格式日志
log_format json escape=json '{'
'"timestamp":"$time_iso8601",'
'"remote_addr":"$remote_addr",'
'"remote_user":"$remote_user",'
'"request":"$request",'
'"status":$status,'
'"body_bytes_sent":$body_bytes_sent,'
'"http_referer":"$http_referer",'
'"http_user_agent":"$http_user_agent",'
'"request_time":$request_time,'
'"upstream_response_time":"$upstream_response_time"'
'}';
# 性能监控日志格式
log_format performance '$remote_addr [$time_local] "$request" '
'$status $body_bytes_sent '
'rt=$request_time '
'urt=$upstream_response_time '
'cs=$upstream_cache_status';
# 安全日志格式
log_format security '$remote_addr [$time_local] "$request" '
'$status "$http_user_agent" '
'"$http_x_forwarded_for" $request_length '
'$request_time $connection $connection_requests';
}
2.3 条件日志记录
http {
# 定义条件变量
map $status $log_condition {
~^[23] 0; # 2xx和3xx状态码不记录
default 1; # 其他状态码记录
}
map $request_uri $skip_log {
~*\.(js|css|png|jpg|jpeg|gif|ico|svg)$ 0;
default 1;
}
server {
listen 80;
server_name example.com;
# 条件日志记录 - 只记录错误
access_log /var/log/nginx/error_only.log main if=$log_condition;
# 条件日志记录 - 跳过静态文件
access_log /var/log/nginx/dynamic_only.log main if=$skip_log;
location /admin {
# 管理区域完整日志
access_log /var/log/nginx/admin.log detailed;
}
}
}
3. 错误日志配置
3.1 基本错误日志配置
# 全局错误日志
error_log /var/log/nginx/error.log warn;
http {
# HTTP级别错误日志
error_log /var/log/nginx/http_error.log;
server {
listen 80;
server_name example.com;
# 服务器级别错误日志
error_log /var/log/nginx/example.com.error.log;
location /api {
# 位置级别错误日志
error_log /var/log/nginx/api_error.log debug;
}
}
}
3.2 调试日志配置
# 开启调试日志(需要编译时支持)
error_log /var/log/nginx/debug.log debug;
events {
# 调试特定连接
debug_connection 192.168.1.100;
debug_connection 2001:db8::/32;
}
http {
server {
listen 80;
server_name debug.example.com;
# 调试特定服务器
error_log /var/log/nginx/debug_server.log debug;
location /debug {
# 输出调试信息到响应
add_header X-Debug-Info "Request processed";
return 200 "Debug mode enabled\n";
}
}
}
4. 日志轮转配置
4.1 使用logrotate进行日志轮转
# /etc/logrotate.d/nginx
/var/log/nginx/*.log {
daily # 每天轮转
missingok # 文件不存在不报错
rotate 52 # 保留52个文件
compress # 压缩旧文件
delaycompress # 延迟压缩
notifempty # 空文件不轮转
create 0640 nginx nginx # 创建新文件的权限
sharedscripts # 共享脚本
prerotate
if [ -d /etc/logrotate.d/httpd-prerotate ]; then \
run-parts /etc/logrotate.d/httpd-prerotate; \
fi \
endscript
postrotate
if [ -f /var/run/nginx.pid ]; then
kill -USR1 `cat /var/run/nginx.pid`
fi
endscript
}
4.2 自定义日志轮转脚本
#!/bin/bash
# /usr/local/bin/nginx-log-rotate.sh
LOG_DIR="/var/log/nginx"
BACKUP_DIR="/var/log/nginx/backup"
DATE=$(date +%Y%m%d)
# 创建备份目录
mkdir -p $BACKUP_DIR
# 移动当前日志文件
for log_file in $LOG_DIR/*.log; do
if [ -f "$log_file" ]; then
filename=$(basename "$log_file")
mv "$log_file" "$BACKUP_DIR/${filename}-${DATE}"
fi
done
# 发送USR1信号给nginx重新打开日志文件
if [ -f /var/run/nginx.pid ]; then
kill -USR1 $(cat /var/run/nginx.pid)
fi
# 压缩7天前的日志
find $BACKUP_DIR -name "*.log-*" -type f -mtime +7 -exec gzip {} \;
# 删除30天前的压缩日志
find $BACKUP_DIR -name "*.gz" -type f -mtime +30 -delete
echo "Log rotation completed at $(date)"
4.3 定时任务设置
# 添加到crontab
crontab -e
# 每天凌晨2点执行日志轮转
0 2 * * * /usr/local/bin/nginx-log-rotate.sh >> /var/log/log-rotate.log 2>&1
5. 日志分析和监控
5.1 实时日志监控
# 实时查看访问日志
tail -f /var/log/nginx/access.log
# 实时查看错误日志
tail -f /var/log/nginx/error.log
# 过滤特定状态码
tail -f /var/log/nginx/access.log | grep " 404 "
# 监控多个日志文件
multitail /var/log/nginx/access.log /var/log/nginx/error.log
5.2 日志分析脚本
#!/bin/bash
# nginx-log-analyzer.sh
LOG_FILE=${1:-/var/log/nginx/access.log}
echo "=== Nginx访问日志分析 ==="
echo "日志文件: $LOG_FILE"
echo "分析时间: $(date)"
echo
# 总请求数
total_requests=$(wc -l < $LOG_FILE)
echo "总请求数: $total_requests"
# 独立访客数(基于IP)
unique_visitors=$(awk '{print $1}' $LOG_FILE | sort | uniq | wc -l)
echo "独立访客: $unique_visitors"
# 最多访问的IP
echo -e "\n=== 访问最多的IP ==="
awk '{print $1}' $LOG_FILE | sort | uniq -c | sort -nr | head -10
# 最多访问的页面
echo -e "\n=== 访问最多的页面 ==="
awk '{print $7}' $LOG_FILE | sort | uniq -c | sort -nr | head -10
# 状态码统计
echo -e "\n=== HTTP状态码统计 ==="
awk '{print $9}' $LOG_FILE | sort | uniq -c | sort -nr
# 浏览器统计
echo -e "\n=== 浏览器统计 ==="
awk -F'"' '{print $6}' $LOG_FILE | sort | uniq -c | sort -nr | head -10
# 小时访问量统计
echo -e "\n=== 小时访问量统计 ==="
awk '{print $4}' $LOG_FILE | cut -c 14-15 | sort | uniq -c
5.3 使用GoAccess进行可视化分析
# 安装GoAccess
sudo apt install goaccess # Ubuntu/Debian
sudo yum install goaccess # CentOS/RHEL
# 生成HTML报告
goaccess /var/log/nginx/access.log -o /var/www/html/report.html --log-format=COMBINED
# 实时监控
goaccess /var/log/nginx/access.log -o /var/www/html/report.html --log-format=COMBINED --real-time-html
# 自定义日志格式
goaccess /var/log/nginx/access.log \
--log-format='%h %^[%d:%t %^] "%r" %s %b "%R" "%u"' \
--date-format='%d/%b/%Y' \
--time-format='%T' \
-o report.html
6. 性能优化
6.1 日志缓冲配置
http {
# 访问日志缓冲
access_log /var/log/nginx/access.log main buffer=64k flush=5s;
# 错误日志缓冲
error_log /var/log/nginx/error.log warn;
server {
listen 80;
server_name example.com;
# 高频访问的日志使用缓冲
access_log /var/log/nginx/example.com.access.log main
buffer=32k flush=10s;
location /api {
# API日志使用较大缓冲
access_log /var/log/nginx/api.access.log json
buffer=128k flush=30s;
}
}
}
6.2 异步日志记录
# 主配置文件
worker_processes auto;
worker_rlimit_nofile 65535;
events {
worker_connections 1024;
use epoll;
}
http {
# 使用异步I/O
aio on;
directio 512;
# 日志配置
access_log /var/log/nginx/access.log main buffer=64k flush=5s;
# 禁用不必要的日志
location ~* \.(js|css|png|jpg|jpeg|gif|ico)$ {
access_log off;
expires 1y;
}
}
7. 安全和审计日志
7.1 安全事件日志
http {
# 安全日志格式
log_format security '$remote_addr [$time_local] "$request" '
'$status $request_length $body_bytes_sent '
'"$http_referer" "$http_user_agent" '
'"$http_x_forwarded_for" $request_time';
# 地理位置映射
geoip_country /usr/share/GeoIP/GeoIP.dat;
geoip_city /usr/share/GeoIP/GeoLiteCity.dat;
# 可疑活动检测
map $request_method $suspicious_method {
default 0;
~*(TRACE|CONNECT|DEBUG) 1;
}
map $http_user_agent $suspicious_ua {
default 0;
~*sqlmap 1;
~*nikto 1;
~*scanner 1;
}
server {
listen 80;
server_name example.com;
# 记录可疑活动
if ($suspicious_method) {
access_log /var/log/nginx/security.log security;
}
if ($suspicious_ua) {
access_log /var/log/nginx/security.log security;
}
# 404错误特别记录
location @notfound {
access_log /var/log/nginx/404.log security;
return 404;
}
}
}
7.2 访问控制日志
http {
# 访问控制日志格式
log_format access_control '$remote_addr [$time_local] "$request" '
'$status "$rule_matched" "$action_taken"';
server {
listen 80;
server_name example.com;
# 管理区域访问控制
location /admin {
allow 192.168.1.0/24;
allow 10.0.0.0/8;
deny all;
access_log /var/log/nginx/admin_access.log access_control;
# 记录拒绝的访问
error_page 403 @access_denied;
}
location @access_denied {
access_log /var/log/nginx/access_denied.log security;
return 403 "Access Denied";
}
}
}
8. 日志集中化管理
8.1 使用rsyslog发送日志
# 配置nginx发送日志到syslog
error_log syslog:server=192.168.1.100:514,facility=local0,tag=nginx,severity=error;
access_log syslog:server=192.168.1.100:514,facility=local0,tag=nginx main;
# /etc/rsyslog.d/nginx.conf
# 接收来自nginx的日志
local0.* /var/log/nginx/centralized.log
# 转发到远程日志服务器
*.* @@log-server.example.com:514
8.2 使用Fluentd收集日志
# /etc/fluent/conf.d/nginx.conf
<source>
@type tail
path /var/log/nginx/access.log
pos_file /var/log/fluentd/nginx-access.log.pos
tag nginx.access
format nginx
</source>
<source>
@type tail
path /var/log/nginx/error.log
pos_file /var/log/fluentd/nginx-error.log.pos
tag nginx.error
format /^(?<time>\d{4}/\d{2}/\d{2} \d{2}:\d{2}:\d{2}) \[(?<log_level>\w+)\] (?<message>.*)$/
</source>
<match nginx.**>
@type elasticsearch
host elasticsearch.example.com
port 9200
index_name nginx-logs
</match>
9. 故障排除
9.1 日志问题诊断
# 检查日志目录权限
ls -la /var/log/nginx/
# 检查nginx进程运行用户
ps aux | grep nginx
# 检查磁盘空间
df -h /var/log
# 检查inode使用情况
df -i /var/log
# 测试日志轮转
sudo logrotate -d /etc/logrotate.d/nginx
9.2 常见问题解决
# 日志文件权限问题
sudo chown nginx:nginx /var/log/nginx/*.log
sudo chmod 640 /var/log/nginx/*.log
# 日志目录不存在
sudo mkdir -p /var/log/nginx
sudo chown nginx:nginx /var/log/nginx
# 重新打开日志文件
sudo nginx -s reopen
# 检查SELinux设置
sudo setsebool -P httpd_can_network_connect 1
sudo restorecon -R /var/log/nginx
10. 监控和告警
10.1 日志监控脚本
#!/bin/bash
# nginx-log-monitor.sh
LOG_FILE="/var/log/nginx/access.log"
ERROR_LOG="/var/log/nginx/error.log"
ALERT_EMAIL="admin@example.com"
# 检查4xx错误数量
error_4xx_count=$(tail -1000 $LOG_FILE | grep -c " 4[0-9][0-9] ")
if [ $error_4xx_count -gt 50 ]; then
echo "High 4xx error rate: $error_4xx_count" | mail -s "Nginx Alert" $ALERT_EMAIL
fi
# 检查5xx错误数量
error_5xx_count=$(tail -1000 $LOG_FILE | grep -c " 5[0-9][0-9] ")
if [ $error_5xx_count -gt 10 ]; then
echo "High 5xx error rate: $error_5xx_count" | mail -s "Nginx Critical Alert" $ALERT_EMAIL
fi
# 检查响应时间
avg_response_time=$(tail -1000 $LOG_FILE | awk '{print $NF}' | awk '{sum+=$1; count++} END {print sum/count}')
if (( $(echo "$avg_response_time > 2.0" | bc -l) )); then
echo "High response time: $avg_response_time" | mail -s "Nginx Performance Alert" $ALERT_EMAIL
fi
10.2 使用Prometheus监控
# prometheus.yml配置
scrape_configs:
- job_name: 'nginx'
static_configs:
- targets: ['localhost:9113']
scrape_interval: 5s
# nginx配置添加状态页面
server {
listen 8080;
server_name localhost;
location /nginx_status {
stub_status on;
access_log off;
allow 127.0.0.1;
deny all;
}
}
小结
通过本文的学习,你应该掌握:
- Nginx日志系统的基本概念和类型
- 访问日志和错误日志的配置方法
- 自定义日志格式和条件日志记录
- 日志轮转和归档管理
- 日志分析和监控技巧
- 性能优化和安全审计
- 集中化日志管理方案
- 常见问题的诊断和解决
下一篇文章将介绍Nginx的反向代理配置。