fail2ban — Nginx 공격 IP 자동 차단
Slack 알림으로 공격을 인지하는 것만으로는 부족하다.
fail2ban을 이용해 Nginx 로그를 실시간 모니터링하고, 반복 공격 IP를 자동으로 iptables로 차단한다.
SSH 브루트포스 차단은 fail2ban SSH 보호 문서를 참고한다.
설치 (Amazon Linux 2023)
sudo dnf install -y epel-release fail2ban
sudo systemctl enable --now fail2ban
필터 작성
/etc/fail2ban/filter.d/nginx-attack.conf
[Definition]
failregex = ^<HOST> - \S+ \[\] "POST / HTTP/[0-9\.]+" 5\d\d
^<HOST> - \S+ \[\] "(GET|POST|HEAD|OPTIONS) /?(wp-admin|wp-login|xmlrpc|phpinfo|phpmyadmin|\.env|\.git|\.aws|actuator|cgi-bin|shell|eval)\S* HTTP/[0-9\.]+" [45]\d\d
ignoreregex =
datepattern = {^LN-BEG}%%ExY(?P<_sep>[-/.])%%m(?P=_sep)%%d[T ]%%H:%%M:%%S(?:[.,]%%f)?(?:\s*%%z)?
^[^\[]*\[({DATE})
{^LN-BEG}
failregex에서 \[\]를 쓰는 이유
fail2ban은 datepattern으로 타임스탬프를 찾은 뒤 해당 부분을 빈 괄호 []로 대체하고 failregex를 적용한다.
# Nginx 로그 원본
198.51.100.10 - - [22/May/2026:00:11:28 +0000] "POST / HTTP/1.1" 500 44
# fail2ban이 변환한 형태 (failregex가 매칭하는 실제 대상)
198.51.100.10 - - [] "POST / HTTP/1.1" 500 44
날짜 형식을 failregex에 직접 쓰면 매칭되지 않는다. 반드시 \[\](빈 괄호)를 사용해야 한다.
Jail 설정
/etc/fail2ban/jail.local
[nginx-attack]
enabled = true
filter = nginx-attack
logpath = /var/log/nginx/access.log
maxretry = 3
findtime = 5m
bantime = 24h
| 항목 | 값 | 의미 |
|---|---|---|
maxretry | 3 | 5분 내 3회 이상 공격 시 차단 |
findtime | 5m | 탐지 기준 시간 윈도우 |
bantime | 24h | 차단 유지 시간 |
필터 테스트
적용 전에 반드시 기존 로그로 테스트한다.
sudo fail2ban-regex /var/log/nginx/access.log /etc/fail2ban/filter.d/nginx-attack.conf
출력에서 Failregex: N total — N > 0이면 정상 작동.
적용
sudo fail2ban-client reload
sudo fail2ban-client status nginx-attack
운영 명령어
# 현재 차단 IP 목록 조회
sudo fail2ban-client status nginx-attack
# 수동 차단
sudo fail2ban-client set nginx-attack banip 1.2.3.4
# 차단 해제
sudo fail2ban-client set nginx-attack unbanip 1.2.3.4
# 로그 실시간 확인
sudo tail -f /var/log/fail2ban.log
보안 이중화 구조
공격 요청 도달
│
▼
[Nginx] → POST / 차단 (444, 즉시 연결 끊음)
│ 의심 경로는 앱까지 전달
▼
[Spring] → SecurityAlertService → Slack 알림 (IP당 10분 쿨다운)
│
▼
[fail2ban] → Nginx 로그 감시 → 3회 이상 시 24시간 자동 차단
Slack 알림(인지) + fail2ban 자동 차단(방어) 두 레이어가 함께 동작한다.