운영 환경에 적용하기 전 한 번씩 점검할 것.
가장 흔한 사고. Rewrite가 JkUnMount보다 먼저 동작해 경로를 갈아낀 케이스.
해결:
RewriteCond %{REQUEST_URI} !^/resources
RewriteCond %{REQUEST_URI} !^/files
RewriteRule "^(.*)$" "/your-app/$1" [R,L]자세히 → 03-rewrite-priority.md
maxThreads=800이라도 acceptCount가 작으면 OS 대기 큐에서 거부될 수 있다.
<Connector protocol="AJP/1.3"
executor="tomcatThreadPool"
acceptCount="200" <!-- 큐 크기 -->
maxConnections="2000" <!-- 최대 동시 연결 -->
.../>acceptCount 기본은 100. 부하 큰 환경에선 200~500.
RAM 가용 메모리 < 스왑 사용량이면 swapoff가 멈춘다.
# 사전 점검
AVAILABLE=$(free -m | awk 'NR==2 {print $7}')
SWAP_USED=$(free -m | awk 'NR==3 {print $3}')
if [ "$SWAP_USED" -gt "$AVAILABLE" ]; then
echo "위험: swapoff 금지"
exit 1
fi
sudo swapoff -a && sudo swapon -aAlias 경로의 디렉토리 권한·소유권 확인:
# Apache 데몬 사용자가 읽을 수 있어야 함
ls -la /srv/webapp/your-app/static
# drwxr-xr-x. daemon daemon ...
# 안 맞으면
sudo chown -R daemon:daemon /srv/webapp/your-app/static
sudo chmod -R 755 /srv/webapp/your-app/staticSELinux가 enforcing인 경우:
sudo semanage fcontext -a -t httpd_sys_content_t "/srv/webapp/your-app/static(/.*)?"
sudo restorecon -Rv /srv/webapp/your-app/static
# 확인
ls -Z /srv/webapp/your-app/staticApache 직접 서빙으로 바꿨으니 mod_expires로 캐시 정책 별도 적용. 안 하면:
- 첫 호출: 빠름 (Apache가 직접 처리)
- 재방문: 같은 자원을 매번 다운로드 (304도 안 옴) → 무거움
LoadModule expires_module modules/mod_expires.so
<IfModule expires_module>
ExpiresActive On
ExpiresByType image/* "access plus 30 days"
ExpiresByType text/css "access plus 30 days"
ExpiresByType application/javascript "access plus 30 days"
ExpiresByType font/* "access plus 1 year"
</IfModule>검증:
curl -I https://your-domain.example/resources/css/main.css
# Cache-Control: max-age=2592000 ← 30일
# Expires: ...<!-- ❌ 위험 -->
<Connector protocol="AJP/1.3"
address="0.0.0.0" <!-- 모든 인터페이스 -->
secretRequired="false"
port="8009"/>
<!-- ✅ 안전 -->
<Connector protocol="AJP/1.3"
address="127.0.0.1" <!-- localhost만 -->
secretRequired="true"
secret="<long-random>"
port="8009"/># ❌ 무한 루프
RewriteCond %{REQUEST_URI} !^/your-app
RewriteRule "^(.*)$" "/your-app/$1" [R,L]
# 처음: /resources → /your-app/resources (Redirect)
# 두 번째 요청: /your-app/resources → 위 조건에 안 걸림 → 통과
# 정상 동작이지만, 만약 RewriteCond를 빼면:
# /resources → /your-app/resources → /your-app/your-app/resources → ... 무한!^/your-app 같은 자기 자신 제외 조건을 항상 포함.
또는 [R,L] 대신 [L]만 써서 내부 리라이트(클라이언트 리다이렉트 없음)로 처리:
RewriteRule "^(.*)$" "/your-app/$1" [L]내부 리라이트면 클라이언트는 모르지만, JkMount 평가는 새 경로 기준이라 본 가이드 패턴과 호환된다.
<!-- Tomcat -->
<Connector protocol="AJP/1.3"
secretRequired="true"
secret="abc123def456"
.../># mod_jk workers.properties - 같은 값이어야 함
worker.worker1.secret=abc123def456불일치 시 mod_jk가 Tomcat에 연결 시도하지만 거부됨. Apache error_log에 secret required 류 에러.
-
httpd -t(Apache 설정 문법 OK) -
catalina.sh configtest(Tomcat OK) - 정적 리소스 응답에
Server: Apache(Tomcat 흔적 없음) - 캐시 헤더(
Cache-Control) 포함 - AJP 포트가 외부에서 접근 불가 (
telnet <external-ip> 8009실패) - 스왑 사용량 1GB 이하 유지
- 24시간 후 같은 시간대 재측정 안정성 확인