본문으로 건너뛰기
Advertisement

로그 설정과 분석

Nginx의 로그는 장애 원인 파악, 성능 분석, 보안 감사의 핵심 도구입니다. 로그 포맷 커스터마이징, 레벨 설정, 로그 로테이션까지 실무에서 필요한 모든 내용을 다룹니다.


로그 종류

Nginx는 두 가지 로그를 생성합니다.

로그기본 경로용도
access_log/var/log/nginx/access.logHTTP 요청 기록 (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 offfavicon·이미지 등 불필요한 로그 제외
로테이션logrotatedaily + 14일 보관 + compress 설정
분석awk, grep상태 코드·응답 시간·IP별 집계
Advertisement