mod_proxy_ajp 설정
mod_proxy_ajp는 Apache 내장 프록시 모듈을 AJP 프로토콜에 적용한 방식입니다. mod_jk보다 설정이 단순하고 Apache 표준 모듈을 사용하지만, AJP 프로토콜을 사용하므로 Ghostcat 취약점 보안 설정이 필수입니다.
모듈 활성화
sudo a2enmod proxy
sudo a2enmod proxy_ajp
sudo systemctl reload apache2
# 확인
apache2ctl -M | grep "proxy_ajp"
# proxy_ajp_module (shared)
기본 설정
# /etc/apache2/sites-available/myapp.conf
<VirtualHost *:80>
ServerName example.com
ProxyRequests Off # 포워드 프록시 비활성화 (보안)
ProxyPreserveHost On # 원래 Host 헤더 유지
# AJP 프록시
ProxyPass / ajp://127.0.0.1:8009/
ProxyPassReverse / ajp://127.0.0.1:8009/
</VirtualHost>
Ghostcat 보안 설정 (필수)
Tomcat server.xml
<Connector protocol="AJP/1.3"
address="127.0.0.1" <!-- 로컬만 수신 -->
port="8009"
redirectPort="8443"
secretRequired="true" <!-- 시크릿 필수 -->
secret="ApacheAjpSecret2024!" <!-- 강력한 시크릿 -->
maxThreads="200"
connectionTimeout="20000"/>
Apache 설정에 시크릿 포함
<VirtualHost *:80>
ServerName example.com
ProxyRequests Off
ProxyPreserveHost On
# 시크릿 포함한 AJP 연결
<Proxy "ajp://127.0.0.1:8009?secret=ApacheAjpSecret2024!">
Require all granted
</Proxy>
ProxyPass / "ajp://127.0.0.1:8009/?secret=ApacheAjpSecret2024!"
ProxyPassReverse / ajp://127.0.0.1:8009/
</VirtualHost>
실제 IP 전달 (mod_remoteip)
sudo a2enmod remoteip
<VirtualHost *:80>
ServerName example.com
# 실제 클라이언트 IP를 REMOTE_ADDR로 설정
RemoteIPHeader X-Forwarded-For
ProxyRequests Off
ProxyPreserveHost On
# 실제 IP 전달 헤더
RequestHeader set X-Forwarded-For "%{REMOTE_ADDR}s"
RequestHeader set X-Forwarded-Proto "http"
ProxyPass / "ajp://127.0.0.1:8009/?secret=MySecret"
ProxyPassReverse / ajp://127.0.0.1:8009/
</VirtualHost>
SSL + mod_proxy_ajp
<VirtualHost *:80>
ServerName example.com
Redirect permanent / https://example.com/
</VirtualHost>
<VirtualHost *:443>
ServerName example.com
SSLEngine on
SSLCertificateFile /etc/letsencrypt/live/example.com/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/example.com/privkey.pem
# HTTPS임을 Tomcat에 알림 (request.isSecure() = true)
RequestHeader set X-Forwarded-Proto "https"
RequestHeader set X-Forwarded-Port "443"
ProxyRequests Off
ProxyPreserveHost On
<Proxy "ajp://127.0.0.1:8009?secret=ApacheAjpSecret2024!">
Require all granted
</Proxy>
ProxyPass / "ajp://127.0.0.1:8009/?secret=ApacheAjpSecret2024!"
ProxyPassReverse / ajp://127.0.0.1:8009/
</VirtualHost>
정적 파일 분리
<VirtualHost *:443>
ServerName example.com
# 정적 파일 — Apache 직접 서빙
Alias /static /var/www/myapp/static
<Directory "/var/www/myapp/static">
Options -Indexes
AllowOverride None
Require all granted
ExpiresActive On
ExpiresByType text/css "access plus 1 year"
ExpiresByType application/javascript "access plus 1 year"
ExpiresByType image/png "access plus 1 month"
</Directory>
# 정적 경로는 AJP로 넘기지 않음
ProxyPass /static !
ProxyPass /favicon.ico !
ProxyPass /robots.txt !
# 동적 요청 → Tomcat
ProxyPass / "ajp://127.0.0.1:8009/?secret=MySecret"
ProxyPassReverse / ajp://127.0.0.1:8009/
</VirtualHost>
로드밸런싱 (mod_proxy_balancer)
sudo a2enmod proxy_balancer
sudo a2enmod lbmethod_byrequests
sudo a2enmod headers
<VirtualHost *:443>
ServerName example.com
# 로드밸런서 정의
<Proxy "balancer://tomcatcluster">
BalancerMember "ajp://127.0.0.1:8009?secret=MySecret" route=tomcat1
BalancerMember "ajp://192.168.1.11:8009?secret=MySecret" route=tomcat2
ProxySet lbmethod=byrequests
ProxySet stickysession=JSESSIONID
</Proxy>
ProxyPass / balancer://tomcatcluster/
ProxyPassReverse / balancer://tomcatcluster/
# 밸런서 상태 페이지 (내부망만)
<Location /balancer-manager>
SetHandler balancer-manager
Require ip 127.0.0.1
</Location>
</VirtualHost>
타임아웃 튜닝
<VirtualHost *:443>
# AJP 연결 타임아웃
ProxyTimeout 60
# 개별 경로 타임아웃 (ProxyPass 속성)
ProxyPass / "ajp://127.0.0.1:8009/?secret=MySecret" \
timeout=60 \
connectiontimeout=10 \
retry=1 \
acquire=3000
</VirtualHost>
| 속성 | 설명 | 기본값 |
|---|---|---|
timeout | AJP 응답 대기 시간(초) | Apache ProxyTimeout |
connectiontimeout | 연결 수립 대기 시간(초) | timeout 값 |
retry | 실패 후 재시도 대기 시간(초) | 60 |
acquire | 연결 풀에서 획득 대기 시간(ms) | 무한대 |
진단
# AJP 연결 확인
ss -tlnp | grep 8009
# Apache 에러 로그
tail -f /var/log/apache2/error.log
# mod_proxy_ajp 관련 에러 예시
# [error] ajp_read_header: ajp_ilink_receive failed
# → Tomcat 재시작 또는 AJP 연결 풀 고갈
# 설정 검증
sudo apache2ctl configtest
Summary
| 항목 | 설정 |
|---|---|
| 필수 모듈 | proxy + proxy_ajp |
| Ghostcat 대응 | Tomcat: secretRequired=true + Apache: ?secret=... |
| 수신 제한 | Tomcat: address="127.0.0.1" |
| SSL | RequestHeader set X-Forwarded-Proto "https" |
| 로드밸런싱 | proxy_balancer + stickysession=JSESSIONID |
| 권장 전환 | 신규 시스템은 mod_proxy_http 사용 |