mod_proxy_http 설정 — 현대적 Apache+Tomcat 연동
mod_proxy_http는 표준 HTTP/1.1로 Tomcat과 통신하는 방식으로, 신규 Apache+Tomcat 연동의 권장 방법입니다. AJP 취약점이 없고 설정이 단순하며, SSL Termination, 헤더 제어, 로드밸런싱까지 Apache 표준 기능을 그대로 활용할 수 있습니다.
모듈 활성화
sudo a2enmod proxy
sudo a2enmod proxy_http
sudo a2enmod headers
sudo a2enmod rewrite
sudo systemctl reload apache2
apache2ctl -M | grep "proxy_http"
# proxy_http_module (shared)
기본 설정
# /etc/apache2/sites-available/myapp.conf
<VirtualHost *:80>
ServerName example.com
ProxyRequests Off # 포워드 프록시 비활성화
ProxyPreserveHost On # 원래 Host 헤더 유지
ProxyPass / http://127.0.0.1:8080/
ProxyPassReverse / http://127.0.0.1:8080/
</VirtualHost>
완전한 프로덕션 설정
# /etc/apache2/sites-available/myapp-ssl.conf
<VirtualHost *:80>
ServerName example.com
ServerAlias www.example.com
# HTTPS 리다이렉트
RewriteEngine On
RewriteRule ^(.*)$ https://%{HTTP_HOST}$1 [R=301,L]
</VirtualHost>
<VirtualHost *:443>
ServerName example.com
ServerAlias www.example.com
# SSL 설정
SSLEngine on
SSLCertificateFile /etc/letsencrypt/live/example.com/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/example.com/privkey.pem
SSLProtocol all -SSLv3 -TLSv1 -TLSv1.1
SSLCipherSuite ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256
# 실제 클라이언트 IP 전달
RequestHeader set X-Real-IP "%{REMOTE_ADDR}s"
RequestHeader set X-Forwarded-For "%{X-Forwarded-For}e env=HTTP_X_FORWARDED_FOR"
RequestHeader set X-Forwarded-For "%{REMOTE_ADDR}s" env=!HTTP_X_FORWARDED_FOR
RequestHeader set X-Forwarded-Proto "https"
RequestHeader set X-Forwarded-Port "443"
RequestHeader set X-Forwarded-Host "%{HTTP_HOST}s"
# 보안 헤더
Header always set X-Frame-Options "SAMEORIGIN"
Header always set X-Content-Type-Options "nosniff"
Header always set Strict-Transport-Security "max-age=31536000; includeSubDomains"
# 프록시 설정
ProxyRequests Off
ProxyPreserveHost On
# 정적 파일 제외
ProxyPass /static !
ProxyPass /favicon.ico !
ProxyPass /robots.txt !
# 동적 요청 → Tomcat
ProxyPass / http://127.0.0.1:8080/ connectiontimeout=10 timeout=60
ProxyPassReverse / http://127.0.0.1:8080/
# 정적 파일 직접 서빙
Alias /static /var/www/myapp/static
<Directory "/var/www/myapp/static">
Options -Indexes
AllowOverride None
Require all granted
</Directory>
<IfModule mod_expires.c>
ExpiresActive On
ExpiresByType text/css "access plus 1 year"
ExpiresByType application/javascript "access plus 1 year"
ExpiresByType image/png "access plus 1 month"
ExpiresByType image/jpeg "access plus 1 month"
</IfModule>
# 로그
CustomLog ${APACHE_LOG_DIR}/myapp_access.log combined
ErrorLog ${APACHE_LOG_DIR}/myapp_error.log
</VirtualHost>
ProxyPass 경로 처리
ProxyPass의 경로 변환 규칙을 이해하는 것이 중요합니다.
# 경로 그대로 전달
ProxyPass /app/ http://127.0.0.1:8080/app/
# /app/users → http://127.0.0.1:8080/app/users
# 경로 변환 (슬래시 주의)
ProxyPass /app/ http://127.0.0.1:8080/
# /app/users → http://127.0.0.1:8080/users
# API 경로 분기
ProxyPass /api/v1/ http://127.0.0.1:8080/api/
# /api/v1/users → http://127.0.0.1:8080/api/users
ProxyPass 순서: 더 구체적인 경로를 먼저 작성합니다.
# 올바른 순서 (구체적인 경로 먼저)
ProxyPass /api/admin http://127.0.0.1:8081/admin
ProxyPass /api/ http://127.0.0.1:8080/api/
ProxyPass / http://127.0.0.1:8080/
# 잘못된 순서 (/ 가 모든 요청을 잡아버림)
ProxyPass / http://127.0.0.1:8080/ # 먼저 작성하면 안 됨
ProxyPass /api/ http://127.0.0.1:8080/api/ # 도달 불가
쿠키 경로 재작성 (ProxyPassReverseCookiePath)
Tomcat이 /myapp/으로 설정된 쿠키 경로를 /로 변환해야 할 때 사용합니다.
# Tomcat이 Set-Cookie: Path=/myapp/ 설정 시
# 클라이언트는 Apache를 통해 /로 접근하므로 불일치 발생
ProxyPassReverseCookiePath /myapp/ /
ProxyPassReverseCookieDomain 127.0.0.1 example.com
타임아웃과 재시도 설정
# 글로벌 프록시 타임아웃
ProxyTimeout 60
# ProxyPass 개별 속성
ProxyPass / http://127.0.0.1:8080/ \
connectiontimeout=10 \
timeout=60 \
retry=5 \
acquire=3000 \
max=100 \
ttl=300
# keepalive 연결 재사용
SetEnv proxy-nokeepalive 0 # keepalive 활성화
SetEnv proxy-initial-not-pooled 0 # 연결 풀 사용
| 속성 | 설명 |
|---|---|
connectiontimeout | 연결 수립 대기 시간(초) |
timeout | 응답 대기 시간(초) |
retry | 오류 후 재시도 간격(초), 0이면 즉시 |
acquire | 연결 풀 대기 시간(ms) |
max | 최대 연결 수 |
ttl | 연결 재사용 최대 시간(초) |
로드밸런싱
sudo a2enmod proxy_balancer
sudo a2enmod lbmethod_byrequests
sudo a2enmod lbmethod_bybusyness
<Proxy "balancer://tomcatcluster">
# 멤버 추가
BalancerMember "http://127.0.0.1:8080" route=tomcat1 loadfactor=1
BalancerMember "http://192.168.1.11:8080" route=tomcat2 loadfactor=1
# 백업 서버 (모든 메인이 다운됐을 때)
BalancerMember "http://192.168.1.12:8080" status=+H
# 로드밸런싱 설정
ProxySet lbmethod=bybusyness # bybusyness: 바쁘지 않은 서버 우선
ProxySet stickysession=JSESSIONID # 세션 고정
ProxySet nofailover=Off # 장애 시 다른 서버로 전환 허용
</Proxy>
ProxyPass / balancer://tomcatcluster/
ProxyPassReverse / balancer://tomcatcluster/
# 밸런서 관리 페이지
<Location /balancer-manager>
SetHandler balancer-manager
Require ip 127.0.0.1 10.0.0.0/8
</Location>
헬스체크 설정
# Apache 2.4.55+ 내장 헬스체크
<Proxy "balancer://tomcatcluster">
BalancerMember "http://127.0.0.1:8080" hcmethod=GET hcuri=/actuator/health hcinterval=10
BalancerMember "http://192.168.1.11:8080" hcmethod=GET hcuri=/actuator/health hcinterval=10
ProxySet lbmethod=byrequests
</Proxy>
Summary
| 항목 | 설정 |
|---|---|
| 필수 모듈 | proxy + proxy_http |
| 기본 지시어 | ProxyPass + ProxyPassReverse |
| 실제 IP 전달 | RequestHeader set X-Forwarded-For/Proto |
| 정적 파일 제외 | ProxyPass /static ! |
| 로드밸런싱 | proxy_balancer + stickysession=JSESSIONID |
| 쿠키 경로 | ProxyPassReverseCookiePath |
| 타임아웃 | ProxyTimeout + connectiontimeout=10 timeout=60 |