1. Access Log 與 Error Log
Nginx 有兩種主要的日誌類型來監控伺服器活動:Access log(記錄所有請求)和 Error log(記錄錯誤和警告)。
1.1. Access Log
Access log 記錄伺服器收到的每個請求,包含用戶端資訊、請求內容、回應狀態和處理時間。
預設位置:
# Ubuntu/Debian /var/log/nginx/access.logCentOS/RHEL
/var/log/nginx/access.log
macOS (Homebrew)
/usr/local/var/log/nginx/access.log
基本設定:
http { # 整個 HTTP context 的 access log access_log /var/log/nginx/access.log;server { listen 80; server_name example.com; # 虛擬主機的獨立 access log access_log /var/log/nginx/example.com.access.log; location / { root /var/www/html; } # 關閉特定 location 的 access log location /health-check { access_log off; return 200 "OK\n"; } }
}
預設格式(combined):
192.168.1.100 - - [03/Dec/2024:10:30:45 +0700] "GET /index.html HTTP/1.1" 200 1234 "https://google.com" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
欄位說明:
192.168.1.100- 用戶端 IP 位址-- 遠端使用者(通常無認證時為-)-- 已驗證的使用者[03/Dec/2024:10:30:45 +0700]- 時間戳記"GET /index.html HTTP/1.1"- 請求方法、URI 和 HTTP 版本200- HTTP 狀態碼1234- 回應主體大小(bytes)"https://google.com"- Referer"Mozilla/5.0..."- User Agent
1.2. Error Log
Error log 記錄 Nginx 產生的錯誤、警告和除錯資訊。
預設位置:
/var/log/nginx/error.log
日誌層級(由少到多):
emerg- 緊急:系統無法使用alert- 警報:必須立即採取行動crit- 嚴重狀態error- 錯誤狀態warn- 警告狀態notice- 正常但重要的事件info- 資訊debug- 除錯訊息
設定:
# 全域 error log error_log /var/log/nginx/error.log warn;http { # HTTP 層級的 error log error_log /var/log/nginx/http-error.log error;
server { listen 80; server_name example.com; # Server 層級的 error log error_log /var/log/nginx/example.com.error.log error; # 疑難排解用 debug log error_log /var/log/nginx/debug.log debug; }
}
Error log 範例:
2024/12/03 10:30:45 [error] 1234#1234: *1 open() "/var/www/html/notfound.html" failed (2: No such file or directory), client: 192.168.1.100, server: example.com, request: "GET /notfound.html HTTP/1.1", host: "example.com"2024/12/03 10:31:20 [warn] 1234#1234: *2 upstream server temporarily disabled while connecting to upstream, client: 192.168.1.101, server: api.example.com, request: "GET /api/users HTTP/1.1", upstream: "http://192.168.1.200:3000/api/users"
2024/12/03 10:32:05 [crit] 1234#1234: malloc() 8192 bytes failed (12: Cannot allocate memory)
1.3. 即時查看與監控日誌
# 查看 access log sudo tail -f /var/log/nginx/access.log查看 error log
sudo tail -f /var/log/nginx/error.log
查看最後 100 行
sudo tail -n 100 /var/log/nginx/access.log
同時查看兩個日誌
sudo tail -f /var/log/nginx/access.log /var/log/nginx/error.log
過濾日誌
sudo tail -f /var/log/nginx/access.log | grep "404" sudo tail -f /var/log/nginx/access.log | grep "192.168.1.100"
用 less 查看日誌(可滾動)
sudo less +F /var/log/nginx/access.log
1.4. 基本日誌分析
計算總請求數:
# 總請求數 wc -l /var/log/nginx/access.log過去一小時的請求
sudo awk -v date="$(date -d '1 hour ago' '+%d/%b/%Y:%H')" '$4 > "["date' /var/log/nginx/access.log | wc -l
前 10 個 IP:
sudo awk '{print $1}' /var/log/nginx/access.log | sort | uniq -c | sort -rn | head -10
存取次數最多的前 10 個 URL:
sudo awk '{print $7}' /var/log/nginx/access.log | sort | uniq -c | sort -rn | head -10
HTTP 狀態碼統計:
sudo awk '{print $9}' /var/log/nginx/access.log | sort | uniq -c | sort -rn
前 10 個 User Agent:
sudo awk -F'"' '{print $6}' /var/log/nginx/access.log | sort | uniq -c | sort -rn | head -10
每小時請求數:
sudo awk '{print $4}' /var/log/nginx/access.log | cut -d: -f1-2 | sort | uniq -c
2. 自訂記錄格式
Nginx 允許您建立自訂記錄格式,只收集您需要的資訊。
2.1. 基本記錄格式
定義格式:
http { # 預設格式(combined) log_format combined '$remote_addr - $remote_user [$time_local] ' '"$request" $status $body_bytes_sent ' '"$http_referer" "$http_user_agent"';# 簡單格式 log_format simple '$remote_addr - $request - $status'; # 詳細格式 log_format detailed '$remote_addr - $remote_user [$time_local] ' '"$request" $status $body_bytes_sent ' '"$http_referer" "$http_user_agent" ' 'rt=$request_time uct="$upstream_connect_time" ' 'uht="$upstream_header_time" urt="$upstream_response_time"'; server { listen 80; # 使用自訂格式 access_log /var/log/nginx/access.log detailed; }
}
2.2. 常用變數
用戶端資訊:
$remote_addr # 用戶端 IP
$remote_user # HTTP 認證使用者
$http_x_forwarded_for # 透過代理/CDN 的真實 IP
請求資訊:
$time_local # 本地時間
$time_iso8601 # ISO 8601 格式時間
$request # 完整請求行
$request_method # GET、POST 等
$request_uri # 含參數的請求 URI
$uri # 當前 URI
$args # 查詢字串參數
$query_string # 同 $args
$scheme # http 或 https
$server_protocol # HTTP/1.1、HTTP/2.0
$host # Host 標頭
$server_name # 伺服器名稱
回應資訊:
$status # HTTP 狀態碼
$body_bytes_sent # 回應主體大小
$bytes_sent # 總傳送位元組(標頭 + 主體)
$request_length # 請求長度(含標頭)
時間資訊:
$request_time # 請求處理時間(秒)
$upstream_response_time # 後端回應時間
$upstream_connect_time # 連線到上游的時間
$upstream_header_time # 接收上游標頭的時間
上游資訊:
$upstream_addr # 上游伺服器位址
$upstream_status # 上游回應狀態
$upstream_cache_status # 快取狀態(HIT、MISS 等)
標頭:
$http_user_agent # User-Agent 標頭
$http_referer # Referer 標頭
$http_cookie # Cookie 標頭
$http_<header_name> # 任意 HTTP 標頭(小寫加底線)
2.3. 實際記錄格式範例
效能監控格式:
log_format performance '$remote_addr - [$time_local] "$request" ' '$status $body_bytes_sent ' 'rt=$request_time ' 'uct=$upstream_connect_time ' 'uht=$upstream_header_time ' 'urt=$upstream_response_time';
server { listen 80; access_log /var/log/nginx/performance.log performance; }
輸出:
192.168.1.100 - [03/Dec/2024:10:30:45 +0700] "GET /api/users HTTP/1.1" 200 1234 rt=0.125 uct=0.005 uht=0.050 urt=0.120
JSON 格式(易於解析):
log_format json_combined escape=json '{' '"time_local":"$time_local",' '"remote_addr":"$remote_addr",' '"request":"$request",' '"status":$status,' '"body_bytes_sent":$body_bytes_sent,' '"request_time":$request_time,' '"http_referer":"$http_referer",' '"http_user_agent":"$http_user_agent"' '}';
server { listen 80; access_log /var/log/nginx/access.json json_combined; }
輸出:
{"time_local":"03/Dec/2024:10:30:45 +0700","remote_addr":"192.168.1.100","request":"GET /index.html HTTP/1.1","status":200,"body_bytes_sent":1234,"request_time":0.005,"http_referer":"https://google.com","http_user_agent":"Mozilla/5.0"}
安全性監控格式:
log_format security '$remote_addr - [$time_local] ' '"$request" $status ' '"$http_user_agent" ' '"$http_x_forwarded_for" ' 'host=$host ' 'args=$args';
server { listen 80; access_log /var/log/nginx/security.log security; }
CDN/代理格式:
log_format cdn '$http_x_forwarded_for - $remote_addr - $remote_user [$time_local] ' '"$request" $status $body_bytes_sent ' '"$http_referer" "$http_user_agent" ' 'cache=$upstream_cache_status';
server { listen 80; access_log /var/log/nginx/cdn.log cdn; }
2.4. 條件式記錄
只在條件成立時記錄:
http { # 定義 map 來確認條件 map $status $loggable { ~^[23] 0; # 不記錄 2xx 和 3xx default 1; # 其他全部記錄 }server { listen 80; # 只在 $loggable = 1 時記錄 access_log /var/log/nginx/errors-only.log combined if=$loggable; }
}
不記錄靜態檔案:
map $request_uri $log_static { ~*.(jpg|jpeg|png|gif|ico|css|js)$ 0; default 1; }
server { listen 80; access_log /var/log/nginx/access.log combined if=$log_static; }
不記錄健康檢查:
map $request_uri $log_health { ~^/health$ 0; ~^/ping$ 0; default 1; }
server { listen 80; access_log /var/log/nginx/access.log combined if=$log_health; }
不記錄機器人:
map $http_user_agent $log_bots { ~bot 0; ~crawler 0; ~*spider 0; default 1; }
server { listen 80; access_log /var/log/nginx/access.log combined if=$log_bots; }
2.5. 多個 Access Log
server { listen 80; server_name example.com;# 記錄所有請求 access_log /var/log/nginx/all.log combined; # 只記錄錯誤 access_log /var/log/nginx/errors.log combined if=$loggable; # 效能記錄 access_log /var/log/nginx/performance.log performance; # 用於處理的 JSON 記錄 access_log /var/log/nginx/json.log json_combined;
}
3. 使用 Logrotate 進行日誌輪替
日誌檔案可能成長得非常快。日誌輪替透過自動壓縮和刪除舊日誌來管理磁碟空間。
3.1. Logrotate 基本
預設設定檔:
# Ubuntu/Debian /etc/logrotate.d/nginxCentOS/RHEL
/etc/logrotate.d/nginx
預設內容:
/var/log/nginx/*.log {
daily
missingok
rotate 14
compress
delaycompress
notifempty
create 0640 www-data adm
sharedscripts
postrotate
if [ -f /var/run/nginx.pid ]; then
kill -USR1 cat /var/run/nginx.pid
fi
endscript
}
指令說明:
daily- 每天輪替missingok- 日誌不存在時不報錯rotate 14- 保留 14 個備份compress- 用 gzip 壓縮舊日誌delaycompress- 延到下次輪替才壓縮notifempty- 檔案為空時不輪替create 0640 www-data adm- 以指定權限建立新檔案sharedscripts- 所有日誌只執行一次 postrotate 腳本postrotate/endscript- 輪替後執行的腳本
3.2. 自訂 Logrotate 設定
每小時輪替(高流量網站):
sudo nano /etc/logrotate.d/nginx-hourly內容:
/var/log/nginx/high-traffic.log { hourly rotate 168 # 7天 × 24小時 compress delaycompress notifempty create 0640 www-data adm dateext dateformat -%Y%m%d-%H sharedscripts postrotate if [ -f /var/run/nginx.pid ]; then kill -USR1cat /var/run/nginx.pidfi endscript }
依大小輪替:
/var/log/nginx/.log {
size 100M # 達到 100MB 時輪替
rotate 10
compress
delaycompress
notifempty
create 0640 www-data adm
sharedscripts
postrotate
if [ -f /var/run/nginx.pid ]; then
kill -USR1 cat /var/run/nginx.pid
fi
endscript
}
自訂命名輪替:
/var/log/nginx/.log { daily rotate 30 compress delaycompress notifempty create 0640 www-data adm dateext dateformat -.%Y-%m-%d extension .log sharedscripts postrotate if [ -f /var/run/nginx.pid ]; then kill -USR1cat /var/run/nginx.pidfi endscript }輸出: access.log-2024-12-03.log.gz
各日誌分開輪替:
# 效能日誌 - 保存較久 /var/log/nginx/performance.log { daily rotate 90 # 3個月 compress delaycompress notifempty create 0640 www-data adm }錯誤日誌 - 保存非常久
/var/log/nginx/error.log { weekly rotate 52 # 1年 compress delaycompress notifempty create 0640 www-data adm }
Access log - 快速輪替
/var/log/nginx/access.log { daily rotate 7 # 1週 compress delaycompress notifempty create 0640 www-data adm }
3.3. 測試與強制輪替
# 測試設定(模擬執行) sudo logrotate -d /etc/logrotate.d/nginx強制輪替(立即執行)
sudo logrotate -f /etc/logrotate.d/nginx
查看狀態
sudo cat /var/lib/logrotate/status
手動輪替(不使用 logrotate)
sudo mv /var/log/nginx/access.log /var/log/nginx/access.log.1 sudo nginx -s reopen sudo gzip /var/log/nginx/access.log.1
3.4. Logrotate 疑難排解
確認 logrotate 是否在執行:
# 確認 cron 作業 ls -la /etc/cron.daily/logrotate確認 logrotate 狀態
sudo cat /var/lib/logrotate/status | grep nginx
以詳細模式手動執行 logrotate
sudo logrotate -v /etc/logrotate.d/nginx
常見錯誤:
# 錯誤: Permission denied修正: 確認擁有者
ls -la /var/log/nginx/ sudo chown www-data:adm /var/log/nginx/*.log
錯誤: Nginx 未重新開啟日誌
修正: 確認 PID 檔案
ls -la /var/run/nginx.pid sudo systemctl restart nginx
錯誤: 日誌未被壓縮
修正: 確認 gzip 已安裝
which gzip sudo apt install gzip
4. 監控的基本指標
4.1. 每秒請求數(RPS)
計算 RPS 的腳本:
#!/bin/bashrps.sh - 計算 RPS
LOG_FILE="/var/log/nginx/access.log" INTERVAL=60 # 秒
while true; do START_COUNT=$(wc -l < "$LOG_FILE") sleep $INTERVAL END_COUNT=$(wc -l < "$LOG_FILE")
REQUESTS=$((END_COUNT - START_COUNT)) RPS=$(echo "scale=2; $REQUESTS / $INTERVAL" | bc) echo "$(date '+%Y-%m-%d %H:%M:%S') - RPS: $RPS"
done
執行腳本:
chmod +x rps.sh
./rps.sh
4.2. 回應時間分析
分析回應時間的腳本:
#!/bin/bashresponse_time.sh - 分析回應時間
LOG_FILE="/var/log/nginx/access.log"
echo "回應時間統計:" echo "=============="
擷取 request_time(假設已記錄)
awk '{print $NF}' "$LOG_FILE" |
awk '{ sum += $1; count++; if ($1 > max) max = $1; if (min == 0 || $1 < min) min = $1; } END { print "平均: " sum/count " 秒"; print "最小: " min " 秒"; print "最大: " max " 秒"; }'
4.3. 狀態碼分佈
#!/bin/bashstatus_codes.sh - 統計 HTTP 狀態碼
LOG_FILE="/var/log/nginx/access.log"
echo "HTTP 狀態碼分佈:" echo "=================="
awk '{print $9}' "$LOG_FILE" | sort | uniq -c | sort -rn |
while read count code; do percentage=$(echo "scale=2; ($count * 100) / $(wc -l < $LOG_FILE)" | bc) printf "%3s: %6d 個請求 (%5.2f%%)\n" "$code" "$count" "$percentage" done
4.4. 每小時流量
#!/bin/bashtraffic_by_hour.sh - 分析每小時流量
LOG_FILE="/var/log/nginx/access.log"
echo "每小時流量:" echo "============"
awk '{print $4}' "$LOG_FILE" | cut -d: -f2 | sort | uniq -c |
while read count hour; do printf "第 %02d 時: %6d 個請求\n" "$hour" "$count" done
4.5. 最多請求的用戶端(IP 位址)
#!/bin/bashtop_clients.sh - 找出請求最多的用戶端
LOG_FILE="/var/log/nginx/access.log" TOP_N=10
echo "前 $TOP_N 個用戶端:" echo "===================="
awk '{print $1}' "$LOG_FILE" | sort | uniq -c | sort -rn | head -n $TOP_N |
while read count ip; do printf "%15s: %6d 個請求\n" "$ip" "$count" done
4.6. 頻寬使用量
#!/bin/bashbandwidth.sh - 計算頻寬使用量
LOG_FILE="/var/log/nginx/access.log"
echo "頻寬統計:" echo "=========="
假設 $body_bytes_sent 在第 10 個欄位
awk '{sum += $10} END { gb = sum / 1024 / 1024 / 1024; mb = sum / 1024 / 1024; kb = sum / 1024; printf "合計: %.2f GB (%.2f MB, %.2f KB)\n", gb, mb, kb; }' "$LOG_FILE"
4.7. 即時儀表板腳本
#!/bin/bashdashboard.sh - Nginx 即時監控儀表板
LOG_FILE="/var/log/nginx/access.log"
while true; do clear echo "=======================================" echo " NGINX 監控儀表板" echo "=======================================" echo "時間:$(date '+%Y-%m-%d %H:%M:%S')" echo
# 總請求數 TOTAL=$(wc -l < "$LOG_FILE") echo "總請求數:$TOTAL" echo echo "最近 ~1000 個請求" echo # 狀態碼(最近 1000 筆) echo "狀態碼(最近):" tail -n 1000 "$LOG_FILE" | awk '{print $9}' | sort | uniq -c | sort -rn echo # 前 5 個 IP(最近) echo "前 5 個 IP(最近):" tail -n 1000 "$LOG_FILE" | awk '{print $1}' | sort | uniq -c | sort -rn | head -5 echo # 前 5 個 URL(最近) echo "前 5 個 URL(最近):" tail -n 1000 "$LOG_FILE" | awk '{print $7}' | sort | uniq -c | sort -rn | head -5 sleep 5
done
執行儀表板:
chmod +x dashboard.sh
./dashboard.sh
4.8. 發生問題時傳送警示
#!/bin/bashalert.sh - 錯誤率過高時傳送警示
LOG_FILE="/var/log/nginx/access.log" ERROR_THRESHOLD=10 # 5xx 錯誤百分比 EMAIL="[email protected]"
統計最近 100 筆請求
TOTAL=$(tail -n 100 "$LOG_FILE" | wc -l) ERRORS=$(tail -n 100 "$LOG_FILE" | awk '{print $9}' | grep "^5" | wc -l)
ERROR_RATE=$(echo "scale=2; ($ERRORS * 100) / $TOTAL" | bc)
if (( $(echo "$ERROR_RATE > $ERROR_THRESHOLD" | bc -l) )); then MESSAGE="警示:偵測到高錯誤率!${ERROR_RATE}% 的請求為 5xx 錯誤" echo "$MESSAGE" | mail -s "Nginx 警示" "$EMAIL" echo "$MESSAGE" fi
4.9. 與監控工具整合
匯出 Prometheus 指標:
# 安裝 nginx-prometheus-exporter wget https://github.com/nginxinc/nginx-prometheus-exporter/releases/download/v0.11.0/nginx-prometheus-exporter_0.11.0_linux_amd64.tar.gz tar xzf nginx-prometheus-exporter_0.11.0_linux_amd64.tar.gz sudo mv nginx-prometheus-exporter /usr/local/bin/執行 exporter
nginx-prometheus-exporter -nginx.scrape-uri=http://localhost:8080/stub_status
設定 Nginx stub_status:
server { listen 8080; server_name localhost;location /stub_status { stub_status; access_log off; allow 127.0.0.1; deny all; }
}
5. 實作練習
練習1:自訂記錄格式
- 建立名為
timing的自訂記錄格式,包含:- 遠端位址
- 請求
- 狀態
- 請求時間
- 上游回應時間
- 將此格式套用到虛擬主機
- 產生流量並查看日誌
練習2:JSON 記錄
- 建立 JSON 記錄格式
- 設定 Nginx 以 JSON 格式記錄
- 用
jq解析 JSON 日誌:
cat /var/log/nginx/access.json | jq '.status'
cat /var/log/nginx/access.json | jq 'select(.status >= 400)'
練習3:日誌輪替
- 建立達到 10MB 時輪替的自訂 logrotate 設定
- 用
logrotate -d測試 - 強制輪替並驗證
練習4:流量分析
- 用
ab產生 1000 個請求:
ab -n 1000 -c 10 http://localhost/
- 分析日誌找出:
- 總請求數
- 平均回應時間
- 狀態碼分佈
- 最多存取的 URL
練習5:即時監控
- 設定儀表板腳本
- 修改腳本新增:
- 錯誤率(%)
- 頻寬使用量
- 最慢的請求
練習6:條件式記錄
- 設定不記錄以下內容:
- 靜態檔案(.css、.js、.jpg、.png)
- 健康檢查端點(/health)
- 機器人流量
- 驗證這些請求不出現在日誌中
6. 使用日誌進行疑難排解
6.1. 除錯 404 錯誤
# 找出所有 404 grep " 404 " /var/log/nginx/access.log造成 404 的前幾個 URL
grep " 404 " /var/log/nginx/access.log | awk '{print $7}' | sort | uniq -c | sort -rn | head -10
來自特定 IP 的 404
grep "192.168.1.100" /var/log/nginx/access.log | grep " 404 "
6.2. 除錯 500 錯誤
# 找出 5xx 錯誤 grep " 50[0-9] " /var/log/nginx/access.log查看 error log 取得詳細資訊
sudo tail -100 /var/log/nginx/error.log | grep "error"
各時段的 5xx 錯誤
grep " 50[0-9] " /var/log/nginx/access.log | awk '{print $4}' | cut -d: -f1-2 | uniq -c
6.3. 除錯慢速請求
# 找出超過 1 秒的請求(假設 request_time 已記錄) awk '$NF > 1.0' /var/log/nginx/access.log最慢的前 10 個請求
awk '{print $NF, $7}' /var/log/nginx/access.log | sort -rn | head -10
6.4. 除錯高流量
# 每分鐘請求數 awk '{print $4}' /var/log/nginx/access.log | cut -d: -f1-3 | uniq -c找出流量尖峰
awk '{print $4}' /var/log/nginx/access.log | cut -d: -f1-3 | uniq -c | awk '$1 > 1000'
6.5. 除錯安全性問題
# 找出 SQL 注入嘗試 grep -i "select.*from|union.*select" /var/log/nginx/access.log找出路徑遍歷嘗試
grep ".." /var/log/nginx/access.log
可疑的 User Agent
grep -i "sqlmap|nikto|nmap" /var/log/nginx/access.log
7. 最佳實踐
7.1. 日誌管理
- 各虛擬主機分開記錄:
server {
server_name site1.com;
access_log /var/log/nginx/site1.access.log;
error_log /var/log/nginx/site1.error.log;
}
- 使用適當的日誌層級:
# 正式環境:error 或 warn error_log /var/log/nginx/error.log warn;開發環境:info 或 debug
error_log /var/log/nginx/error.log debug;
- 不要過度記錄:
# 靜態檔案停用 location ~* .(jpg|jpeg|png|gif|ico|css|js)$ { access_log off; }健康檢查停用
location /health { access_log off; return 200; }
7.2. 效能
- 緩衝日誌:
access_log /var/log/nginx/access.log combined buffer=32k;
- 非同步記錄(Nginx 1.7.11+):
access_log /var/log/nginx/access.log combined buffer=32k flush=5s;
7.3. 安全性
- 保護日誌檔案:
sudo chmod 640 /var/log/nginx/.log
sudo chown www-data:adm /var/log/nginx/.log
- 定期輪替:
# 高流量網站每天輪替低流量網站每週輪替
- 監控並設定警示:
# 設定錯誤率監控異常尖峰時傳送警示
總結
在本課中,您學到了:
- ✅ Access log 與 error log
- ✅ 自訂記錄格式與變數
- ✅ 使用 logrotate 進行日誌輪替
- ✅ 日誌分析與指標
- ✅ 使用日誌進行疑難排解
- ✅ 記錄的最佳實踐
下一課:我們將探討反向代理——如何將 Nginx 用作後端應用程式的反向代理。