로그 설정과 분석
Nginx의 로그는 장애 원인 파악, 성능 분석, 보안 감사의 핵심 도구입니다. 로그 포맷 커스터마이징, 레벨 설정, 로그 로테이션까지 실무에서 필요한 모든 내용을 다룹니다.
로그 종류
Nginx는 두 가지 로그를 생성합니다.
| 로그 | 기본 경로 | 용도 |
|---|---|---|
| access_log | /var/log/nginx/access.log | HTTP 요청 기록 (IP, URL, 상태 코드, 응답 시간 등) |
| error_log | /var/log/nginx/error.log | 에러 및 경고 기록 (설정 오류, 파일 없음, 연결 실패 등) |
access_log 포맷 커스터마이징
기본 로그 포맷(main)은 필요한 정보를 대부분 담고 있지만, 실무에서는 응답 시간, ** 업스트림 정보**등을 추가한 커스텀 포맷을 사용합니다.
기본 포맷
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;
}
기본 포맷 로그 예시:
203.0.113.10 - - [24/Mar/2026:10:00:01 +0900] "GET /api/users HTTP/1.1" 200 512 "https://example.com" "Mozilla/5.0" "-"
응답 시간 포함 커스텀 포맷
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' # 업스트림 전체 응답 시간
;
access_log /var/log/nginx/access.log detailed;
상세 포맷 로그 예시:
203.0.113.10 - - [24/Mar/2026:10:00:01 +0900] "GET /api/users HTTP/1.1" 200 512 "-" "curl/7.88" rt=0.043 uct=0.001 uht=0.040 urt=0.042
JSON 포맷 (로그 수집 시스템 연동용)
ELK, Loki 같은 로그 수집 시스템에 적합한 JSON 포맷입니다.
log_format json_combined escape=json
'{'
'"time_local":"$time_local",'
'"remote_addr":"$remote_addr",'
'"method":"$request_method",'
'"uri":"$request_uri",'
'"status":$status,'
'"bytes_sent":$body_bytes_sent,'
'"request_time":$request_time,'
'"upstream_response_time":"$upstream_response_time",'
'"http_referer":"$http_referer",'
'"http_user_agent":"$http_user_agent",'
'"http_x_forwarded_for":"$http_x_forwarded_for"'
'}';
access_log /var/log/nginx/access.json json_combined;
JSON 로그 예시:
{"time_local":"24/Mar/2026:10:00:01 +0900","remote_addr":"203.0.113.10","method":"GET","uri":"/api/users","status":200,"bytes_sent":512,"request_time":0.043,"upstream_response_time":"0.042","http_referer":"","http_user_agent":"curl/7.88","http_x_forwarded_for":"-"}
주요 로그 변수 목록
$remote_addr # 클라이언트 IP
$remote_user # HTTP Basic Auth 사용자명
$time_local # 요청 시간 (로컬 시간)
$time_iso8601 # ISO 8601 형식 시간
$request # 전체 요청 줄 (메서드 + URI + 프로토콜)
$request_method # HTTP 메서드 (GET, POST 등)
$request_uri # 요청 URI + 쿼리 스트링
$status # HTTP 응답 상태 코드
$body_bytes_sent # 응답 본문 크기 (바이트)
$bytes_sent # 전체 응답 크기 (헤더 포함)
$request_time # 요청 처리 총 시간 (초, 밀리초 단위 소수점)
$upstream_addr # 업스트림 서버 주소
$upstream_status # 업스트림 응답 상태 코드
$upstream_response_time # 업스트림 응답 시간 (초)
$upstream_connect_time # 업스트림 연결 시간
$upstream_header_time # 업스트림 헤더 수신 시간
$http_referer # Referer 헤더
$http_user_agent # User-Agent 헤더
$http_x_forwarded_for # X-Forwarded-For 헤더
$server_name # 처리한 server_name
$server_port # 서버 포트
$scheme # http 또는 https
$ssl_protocol # TLS 버전 (HTTPS인 경우)
$ssl_cipher # 사용된 암호화 스위트
error_log 레벨 설정
error_log는 로그 레벨을 지정하여 기록할 메시지의 심각도를 조절합니다.
# 문법: error_log 경로 레벨;
error_log /var/log/nginx/error.log warn;
# 레벨 (낮을수록 더 많은 정보)
# debug → 모든 디버그 정보 (매우 상세, 운영환경 사용 금지)
# info → 정보성 메시지
# notice → 일반 알림
# warn → 경고 (기본 권장)
# error → 에러
# crit → 심각한 에러
# alert → 즉시 조치 필요
# emerg → 시스템 불능 상태
특정 서버별 에러 로그 분리
server {
server_name example.com;
error_log /var/log/nginx/example.com.error.log warn;
}
server {
server_name api.example.com;
error_log /var/log/nginx/api.error.log error;
}
불필요한 로그 비활성화
정적 파일(favicon, 이미지 등) 요청은 로그에서 제외하여 로그 용량을 줄입니다.
location = /favicon.ico {
log_not_found off; # 파일 없을 때 에러 로그 기록 안 함
access_log off; # 접근 로그 기록 안 함
}
location ~* \.(jpg|jpeg|png|gif|ico|css|js)$ {
access_log off; # 정적 파일 접근 로그 제외
expires 7d;
}
# 헬스체크 엔드포인트 로그 제외
location /health {
access_log off;
return 200 "OK";
}
로그 로테이션 (logrotate)
Nginx 로그는 방치하면 파일이 무한히 커집니다. logrotate로 자동 관리합니다.
/etc/logrotate.d/nginx 설정
/var/log/nginx/*.log {
daily # 매일 로테이션
missingok # 파일 없어도 에러 없음
rotate 14 # 14일치 보관
compress # 이전 로그 gzip 압축
delaycompress # 직전 로그는 압축 유예 (현재 쓰는 파일 보호)
notifempty # 빈 파일은 로테이션 안 함
sharedscripts # postrotate 스크립트 한 번만 실행
postrotate
# Nginx에 USR1 시그널 전송 → 로그 파일 다시 열기
if [ -f /var/run/nginx.pid ]; then
kill -USR1 `cat /var/run/nginx.pid`
fi
endscript
}
# 즉시 로테이션 테스트
sudo logrotate -f /etc/logrotate.d/nginx
# 로테이션 확인
ls -la /var/log/nginx/
실전 로그 분석 명령어
상태 코드별 집계
# 상태 코드 분포 확인
awk '{print $9}' /var/log/nginx/access.log | sort | uniq -c | sort -rn
# 출력 예시:
# 15432 200
# 234 304
# 87 404
# 12 500
응답 시간이 느린 요청 추출
# 응답 시간 1초 이상인 요청 (detailed 포맷 사용 시)
grep 'rt=' /var/log/nginx/access.log | awk '{
for(i=1;i<=NF;i++) if($i~/^rt=/) print $i, $0
}' | awk -F= '{if($2+0 > 1) print}' | sort -rn | head -20
특정 IP의 요청 횟수
# 특정 IP 요청 수
grep "203.0.113.10" /var/log/nginx/access.log | wc -l
# IP별 요청 수 상위 10개
awk '{print $1}' /var/log/nginx/access.log | sort | uniq -c | sort -rn | head -10
404 에러 URL 목록
awk '($9=="404") {print $7}' /var/log/nginx/access.log | sort | uniq -c | sort -rn | head -20
정리
| 항목 | 설정 | 권장 사항 |
|---|---|---|
| 포맷 | log_format | 응답 시간($request_time) 포함 커스텀 포맷 사용 |
| 에러 레벨 | error_log | 운영환경: warn, 디버깅: debug (임시) |
| 정적 파일 | access_log off | favicon·이미지 등 불필요한 로그 제외 |
| 로테이션 | logrotate | daily + 14일 보관 + compress 설정 |
| 분석 | awk, grep | 상태 코드·응답 시간·IP별 집계 |