OSWeb Hosting

[AWS LAMP] Apache 2.4 – Rate limit : 한 IP나 기기가 짧은 시간에 서버 API를 너무 많이 호출하지 못하게 제한하는 방법

Apache라면 mod_evasive 또는 PHP/Redis 기반 제한을 사용할 수 있습니다. 단순 PHP+MariaDB로도 만들 수 있지만 모든 공격 요청이 PHP와 DB까지 도달하므로 Nginx 제한보다 효율이 떨어집니다.

현재 서버가 1대이고 “빠르고 간단하게” 적용하려는 목적이면 mod_evasive가 더 적합합니다.

비교하면:

구분mod_evasivePHP + Redis
적용 난이도간단Redis 설치·PHP 확장·코드 필요
차단 위치PHP 실행 전PHP 실행 후
서버 부하 방어더 유리이미 PHP 자원 사용
URL별 정밀 제한제한적매우 유연
여러 서버 간 공유어려움가능
유지보수적음상대적으로 많음

추천 구성은:

  • Apache mod_evasive: 서버 전체의 과도한 반복 요청 차단
  • PHP 자체 제한: 결제 API에만 조금 더 엄격한 규칙 적용
  • Redis는 서버가 여러 대로 늘어나거나 사용자·API별 정밀 제한이 필요할 때 도입

다만 mod_evasive/verify_purchase.php는 분당 10회 같은 정밀한 API별 정책보다는 DoS성 반복 요청 차단에 가깝습니다. 각 Apache 프로세스 내부의 IP/URI 해시 테이블을 기반으로 차단하므로 단일 서버에서는 간단하지만 분산 서버에는 적합하지 않습니다.

mod_evasive 적용방법

Apache 서버라면 mod_evasive를 서버 전체 1차 방어막으로 사용하는 것이 가장 빠르고 간단합니다. 다만 이것은 정밀한 API rate limit이나 대규모 DDoS 방어가 아니라, 같은 IP가 짧은 시간에 동일 URL 또는 서버 전체에 요청을 반복할 때 임시로 403을 반환하는 방식입니다. mod_evasive 공식 README

1. 먼저 프록시 사용 여부 확인

Cloudflare, 로드밸런서, Nginx 리버스 프록시 앞단이 있다면 Apache가 모든 접속자를 동일한 프록시 IP로 볼 수 있습니다. 이 상태에서 mod_evasive를 켜면 여러 사용자가 한꺼번에 차단될 수 있습니다.

Apache access log에서 서로 다른 사용자가 실제 공인 IP로 기록되는지 확인하세요.

sudo tail -f /opt/bitnami/apache/logs/access_log

실제 사용자 IP가 기록된다면 진행해도 됩니다. Cloudflare IP나 127.0.0.1만 기록된다면 먼저 Apache mod_remoteip 설정이 필요합니다.

2. Bitnami Apache 경로 확인

현재 서버가 Bitnami 구성이면 일반적으로 다음 경로입니다.

/opt/bitnami/apache/bin/httpd -V

혹시 없다면 다음도 확인합니다.

/opt/bitnami/apache2/bin/httpd -V

이후 예제는 /opt/bitnami/apache 기준입니다. 실제 환경이 apache2이면 경로만 바꾸면 됩니다.

기존 설치 여부도 확인합니다.

sudo /opt/bitnami/apache/bin/httpd -M | grep evasive

아래처럼 나오면 이미 설치된 것입니다.

evasive20_module (shared)

3. mod_evasive 설치

Bitnami가 자체 Apache를 사용하면 Ubuntu의 libapache2-mod-evasive 패키지가 시스템 Apache용으로 설치될 수 있으므로, Bitnami의 apxs로 컴파일하는 편이 안전합니다.

sudo apt update
sudo apt install build-essential git
git clone https://github.com/jzdziarski/mod_evasive.git /tmp/mod_evasive

Apache 2.4용 버전은 아래껄로 받습니다.

git clone https://github.com/shivaas/mod_evasive.git /tmp/mod_evasive
cd /tmp/mod_evasive

Apache 버전도 확인합니다.

/opt/bitnami/apache/bin/httpd -v

Apache/2.4.x이면 다음 명령으로 설치합니다.

sudo /opt/bitnami/apache/bin/apxs -i -a -c mod_evasive24.c

설치 결과 확인

컴파일 마지막 부분에 다음처럼 나와야 합니다.

libtool: install: ...
/opt/bitnami/apache/modules/mod_evasive24.so

모듈 설정이 자동으로 추가되었는지 확인합니다.

grep -n "evasive" /opt/bitnami/apache/conf/httpd.conf

예상 결과는 다음과 비슷합니다.

LoadModule evasive20_module modules/mod_evasive24.so

모듈 내부 이름은 소스상 evasive20_module이므로 파일 이름이 mod_evasive24.so여도 정상입니다.

4. 로그 디렉터리 생성

Apache 실행 사용자를 확인합니다.

grep -E '^(User|Group)' /opt/bitnami/apache/conf/httpd.conf

Bitnami에서는 흔히 다음처럼 나옵니다.

User daemon
Group daemon

로그 디렉터리를 만듭니다.

sudo mkdir -p /opt/bitnami/apache/logs/mod_evasive

daemon이 실제 Apache 사용자일 때:

sudo chown daemon:daemon /opt/bitnami/apache/logs/mod_evasive
sudo chmod 750 /opt/bitnami/apache/logs/mod_evasive

실제 사용자가 다르면 daemon:daemon을 해당 사용자와 그룹으로 바꿔야 합니다.


5. 서버 전체 설정 작성

다음 파일을 생성합니다.

/opt/bitnami/apache/conf/mod_evasive.conf

초기 운영값은 아래 정도를 권장합니다.

<IfModule evasive20_module>
    DOSHashTableSize 3097

    # 동일 IP가 동일 URL을 1초 동안 15회 초과 요청하면 차단
    DOSPageCount 15
    DOSPageInterval 1

    # 동일 IP가 서버 전체에 1초 동안 100회 초과 요청하면 차단
    DOSSiteCount 100
    DOSSiteInterval 1

    # 차단 유지 시간(초)
    DOSBlockingPeriod 60

    # 상태 파일 디렉터리
    DOSLogDir "/opt/bitnami/apache/logs/mod_evasive"

    # 로컬 요청 제외
    DOSWhitelist 127.0.0.1
    #DOSWhitelist ::1
</IfModule>

DOSPageCount 15는 정확히 “초당 15개만 허용”하는 일반적인 rate limiter와는 조금 다릅니다. 동일 Apache worker가 지정된 시간 안에 동일 IP의 동일 URI를 반복해서 관측하면 차단하는 방식입니다.

모바일 앱이 짧은 시간에 API 여러 개를 병렬 호출할 수 있으므로 공식 예제의 DOSPageCount 2처럼 너무 낮게 설정하면 정상 사용자가 차단될 가능성이 큽니다.

현재 mod_evasive24.c는 IPv4 중심 화이트리스트 구현이므로 우선 DOSWhitelist ::1은 넣지 않는 편이 안전합니다.

6. Apache 설정에 포함

다음 파일을 엽니다.

/opt/bitnami/apache/conf/httpd.conf

파일 맨 아래에 추가합니다.

Include "/opt/bitnami/apache/conf/mod_evasive.conf"

그리고 모듈 로딩 줄이 있는지 확인합니다.

grep -n "evasive" /opt/bitnami/apache/conf/httpd.conf

설치가 정상적이면 다음과 비슷한 줄이 있어야 합니다.

LoadModule evasive20_module modules/mod_evasive20.so

apxs -a가 이미 추가했다면 중복으로 넣으면 안 됩니다.

Bitnami Apache의 주요 설정 경로는 /opt/bitnami/apache/conf/httpd.conf/opt/bitnami/apache/conf/bitnami/ 아래입니다. Bitnami Apache 설정 문서

7. 문법 검사 후 재시작

먼저 문법 검사부터 합니다.

sudo /opt/bitnami/apache/bin/apachectl -t

정상이면 다음이 표시됩니다.

Syntax OK

그다음 Apache를 재시작합니다.

sudo /opt/bitnami/ctlscript.sh restart apache

로드 여부를 재확인합니다.

sudo /opt/bitnami/apache/bin/httpd -M | grep evasive

8. 차단 테스트

운영 관리자 IP가 차단될 수 있으므로 SSH 세션을 유지하고, 가능하면 다른 인터넷 회선이나 테스트 장비에서 실행합니다.

for i in $(seq 1 30)
do
  curl -s -o /dev/null -w "%{http_code}\n" https://jspsoft.co.kr/billing/ios/entitlements.php
done

처음에는 API 자체 응답인 200, 400, 401, 405 등이 나오다가 기준을 초과하면 403이 나와야 합니다.

주의할 점은 차단된 상태에서 계속 요청하면 차단 시간이 계속 갱신될 수 있다는 것입니다. 테스트가 끝나면 60초 이상 요청을 멈추세요.

9. 로그 확인

Apache 오류 로그:

sudo tail -f /opt/bitnami/apache/logs/error_log

Ubuntu 계열 시스템 로그:

sudo tail -f /var/log/syslog

systemd journal을 사용한다면:

sudo journalctl -f

DOSLogDir에는 차단 상태를 위한 파일이 만들어질 수 있습니다.

sudo ls -la /opt/bitnami/apache/logs/mod_evasive

10. 운영 중 조정 기준

정상 사용자가 차단되면 다음 순서로 완화하세요.

DOSPageCount 25
DOSSiteCount 150
DOSBlockingPeriod 30

공격성 요청이 그대로 통과한다면 조금 강화할 수 있습니다.

DOSPageCount 10
DOSSiteCount 60
DOSBlockingPeriod 120

DOSPageIntervalDOSSiteInterval은 우선 1초를 유지하는 것이 좋습니다. 서버 전체 설정에서 60초처럼 길게 잡고 횟수를 낮게 설정하면 앱 사용자, 사내망, 통신사 NAT 이용자들이 쉽게 오탐 차단됩니다.

11. 고정 IP 화이트리스트

서버 모니터링, 관리자 사무실 등 확실한 고정 IP만 제외합니다.

DOSWhitelist 203.0.113.10

내부망 전체를 허용해야 한다면 와일드카드도 사용할 수 있습니다.

DOSWhitelist 192.168.1.*

일반 사용자 대역이나 이동통신사 IP를 광범위하게 화이트리스트 처리하면 안 됩니다.

꼭 알아야 할 한계

  • 동일 공인 IP를 공유하는 회사, 학교, 이동통신사 사용자가 함께 차단될 수 있습니다.
  • Apache worker별 메모리를 이용하므로 정밀한 전역 요청 카운터는 아닙니다.
  • 회선을 가득 채우는 대규모 DDoS는 Apache에 도달하기 전에 이미 문제가 생기므로 Cloudflare 같은 앞단 방어가 필요합니다.
  • 결제 검증 API처럼 민감한 URL은 mod_evasive와 별도로 PHP/Redis 기반의 사용자·토큰·IP별 제한을 두는 것이 안전합니다.
  • DOSEmailNotify는 서버에 메일 전송 환경이 필요하고, DOSSystemCommand는 외부 명령 실행 위험이 있으므로 초기에는 사용하지 않는 편이 좋습니다.

현재 구조에는 우선 DOSPageCount 15, DOSSiteCount 100, DOSBlockingPeriod 60으로 시작하고 access log를 관찰하면서 조정하는 구성이 적당합니다.

Hi, I’m 관리자