Fail2Ban + Nginx로 웹 스크래퍼 차단 (프로덕션 가이드)
Source: Dev.to
웹 스크래핑 및 과도한 크롤링은 인프라 비용을 은밀히 소모하고, 서버 부하를 증가시키며, 제품이 규모 확장을 준비하기도 전에 API를 노출시킬 수 있습니다.
만약 Nginx, Django (Gunicorn), 그리고 Next.js 프런트엔드를 사용하는 자체 관리 스택(EC2 / VPS)을 운영하고 있다면, Fail2Ban은 가장 높은 ROI와 비용이 전혀 들지 않는 방어 수단 중 하나입니다.
이 글에서는 Fail2Ban이 무엇인지, 왜 사용해야 하는지, 어떻게 설정하는지, 아키텍처에서 어디에 위치하는지, 그리고 프로덕션 환경에서 제대로 작동하는지 확인하는 방법을 설명합니다.
1. 문제: 스크래핑이 비용이 많이 드는 이유
비록:
- 제품이 아직 개발 중이더라도
- 등록된 사용자가 적더라도
- 트래픽이 “낮아 보이더라도”
스크래퍼와 봇은:
- 분당 수천 개의 URL에 접근할 수 있고
- 대량의
404및403응답을 생성하며 - 정적 자산을 반복적으로 다운로드하고
- 아웃바운드 대역폭을 소모합니다 (AWS 데이터 전송은 무료가 아닙니다)
전통적인 속도 제한은 도움이 되지만 봇은 적응합니다.
우리는 다음을 수행할 수 있는 메커니즘이 필요합니다:
- 행동을 학습하고
- 위반자를 자동으로 차단하며
- OS/방화벽 수준에서 작동하고
- 비용이 전혀 들지 않는
바로 Fail2Ban이 빛을 발하는 지점입니다.
2. What Is Fail2Ban?
Fail2Ban은 로그를 모니터링하는 침입 방지 도구입니다.
높은 수준에서 보면:
- 로그 파일(Nginx 접근 로그 등)을 감시합니다
- 정규식을 사용해 패턴을 매칭합니다
- 해당 패턴을 트리거하는 IP가 얼마나 자주 발생했는지 추적합니다
- 방화벽 규칙을 이용해 남용하는 IP를 일시적으로 차단합니다
차단되면:
- 트래픽이 Nginx에 도달하지 않음
- CPU와 대역폭 사용량이 즉시 감소
Fail2Ban은:
- 가벼움
- 검증된 신뢰성
- 프로덕션 환경에서 널리 사용됨
3. Fail2Ban이 스택에서 차지하는 위치
전형적인 아키텍처
Client (User / Bot)
|
v
Nginx (Reverse Proxy)
|
+--> Frontend (Next.js)
|
+--> Backend (Gunicorn + Django)
Fail2Ban은 요청 경로 외부에서 동작합니다
Nginx access.log
|
v
Fail2Ban
|
v
Firewall (iptables / nftables)
IP가 차단되면, 요청은 Nginx에 도달하기 전에 차단됩니다.
4. 설치
Ubuntu에서:
sudo apt update
sudo apt install fail2ban -y
설치 확인:
fail2ban-client --version
예시 출력
Fail2Ban v1.0.x
5. Understanding Nginx Logs (Very Important)
Fail2Ban은 로그 형식에 의존합니다.
일반적인 Nginx access‑log 라인은 다음과 같습니다:
203.0.113.45 - - [17/Dec/2025:01:57:51 +0000] "GET /unknown HTTP/1.1" 404 548 "-" "SomeBot/1.0"
핵심 요소
- IP 주소
- HTTP 메서드
- 경로
- 상태 코드 (
404,403등)
우리는 반복되는 403 / 404 응답을 감지할 것이며, 이는 스크래핑 및 탐색의 강력한 지표입니다.
6. Creating a Custom Fail2Ban Filter
Create a new filter file:
sudo nano /etc/fail2ban/filter.d/nginx-scraping.conf
Example filter configuration
[Definition]
# Match repeated forbidden or not‑found responses
failregex = ^ - .* "(GET|POST|HEAD).*" (403|404)
ignoreregex =
What this does
- 클라이언트 IP를 캡처합니다
GET,POST,HEAD요청을 모두 매치합니다403또는404응답이 있을 때만 트리거됩니다- 성공적인 요청(
200,301등)은 무시합니다
이렇게 하면 오탐을 최소화할 수 있습니다.
7. Jail 설정 만들기
jail.local를 편집하거나 생성합니다:
sudo nano /etc/fail2ban/jail.local
예시 jail 구성
[nginx-scraping]
enabled = true
filter = nginx-scraping
logpath = /var/log/nginx/access.log
maxretry = 30
findtime = 60
bantime = 3600
각 설정의 의미
| 설정 | 목적 |
|---|---|
enabled | jail을 활성화합니다 |
filter | 적용할 정규식 규칙 |
logpath | Nginx 접근 로그 위치 |
maxretry | 허용되는 실패 횟수 |
findtime | 실패를 카운트하는 시간 창(초) |
bantime | 차단 지속 시간(초) |
효과: IP가 60초 이내에 30 × 403/404 응답을 발생시키면 1시간 동안 차단됩니다.
8. 필터 테스트 (핵심 단계)
Fail2Ban을 재시작하기 전에 실제 로그에 대해 정규식을 테스트합니다:
sudo fail2ban-regex /var/log/nginx/access.log /etc/fail2ban/filter.d/nginx-scraping.conf
예상 출력
- 수백에서 수천 건의 매치
- 구문 오류 없음
이것은 다음을 확인합니다:
- 정규식 정확성
- 로그 형식 호환성
9. Fail2Ban 재시작 및 확인
Fail2Ban을 재시작합니다:
sudo systemctl restart fail2ban
활성화된 jail을 확인합니다:
sudo fail2ban-client status
예시 출력
Jail list: nginx-scraping, sshd
jail 상세 정보를 확인합니다:
sudo fail2ban-client status nginx-scraping
예시 출력
Currently failed: 58
Currently banned: 2
Banned IP list: 203.0.113.10 198.51.100.42
이는 실패가 감지되고 문제가 되는 IP가 차단되고 있음을 확인시켜 줍니다.
10. 수동 언밴 (필요한 경우)
정상적인 IP가 차단된 경우:
sudo fail2ban-client unban <IP>
예시
sudo fail2ban-client unban 203.0.113.10
11. 왜 이것이 프로덕션에서 잘 작동하는가
장점
- 인프라 비용 제로
- 커널 수준 차단
- 애플리케이션 코드 변경 없음
- 모든 백엔드와 호환 (Django, Node, Go 등)
- AWS 데이터 전송 비용 절감
제한 사항
- 실시간 행동 분석이 아님
- 로그 관리가 잘 되어야 함
- 레이트 제한을 보완해야 함 (대체가 아니라)
12. 권장 다음 향상 사항
- recidive jail 추가 (반복 위반자에 대한 장기 차단)
- 프론트엔드와 API jail을 분리
- Nginx 속도 제한과 결합
- Nginx 레벨에서 User‑Agent 필터링 추가
Fail2Ban은 다계층 방어의 일부로 사용할 때 가장 효과적입니다.
최종 생각
자체 관리 스택을 운영하고 외부 대역폭 비용을 지불하고 있다면, Fail2Ban은 배포할 수 있는 가장 빠른 성과 중 하나입니다.
It is:
- Simple
- Reliable
- Production‑proven
그리고 가장 중요한 점은—리소스를 보호하면서 백그라운드에서 조용히 작동한다는 것입니다.
