서버 접근 로그 확인, Apache Nginx 집계 명령
- 접근 로그 한 줄에는 IP, 시간, 요청, 상태 코드, 용량, 참조 주소, 브라우저 정보가 순서대로 들어 있다.
- awk, sort, uniq 조합으로 요청 많은 IP와 자주 실패하는 경로를 몇 줄로 집계할 수 있다.
- 로그는 의심 징후를 찾는 단서일 뿐이며, 침해 여부는 파일 변경 점검과 함께 판단한다.
접근 로그(access log)는 서버가 받은 모든 요청을 한 줄씩 적어 둔 기록입니다. 누가, 언제, 어떤 주소를 요청했고 서버가 어떻게 답했는지가 남기 때문에 이상 징후를 찾는 가장 기본적인 자료입니다. 사이트가 갑자기 느려졌거나 낯선 페이지가 생긴 것 같을 때 제일 먼저 열어 볼 곳이기도 합니다.
이 글은 로그를 읽는 법과 자주 쓰는 집계 명령을 설명합니다. 로그는 단서이지 판결문이 아닙니다. 로그만으로 침해를 확정하거나 부정할 수는 없다는 점을 염두에 두고 읽으세요.
로그 한 줄 읽는 법
Apache와 Nginx 모두 기본적으로 combined 형식을 널리 씁니다. Apache 문서에서 확인한 필드는 다음과 같고 Nginx의 combined도 같은 순서입니다.
| 순서 | Apache 표기 | 의미 |
|---|---|---|
| 1 | %h | 접속자 IP |
| 2 | %l | identd 정보 (대부분 -) |
| 3 | %u | 인증된 사용자 이름 |
| 4 | %t | 요청 받은 시간 |
| 5 | “%r” | 요청 줄 (메서드, 주소, 프로토콜) |
| 6 | %>s | 최종 응답 상태 코드 |
| 7 | %b | 응답 본문 용량(바이트) |
| 8 | ”%{Referer}i” | 어떤 페이지를 통해 왔는지 |
| 9 | ”%{User-agent}i” | 브라우저·봇 정보 |
실제 한 줄은 다음처럼 생겼습니다.
203.0.113.5 - - [24/Oct/2026:10:15:32 +0900] "GET /wp-login.php HTTP/1.1" 200 4521 "-" "Mozilla/5.0 ..."
User-agent는 접속자가 스스로 적는 값이라 위조할 수 있습니다. 봇 판별 근거로 단독 사용하지 않습니다.
로그 위치 찾기
접근 로그의 기본 위치는 배포판과 설정마다 다릅니다. Apache 문서도 접근 로그의 위치는 CustomLog 지시어로 정해지고 상대 경로는 ServerRoot 기준이라고 설명합니다. 흔한 위치는 아래와 같지만 추정이므로 설정에서 확인하세요.
| 서버 | 흔한 위치 | 확인 방법 |
|---|---|---|
| Apache(Debian·Ubuntu) | /var/log/apache2/access.log | 설정에서 CustomLog 검색 |
| Apache(RHEL 계열) | /var/log/httpd/access_log | 설정에서 CustomLog 검색 |
| Nginx | /var/log/nginx/access.log | 설정에서 access_log 검색 |
grep -rn "CustomLog" /etc/apache2 /etc/httpd 2>/dev/null
grep -rn "access_log" /etc/nginx 2>/dev/null
가상호스트마다 로그 파일을 따로 지정한 경우가 많으니 도메인별 파일도 찾아봅니다. 아래 예시는 LOG 변수에 경로를 넣어 사용합니다.
LOG=/var/log/nginx/access.log
내 사이트의 HTTPS·인증서·보안 헤더를 바로 확인할 수 있습니다.
무료 보안 검사 시작자주 쓰는 집계 명령
combined 형식에서 1번 칸이 IP, 9번 칸이 상태 코드, 7번 칸이 요청 주소입니다(공백 기준 awk 번호).
# 최근 요청 보기
tail -n 100 "$LOG"
# 요청이 많은 IP 상위 10개
awk '{print $1}' "$LOG" | sort | uniq -c | sort -rn | head -10
# 상태 코드별 개수
awk '{print $9}' "$LOG" | sort | uniq -c | sort -rn
# 404가 많이 나는 주소 상위 10개
awk '$9==404 {print $7}' "$LOG" | sort | uniq -c | sort -rn | head -10
# 로그인 페이지 요청이 많은 IP
grep "wp-login.php" "$LOG" | awk '{print $1}' | sort | uniq -c | sort -rn | head
CDN 뒤에 있으면 앞서 설명한 대로 IP가 중간 장비 값이라서 집계가 의미 없을 수 있습니다. 여기서 뽑은 숫자는 “많다”의 기준이 사이트마다 다르니, 평소 값을 한번 기록해 두고 비교하는 것이 좋습니다.
의심해 볼 패턴
공격 방법을 따라 하는 것이 아니라 방어자가 눈여겨볼 징후만 정리합니다.
- 짧은 시간에 한 IP가 수백 번 요청: 자동 스캔이나 무차별 로그인 시도일 수 있습니다.
- 존재하지 않는 관리자·설정 파일 경로의 404 반복: 흔한 자동 탐색입니다. 404이면 일단 실패한 시도입니다.
- 업로드 폴더 안 PHP 파일에 대한 200 응답: 정상 사이트는 보통 업로드 폴더에서 PHP를 실행하지 않습니다. 실제로 있다면 파일을 바로 확인합니다. 자세한 점검은 PHP 웹쉘 탐지 글에 있습니다.
- POST 요청이 특정 파일에 집중: 로그인 폼이나 XML-RPC 같은 곳이라면 로그인 시도일 수 있습니다.
- 500 오류가 갑자기 증가: 공격이 아니라 코드 오류일 수도 있으니 PHP 오류 로그와 함께 봅니다.
한 가지 징후만으로 결론내리지 말고 여러 단서를 묶어서 판단하세요. 접속 인증 로그(auth.log)에서 SSH 로그인 기록을 보는 방법과 대응은 SSH 보안 설정 글과 이어집니다.
로그 회전과 보관
로그는 가만히 두면 계속 커집니다. Apache 문서는 요청 1만 건당 1MB 이상 늘어날 수 있다고 설명하며, rotatelogs나 logrotate 같은 도구로 회전하라고 안내합니다. 많은 배포판에서 /etc/logrotate.d/에 설정이 이미 있으므로 먼저 확인합니다. 회전 뒤에는 서버가 새 파일을 열도록 graceful 재시작이나 reload가 필요하다고 문서에 나옵니다.
ls /etc/logrotate.d/
ls -lh /var/log/nginx/ /var/log/apache2/ 2>/dev/null
사고가 의심되면 로그를 지우거나 덮어쓰지 말고 복사본을 따로 보관해 둡니다. 서버가 침해되었다면 서버 안의 로그는 조작되었을 수 있으니 외부 저장소에 복제하는 것이 안전합니다.
로그 분석 도구(GoAccess 등)와 ELK 같은 중앙 수집 시스템은 이 글에서 직접 문서를 확인하지 않아 다루지 않았습니다.
웹사이트 기본 보안 검사HTTPS·리디렉션·인증서·보안 헤더·서버 정보 노출 10개 항목을 무료로 확인할 수 있습니다.
무료 보안 검사 시작자주 묻는 질문
로그 파일이 너무 커서 열리지 않습니다.
전체를 열지 말고 tail -n 200으로 끝부분만 보거나 grep과 awk로 필요한 줄만 뽑습니다. 로그가 계속 커진다면 logrotate 설정이 되어 있는지 확인합니다.
로그에서 내 IP가 뒤바뀌어 보입니다.
CDN이나 로드밸런서 뒤에 서버가 있으면 접속자 IP 자리에 중간 장비의 IP가 찍힙니다. 이 경우 X-Forwarded-For 같은 헤더를 로그 형식에 추가해야 실제 방문자 IP를 볼 수 있습니다.
로그에 공격 시도가 많이 보이면 해킹당한 건가요?
아닙니다. 인터넷에 열린 서버는 자동 스캔을 늘 받습니다. 중요한 것은 시도가 아니라 성공 여부입니다. 상태 코드 200으로 응답된 낯선 경로와 최근 변경된 파일을 함께 확인하세요.
로그를 얼마나 보관해야 하나요?
법적 보관 기간이나 업무 요건에 따라 달라서 이 글에서 확정할 수 없습니다. 최소한 사고 원인을 되짚을 수 있도록 로그 회전 설정에서 보관 개수를 확인하고, 필요하면 별도 서버에 복사해 두세요.
확인한 자료
기술 정보는 2026-10-24에 위 자료로 확인했습니다. 소프트웨어 버전·기본값·서비스 정책은 바뀔 수 있으므로 적용 전 각 문서의 최신 내용을 확인하세요. 이 글은 일반 정보이며 특정 서비스 가입을 권하지 않습니다.