본문으로 건너뛰기
Advertisement

가상 호스트와 웹 애플리케이션 배포

Tomcat은 Host 설정을 통해 여러 가상 호스트를 운영하고, WAR 파일 또는 디렉터리를 자동·수동으로 배포할 수 있습니다. 이 챕터에서는 실무에서 자주 쓰는 배포 패턴과 안전한 운영 방법을 다룹니다.


웹 애플리케이션 배포 방식

Tomcat에는 세 가지 배포 방식이 있습니다.

방식방법특징
자동 배포WAR 파일을 webapps/에 복사간단, 프로덕션 비권장
수동 배포Context XML 파일 생성명시적, 권장
Manager 앱HTTP PUT 또는 웹 UICI/CD 통합 가능

WAR 파일 자동 배포

autoDeploy="true"로 설정된 Host에서는 webapps/ 디렉터리에 WAR 파일을 복사하면 자동으로 배포됩니다.

# WAR 파일을 배포 디렉터리에 복사
sudo cp myapp-1.2.0.war /opt/tomcat/latest/webapps/myapp.war

# Tomcat이 자동으로 압축 해제
# /opt/tomcat/latest/webapps/myapp/ ← 생성됨

# 접근 URL: http://host:8080/myapp/

자동 배포 설정 (server.xml)

<Host name="localhost" appBase="webapps"
unpackWARs="true"
autoDeploy="true"
deployOnStartup="true">
속성설명프로덕션 권장
unpackWARsWAR 자동 압축 해제true
autoDeploy런타임 WAR 자동 감지·배포false
deployOnStartup시작 시 appBase 스캔true

프로덕션 주의: autoDeploy="true" + autoDeploy="true"는 Tomcat이 실행 중에 파일 시스템을 주기적으로 검사합니다. 불완전하게 복사 중인 WAR가 배포될 수 있으므로, 프로덕션에서는 autoDeploy="false"를 권장합니다.


Context XML 파일로 수동 배포 (권장)

conf/Catalina/localhost/ 디렉터리에 Context XML 파일을 생성하는 방식으로, 배포 경로를 명시적으로 제어할 수 있습니다.

$CATALINA_HOME/conf/
└── Catalina/
└── localhost/
├── ROOT.xml → / (루트 컨텍스트)
├── myapp.xml → /myapp
└── api.xml → /api

기본 Context XML

<!-- conf/Catalina/localhost/myapp.xml -->
<Context docBase="/var/www/myapp"
path="/myapp"
reloadable="false"
crossContext="false"
privileged="false">
</Context>

JNDI 데이터소스 포함

<!-- conf/Catalina/localhost/myapp.xml -->
<Context docBase="/var/www/myapp"
path="/myapp"
reloadable="false">

<Resource name="jdbc/myDB"
auth="Container"
type="javax.sql.DataSource"
factory="org.apache.tomcat.jdbc.pool.DataSourceFactory"
driverClassName="com.mysql.cj.jdbc.Driver"
url="jdbc:mysql://db-host:3306/mydb?useSSL=false&amp;serverTimezone=Asia/Seoul"
username="appuser"
password="AppP@ssw0rd"
maxTotal="50"
maxIdle="10"
minIdle="5"
maxWaitMillis="30000"
validationQuery="SELECT 1"
testOnBorrow="true"
removeAbandoned="true"
removeAbandonedTimeout="60"
logAbandoned="true"/>
</Context>

ROOT 컨텍스트 교체 (루트 경로에 앱 배포)

<!-- conf/Catalina/localhost/ROOT.xml -->
<Context docBase="/var/www/myapp/current"
reloadable="false">
</Context>

이 설정으로 /var/www/myapp/current 디렉터리의 앱이 http://host:8080/에서 서빙됩니다.


다중 가상 호스트 설정

server.xml 설정

<Engine name="Catalina" defaultHost="localhost">

<!-- 기본 호스트 (개발용) -->
<Host name="localhost" appBase="webapps"
unpackWARs="true" autoDeploy="false">
</Host>

<!-- 프로덕션 호스트 1 -->
<Host name="app1.example.com" appBase="/var/www/app1"
unpackWARs="true" autoDeploy="false">
<Alias>www.app1.example.com</Alias>
<Valve className="org.apache.catalina.valves.AccessLogValve"
directory="logs"
prefix="app1_access_log"
suffix=".txt"
pattern="%h %l %u %t &quot;%r&quot; %s %b %D"/>
</Host>

<!-- 프로덕션 호스트 2 -->
<Host name="app2.example.com" appBase="/var/www/app2"
unpackWARs="true" autoDeploy="false">
</Host>

</Engine>

각 가상 호스트 Context 파일 구조

conf/
└── Catalina/
├── localhost/
│ └── ROOT.xml
├── app1.example.com/
│ └── ROOT.xml → app1의 루트 컨텍스트
└── app2.example.com/
└── ROOT.xml → app2의 루트 컨텍스트

Tomcat Manager를 통한 배포

Manager 앱 계정 설정

<!-- conf/tomcat-users.xml -->
<?xml version="1.0" encoding="UTF-8"?>
<tomcat-users>
<!-- 관리자 계정 (강력한 패스워드 사용!) -->
<role rolename="manager-gui"/>
<role rolename="manager-script"/>
<role rolename="admin-gui"/>
<user username="admin"
password="MyStr0ngP@ssw0rd!"
roles="manager-gui,manager-script,admin-gui"/>
</tomcat-users>

Manager 앱 접근 IP 제한

기본적으로 Manager 앱은 localhost에서만 접근 가능합니다. 원격 접근이 필요하다면:

<!-- webapps/manager/META-INF/context.xml -->
<Context antiResourceLocking="false" privileged="true">
<CookieProcessor className="org.apache.tomcat.util.http.Rfc6265CookieProcessor"
sameSiteCookies="strict"/>
<Valve className="org.apache.catalina.valves.RemoteAddrValve"
allow="127\.0\.0\.1|192\.168\.1\.\d+"/>
<!-- localhost + 내부망만 허용 -->
</Context>

curl로 원격 배포 (CI/CD 통합)

# WAR 파일 배포
curl -u admin:MyStr0ngP@ssw0rd! \
"http://localhost:8080/manager/text/deploy?path=/myapp&update=true" \
--upload-file /path/to/myapp.war

# 애플리케이션 목록 확인
curl -u admin:MyStr0ngP@ssw0rd! \
"http://localhost:8080/manager/text/list"

# 애플리케이션 언배포
curl -u admin:MyStr0ngP@ssw0rd! \
"http://localhost:8080/manager/text/undeploy?path=/myapp"

# 재시작
curl -u admin:MyStr0ngP@ssw0rd! \
"http://localhost:8080/manager/text/restart?path=/myapp"

무중단 배포 패턴

패턴 1: WAR 파일 교체 + 즉시 재시작

#!/bin/bash
set -e

CATALINA_HOME=/opt/tomcat/latest
APP_NAME=myapp
WAR_FILE=/tmp/myapp-1.2.0.war

# 1. 이전 WAR 백업
if [ -f "$CATALINA_HOME/webapps/${APP_NAME}.war" ]; then
cp "$CATALINA_HOME/webapps/${APP_NAME}.war" \
"/var/backup/${APP_NAME}-$(date +%Y%m%d-%H%M%S).war"
fi

# 2. 기존 배포 디렉터리 제거 (stale class 방지)
rm -rf "$CATALINA_HOME/webapps/${APP_NAME}"
rm -f "$CATALINA_HOME/webapps/${APP_NAME}.war"

# 3. 작업 디렉터리 초기화
rm -rf "$CATALINA_HOME/work/Catalina/localhost/${APP_NAME}"

# 4. 새 WAR 복사
cp "$WAR_FILE" "$CATALINA_HOME/webapps/${APP_NAME}.war"

# 5. Tomcat 재시작
sudo systemctl restart tomcat

echo "배포 완료: ${APP_NAME}"

패턴 2: 심볼릭 링크 + 무중단 (Nginx 앞단)

#!/bin/bash
# Blue-Green 배포 (Nginx + 2개 Tomcat 인스턴스)

BLUE_PORT=8080
GREEN_PORT=8081
NEW_WAR=/tmp/myapp-1.2.0.war

# 현재 Active 인스턴스 확인
ACTIVE=$(cat /var/run/active-tomcat)

if [ "$ACTIVE" = "blue" ]; then
TARGET_PORT=$GREEN_PORT
NEW_ACTIVE="green"
else
TARGET_PORT=$BLUE_PORT
NEW_ACTIVE="blue"
fi

# 비활성 인스턴스에 배포
cp "$NEW_WAR" "/opt/tomcat-${NEW_ACTIVE}/webapps/ROOT.war"
systemctl restart "tomcat-${NEW_ACTIVE}"

# 헬스체크
sleep 10
HTTP_STATUS=$(curl -s -o /dev/null -w "%{http_code}" \
http://localhost:${TARGET_PORT}/actuator/health)

if [ "$HTTP_STATUS" = "200" ]; then
# Nginx 설정 전환
sed -i "s/proxy_pass http:\/\/localhost:[0-9]*/proxy_pass http:\/\/localhost:${TARGET_PORT}/" \
/etc/nginx/sites-available/myapp.conf
nginx -s reload

echo "$NEW_ACTIVE" > /var/run/active-tomcat
echo "✅ 배포 성공: ${NEW_ACTIVE} (포트 ${TARGET_PORT})"
else
echo "❌ 헬스체크 실패 — 롤백"
exit 1
fi

배포 후 확인

# Tomcat 로그로 배포 상태 확인
tail -100 /opt/tomcat/latest/logs/catalina.out | grep -E "(deploy|error|warn)" -i

# 컨텍스트 로드 성공 메시지
# INFO [main] org.apache.catalina.startup.HostConfig.deployWAR
# Deployment of web application archive [.../myapp.war] has finished in X ms

# 접근 테스트
curl -s -o /dev/null -w "%{http_code}" http://localhost:8080/myapp/
# 200

# Manager API로 배포된 앱 목록 확인
curl -u admin:password http://localhost:8080/manager/text/list

Summary

항목내용
기본 배포 경로$CATALINA_HOME/webapps/
권장 배포 방식Context XML 파일 + autoDeploy="false"
ROOT 컨텍스트conf/Catalina/localhost/ROOT.xml
Manager 보안강력한 패스워드 + IP 제한
CI/CD 통합Manager REST API (curl 사용)
무중단 배포Blue-Green 패턴 + Nginx 포트 전환
Advertisement