운영 웹서버(csv.wise.ai.kr) 구축 및 개발→운영 자동 배포 연결
All checks were successful
deploy-dev / deploy (push) Successful in 36s
All checks were successful
deploy-dev / deploy (push) Successful in 36s
웹 티어(211.37.173.197 / Rocky 8): - csv.wise.ai.kr nginx vhost + Let's Encrypt SSL - WAS는 SSH 터널(arko-was-tunnel.service)로 연결 — 개발서버가 NAT 뒤라 8088이 포워딩되지 않고 Tomcat도 127.0.0.1 바인딩이기 때문이다. 키는 WAS에서 restrict,permitopen="127.0.0.1:8088" 로 묶어 셸 접근 불가. - 정적 리소스는 운영 웹이 직접 서빙하고 없으면 @was 폴백 — 전환 중에도 깨지지 않는다. 파이프라인: git push -> 개발 WAS 배포 -> 개발 헬스체크 -> 운영 웹 정적 배포 -> 운영 검증 개발 헬스체크를 통과한 뒤에만 운영으로 넘어간다. 접속 방향은 개발->운영(개발서버는 NAT 뒤라 역방향 접속이 불가능하다).
This commit is contained in:
parent
62ef19c78f
commit
7376c99f17
@ -8,7 +8,11 @@
|
||||
#
|
||||
# [개발자 PC] bash deploy/dev/build-and-upload.sh → 빌드 + WAR 업로드
|
||||
# [개발자 PC] git push origin master → 이 워크플로 자동 실행
|
||||
# [서버] ROOT 재전개 + 환경설정 주입 + 재기동 + 헬스체크(+실패 시 롤백)
|
||||
# [개발서버] ROOT 재전개 + 환경설정 주입 + 재기동 + 헬스체크(+실패 시 롤백)
|
||||
# [개발→운영] 개발 헬스체크 통과 시 운영 웹(211.37.173.197)으로 정적 리소스 배포
|
||||
#
|
||||
# 접속 방향이 개발 → 운영인 이유: 개발서버는 NAT 뒤라 외부에서 먼저 접속할 수 없고,
|
||||
# 운영 웹서버는 공인망에 SSH(9271)가 열려 있어 개발서버에서 나갈 수 있다.
|
||||
#
|
||||
# ※ Gitea 1.22.3 기준으로 작성했다. 이 버전은 workflow_dispatch(수동 실행 버튼)와
|
||||
# inputs 컨텍스트를 지원하지 않는다 — 넣으면 워크플로 자체가 목록에 뜨지 않는다.
|
||||
@ -34,7 +38,8 @@ concurrency:
|
||||
env:
|
||||
APP_HOME: /opt/arko-dev
|
||||
INCOMING_WAR: /opt/arko-dev/incoming/arko.war
|
||||
SITE_URL: https://csv.zioinfo.co.kr/
|
||||
SITE_URL: https://csv.zioinfo.co.kr/ # 개발 웹 (개발서버 nginx)
|
||||
PROD_SITE_URL: https://csv.wise.ai.kr/ # 운영 웹 (211.37.173.197)
|
||||
|
||||
jobs:
|
||||
deploy:
|
||||
@ -71,7 +76,7 @@ jobs:
|
||||
set -e
|
||||
bash "$APP_HOME/bin/arko-dev-deploy.sh" "$INCOMING_WAR"
|
||||
|
||||
- name: 결과 확인
|
||||
- name: 개발 결과 확인
|
||||
run: |
|
||||
set -e
|
||||
CODE=000
|
||||
@ -86,6 +91,23 @@ jobs:
|
||||
echo "$SITE_URL → HTTP $EXT"
|
||||
|
||||
case "$CODE" in
|
||||
200|302) echo "배포 정상" ;;
|
||||
200|302) echo "개발 배포 정상" ;;
|
||||
*) echo "::error::Tomcat 응답 없음 (HTTP $CODE)"; exit 1 ;;
|
||||
esac
|
||||
|
||||
# 개발 헬스체크를 통과한 뒤에만 운영 웹으로 넘어간다.
|
||||
# 개발이 깨진 산출물을 운영 웹에 밀어 넣지 않기 위한 순서다.
|
||||
- name: 운영 웹서버 배포
|
||||
run: |
|
||||
set -e
|
||||
bash "$APP_HOME/bin/arko-prodweb-deploy.sh"
|
||||
|
||||
- name: 운영 결과 확인
|
||||
run: |
|
||||
set -e
|
||||
CODE=$(curl -s -o /dev/null -w "%{http_code}" --max-time 30 "$PROD_SITE_URL" || echo 000)
|
||||
echo "$PROD_SITE_URL → HTTP $CODE"
|
||||
case "$CODE" in
|
||||
200|302) echo "운영 웹 배포 정상" ;;
|
||||
*) echo "::error::운영 웹 응답 없음 (HTTP $CODE) — 터널(arko-was-tunnel) 상태를 확인할 것"; exit 1 ;;
|
||||
esac
|
||||
|
||||
@ -1,84 +1,80 @@
|
||||
#!/usr/bin/env bash
|
||||
# csv.wise.ai.kr 웹 티어 구축 — 웹서버에서 실행
|
||||
# csv.wise.ai.kr 웹 티어 구축 — 웹서버(utimsurpai.cafe24.com / 211.37.173.197)에서 실행
|
||||
#
|
||||
# 사용법: bash 01-web-server-setup.sh [WAS주소]
|
||||
# WAS주소 기본값 101.79.17.164:8088 (같은 사설망이면 10.0.1.6:8088 로 주면 된다)
|
||||
#
|
||||
# 이 서버는 nginx만 올린다. WAS(Tomcat)와 DB(MariaDB)는 개발서버(101.79.17.164)를 그대로 쓴다.
|
||||
# 사용법: bash 01-web-server-setup.sh
|
||||
# 멱등: 다시 실행해도 안전하다.
|
||||
#
|
||||
# 이 서버는 nginx만 담당한다. WAS(Tomcat)와 DB(MariaDB)는 개발서버(101.79.17.164)를 그대로 쓴다.
|
||||
#
|
||||
# 선행 조건:
|
||||
# 1) /root/.ssh/id_arko_tunnel 키가 있고, 그 공개키가 WAS의 authorized_keys에
|
||||
# restrict,permitopen="127.0.0.1:8088" 로 등록되어 있을 것
|
||||
# (WAS에서 deploy/web/03-was-tunnel-key.sh 실행)
|
||||
# 2) csv.wise.ai.kr A/CNAME 레코드가 이 서버를 가리킬 것
|
||||
set -euo pipefail
|
||||
|
||||
WAS_ADDR=${1:-101.79.17.164:8088}
|
||||
DOMAIN=csv.wise.ai.kr
|
||||
WAS_HOST=101.79.17.164
|
||||
KEY=/root/.ssh/id_arko_tunnel
|
||||
SRC_DIR=$(cd "$(dirname "$0")" && pwd)
|
||||
|
||||
log() { echo -e "\n[$(date +'%F %T')] === $* ==="; }
|
||||
|
||||
# ----------------------------------------------------------- 1. nginx 설치
|
||||
log "1. nginx 확인"
|
||||
if command -v nginx > /dev/null; then
|
||||
nginx -v 2>&1
|
||||
else
|
||||
echo "nginx 설치"
|
||||
apt-get update -qq
|
||||
apt-get install -y nginx
|
||||
fi
|
||||
# ------------------------------------------------------- 1. 사전 확인
|
||||
log "1. 사전 확인"
|
||||
command -v nginx > /dev/null || { echo "nginx가 없다"; exit 1; }
|
||||
nginx -v 2>&1
|
||||
[ -f "$KEY" ] || { echo "터널 키가 없다: $KEY"; exit 1; }
|
||||
echo "터널 키 확인"
|
||||
|
||||
# sites-enabled 구조가 없는 배포판(예: RHEL 계열)이면 만들어 준다
|
||||
mkdir -p /etc/nginx/sites-available /etc/nginx/sites-enabled
|
||||
if ! grep -q "sites-enabled" /etc/nginx/nginx.conf; then
|
||||
echo "경고: nginx.conf 가 sites-enabled 를 include 하지 않는다. 수동 확인 필요."
|
||||
fi
|
||||
# --------------------------------------------------------- 2. 터널
|
||||
log "2. WAS 터널 서비스"
|
||||
install -m 644 "$SRC_DIR/arko-was-tunnel.service" /etc/systemd/system/arko-was-tunnel.service
|
||||
systemctl daemon-reload
|
||||
systemctl enable arko-was-tunnel
|
||||
systemctl restart arko-was-tunnel
|
||||
|
||||
# ------------------------------------------------- 2. WAS 도달 여부 확인
|
||||
log "2. WAS 도달 확인 ($WAS_ADDR)"
|
||||
CODE=$(curl -s -o /dev/null -w "%{http_code}" --max-time 15 -H "Host: $DOMAIN" "http://$WAS_ADDR/" || echo 000)
|
||||
echo "http://$WAS_ADDR/ → HTTP $CODE"
|
||||
if [ "$CODE" = "000" ]; then
|
||||
cat <<EOF
|
||||
중단: WAS에 도달할 수 없다.
|
||||
- WAS서버(101.79.17.164)에서 deploy/web/02-was-expose.sh <이 웹서버IP> 를 먼저 실행할 것
|
||||
(Tomcat 바인딩 확대 + 방화벽에서 이 서버 IP만 8088 허용)
|
||||
- 같은 사설망이면 WAS주소를 10.0.1.6:8088 로 주고 다시 실행할 것
|
||||
EOF
|
||||
for i in $(seq 1 20); do
|
||||
ss -lnt 2>/dev/null | grep -q "127.0.0.1:8088" && break
|
||||
sleep 1
|
||||
done
|
||||
|
||||
if ! ss -lnt 2>/dev/null | grep -q "127.0.0.1:8088"; then
|
||||
echo "터널이 열리지 않았다"
|
||||
systemctl status arko-was-tunnel --no-pager | tail -15
|
||||
exit 1
|
||||
fi
|
||||
echo "터널 개통: 127.0.0.1:8088 → $WAS_HOST"
|
||||
|
||||
# --------------------------------------------------------- 3. vhost 배치
|
||||
log "3. nginx 가상호스트 등록"
|
||||
install -m 644 "$SRC_DIR/$DOMAIN.conf" "/etc/nginx/sites-available/$DOMAIN.conf"
|
||||
CODE=$(curl -s -o /dev/null -w "%{http_code}" --max-time 20 -H "Host: $DOMAIN" http://127.0.0.1:8088/ || echo 000)
|
||||
echo "WAS 응답 → HTTP $CODE"
|
||||
[ "$CODE" = "200" ] || [ "$CODE" = "302" ] || { echo "WAS가 정상 응답하지 않는다"; exit 1; }
|
||||
|
||||
# upstream 주소를 인자 값으로 교체
|
||||
sed -i "s|server 101.79.17.164:8088;|server $WAS_ADDR;|" "/etc/nginx/sites-available/$DOMAIN.conf"
|
||||
grep -n "server .*:8088;" "/etc/nginx/sites-available/$DOMAIN.conf"
|
||||
|
||||
ln -sfn "/etc/nginx/sites-available/$DOMAIN.conf" "/etc/nginx/sites-enabled/$DOMAIN.conf"
|
||||
# --------------------------------------------------------- 3. nginx
|
||||
log "3. nginx 가상호스트"
|
||||
# 이 서버는 sites-enabled 없이 conf.d 만 include 한다
|
||||
install -m 644 "$SRC_DIR/$DOMAIN.conf" "/etc/nginx/conf.d/$DOMAIN.conf"
|
||||
|
||||
if nginx -t; then
|
||||
systemctl reload nginx
|
||||
echo "nginx 반영 완료"
|
||||
else
|
||||
rm -f "/etc/nginx/sites-enabled/$DOMAIN.conf"
|
||||
echo "nginx 설정 오류 → 링크 제거하고 중단"
|
||||
rm -f "/etc/nginx/conf.d/$DOMAIN.conf"
|
||||
echo "nginx 설정 오류 → 제거하고 중단"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# ------------------------------------------------------------- 4. 확인
|
||||
log "4. 프록시 확인"
|
||||
CODE=$(curl -s -o /dev/null -w "%{http_code}" --max-time 30 -H "Host: $DOMAIN" http://127.0.0.1/ || echo 000)
|
||||
echo "nginx 경유 → HTTP $CODE"
|
||||
curl -s --max-time 30 -H "Host: $DOMAIN" http://127.0.0.1/ | grep -oiE "<title>[^<]*</title>" | head -1
|
||||
|
||||
# --------------------------------------------------------------- 5. SSL
|
||||
log "5. SSL"
|
||||
# ----------------------------------------------------------- 4. SSL
|
||||
log "4. SSL"
|
||||
if [ -d "/etc/letsencrypt/live/$DOMAIN" ]; then
|
||||
echo "인증서 이미 존재"
|
||||
echo "인증서 이미 존재 — 건너뜀"
|
||||
else
|
||||
cat <<EOF
|
||||
DNS A 레코드($DOMAIN → 이 서버 IP)가 등록된 뒤에 실행할 것:
|
||||
certbot --nginx -d $DOMAIN --non-interactive --agree-tos --redirect
|
||||
certbot 미설치 시: apt-get install -y certbot python3-certbot-nginx
|
||||
EOF
|
||||
certbot --nginx -d "$DOMAIN" --non-interactive --agree-tos --redirect
|
||||
fi
|
||||
|
||||
log "완료"
|
||||
echo "확인: https://$DOMAIN/"
|
||||
|
||||
41
deploy/web/03-was-tunnel-key.sh
Normal file
41
deploy/web/03-was-tunnel-key.sh
Normal file
@ -0,0 +1,41 @@
|
||||
#!/usr/bin/env bash
|
||||
# WAS서버(zio-server / 101.79.17.164)에서 실행 — 웹서버의 터널 전용 공개키를 등록한다.
|
||||
#
|
||||
# 사용법: bash 03-was-tunnel-key.sh '<웹서버 공개키 한 줄>'
|
||||
#
|
||||
# WAS는 NAT 뒤에 있고 8088은 포워딩되지 않는다. 그래서 웹서버가 WAS로 SSH 터널을 열어
|
||||
# 자기 쪽 127.0.0.1:8088 을 WAS의 127.0.0.1:8088 에 연결한다.
|
||||
#
|
||||
# 이 키는 터널 외에는 아무것도 못 하도록 묶는다:
|
||||
# restrict 모든 기능 비활성(셸/PTY/에이전트/X11 전부 차단)
|
||||
# port-forwarding 그 중 포트 포워딩만 다시 허용
|
||||
# permitopen 열 수 있는 대상을 127.0.0.1:8088 하나로 제한
|
||||
# 즉 이 키가 유출되어도 WAS에서 할 수 있는 일은 arko Tomcat 접속뿐이다.
|
||||
set -euo pipefail
|
||||
|
||||
PUBKEY=${1:-}
|
||||
[ -n "$PUBKEY" ] || { echo "사용법: $0 '<공개키>'"; exit 1; }
|
||||
echo "$PUBKEY" | grep -q "^ssh-" || { echo "공개키 형식이 아니다"; exit 1; }
|
||||
|
||||
AK=/root/.ssh/authorized_keys
|
||||
TS=$(date +%Y%m%d_%H%M%S)
|
||||
RESTRICT='restrict,port-forwarding,permitopen="127.0.0.1:8088"'
|
||||
|
||||
mkdir -p /root/.ssh
|
||||
chmod 700 /root/.ssh
|
||||
touch "$AK"
|
||||
cp -f "$AK" "$AK.bak_$TS"
|
||||
echo "백업: $AK.bak_$TS"
|
||||
|
||||
KEY_BODY=$(echo "$PUBKEY" | awk '{print $2}')
|
||||
if grep -q "$KEY_BODY" "$AK"; then
|
||||
echo "이미 등록된 키 — 건너뜀"
|
||||
else
|
||||
echo "$RESTRICT $PUBKEY" >> "$AK"
|
||||
echo "등록 완료"
|
||||
fi
|
||||
chmod 600 "$AK"
|
||||
|
||||
echo
|
||||
echo "=== 현재 authorized_keys (키 본문은 생략) ==="
|
||||
awk '{ printf "%-70s ... %s\n", substr($0,1,70), $NF }' "$AK"
|
||||
76
deploy/web/04-prod-web-deploy.sh
Normal file
76
deploy/web/04-prod-web-deploy.sh
Normal file
@ -0,0 +1,76 @@
|
||||
#!/usr/bin/env bash
|
||||
# 개발서버(zio-server)에서 실행 — 운영 웹서버로 정적 리소스를 배포한다.
|
||||
#
|
||||
# 설치 위치: /opt/arko-dev/bin/arko-prodweb-deploy.sh
|
||||
# 호출 주체: Gitea Actions(.gitea/workflows/deploy-dev.yml) 마지막 단계, 또는 수동
|
||||
#
|
||||
# 흐름: git push → CI → 개발 WAS 배포 → (헬스체크 통과) → 이 스크립트 → 운영 웹 반영
|
||||
#
|
||||
# 방향이 개발 → 운영이다. 운영 웹서버(211.37.173.197)는 NAT 밖 공인망에 있고
|
||||
# SSH 9271이 열려 있어 개발서버에서 바로 접속할 수 있다.
|
||||
# 반대로 개발서버는 NAT 뒤라 운영에서 먼저 접속할 수 없다.
|
||||
#
|
||||
# 배포 대상은 방금 개발 WAS에 전개된 ROOT의 정적 리소스다.
|
||||
# WAR를 다시 풀지 않고 실제 서비스 중인 파일을 그대로 복사하므로
|
||||
# 개발과 운영 웹이 항상 같은 산출물을 바라본다.
|
||||
set -euo pipefail
|
||||
|
||||
PROD_HOST=211.37.173.197
|
||||
PROD_PORT=9271
|
||||
PROD_USER=root
|
||||
KEY=/root/.ssh/id_arko_prodweb
|
||||
SRC_ROOT=/opt/arko-dev/tomcat/webapps/ROOT
|
||||
DEST=/var/www/csv.wise.ai.kr/static
|
||||
SITE=https://csv.wise.ai.kr/
|
||||
DIRS="images css js fonts new"
|
||||
|
||||
log() { echo "[$(date +'%F %T')] $*"; }
|
||||
die() { echo "[$(date +'%F %T')] ERROR: $*"; exit 1; }
|
||||
|
||||
SSH_OPTS="-p $PROD_PORT -i $KEY -o IdentitiesOnly=yes -o StrictHostKeyChecking=accept-new -o ConnectTimeout=20 -o BatchMode=yes"
|
||||
|
||||
# ------------------------------------------------------------ 1. 사전 확인
|
||||
[ -f "$KEY" ] || die "배포 키가 없다: $KEY"
|
||||
[ -d "$SRC_ROOT" ] || die "전개된 ROOT가 없다: $SRC_ROOT (개발 배포가 선행되어야 한다)"
|
||||
|
||||
log "운영 웹서버 접속 확인 ($PROD_HOST:$PROD_PORT)"
|
||||
ssh $SSH_OPTS "$PROD_USER@$PROD_HOST" "test -d $DEST" \
|
||||
|| die "접속 또는 대상 디렉토리 확인 실패 — 운영 웹에서 05-prodweb-prepare.sh 를 먼저 실행할 것"
|
||||
|
||||
# ------------------------------------------------------------ 2. 동기화
|
||||
# --delete 는 쓰지 않는다. 운영 웹에만 있는 파일(수동 배치분)을 지워버릴 수 있고,
|
||||
# 정적 리소스는 누적되어도 문제가 없다. 대신 크기·시각이 다른 것만 전송한다.
|
||||
TOTAL=0
|
||||
for d in $DIRS; do
|
||||
if [ ! -d "$SRC_ROOT/$d" ]; then
|
||||
log "건너뜀(원본 없음): $d"
|
||||
continue
|
||||
fi
|
||||
SIZE=$(du -sh "$SRC_ROOT/$d" | cut -f1)
|
||||
log "동기화: $d ($SIZE)"
|
||||
OUT=$(rsync -az --stats --human-readable \
|
||||
-e "ssh $SSH_OPTS" \
|
||||
"$SRC_ROOT/$d/" "$PROD_USER@$PROD_HOST:$DEST/$d/" 2>&1) || die "rsync 실패: $d"
|
||||
N=$(echo "$OUT" | grep -oE "Number of regular files transferred: [0-9,]+" | grep -oE "[0-9,]+$" | tr -d ',')
|
||||
N=${N:-0}
|
||||
TOTAL=$((TOTAL + N))
|
||||
log " 전송 $N 개"
|
||||
done
|
||||
log "총 전송 파일 수: $TOTAL"
|
||||
|
||||
# ------------------------------------------------------------ 3. 검증
|
||||
log "운영 웹 확인"
|
||||
CODE=$(curl -s -o /dev/null -w "%{http_code}" --max-time 30 "$SITE" || echo 000)
|
||||
log "$SITE → HTTP $CODE"
|
||||
[ "$CODE" = "200" ] || [ "$CODE" = "302" ] || die "운영 웹이 정상 응답하지 않는다 (HTTP $CODE)"
|
||||
|
||||
# 정적 파일이 실제로 운영 웹에서 나오는지 표본 확인.
|
||||
# X-Cache 헤더가 없으므로 nginx access_log 대신 응답 코드로만 판단한다.
|
||||
SAMPLE=$(find "$SRC_ROOT/images" -maxdepth 2 -type f \( -name "*.png" -o -name "*.jpg" -o -name "*.gif" \) 2>/dev/null | head -1)
|
||||
if [ -n "$SAMPLE" ]; then
|
||||
REL=${SAMPLE#$SRC_ROOT}
|
||||
SCODE=$(curl -s -o /dev/null -w "%{http_code}" --max-time 20 "https://csv.wise.ai.kr$REL" || echo 000)
|
||||
log "표본 정적 파일 $REL → HTTP $SCODE"
|
||||
fi
|
||||
|
||||
log "운영 웹 배포 완료"
|
||||
115
deploy/web/05-prodweb-prepare.sh
Normal file
115
deploy/web/05-prodweb-prepare.sh
Normal file
@ -0,0 +1,115 @@
|
||||
#!/usr/bin/env bash
|
||||
# 운영 웹서버(utimsurpai.cafe24.com / 211.37.173.197)에서 실행 — 자동 배포 수신 준비.
|
||||
#
|
||||
# 사용법: bash 05-prodweb-prepare.sh '<개발서버 공개키 한 줄>'
|
||||
#
|
||||
# 하는 일:
|
||||
# 1) 개발서버(101.79.17.164) 배포 키 등록 — 출발지 IP 고정 + 셸 부가기능 차단
|
||||
# 2) 정적 리소스 디렉토리 생성 (/var/www/csv.wise.ai.kr/static)
|
||||
# 3) nginx vhost의 정적 경로를 "로컬 파일 우선, 없으면 WAS 프록시"로 전환
|
||||
#
|
||||
# 3)이 핵심이다. 이렇게 해야 배포가 의미를 갖는다 —
|
||||
# 정적 파일을 운영 웹서버가 직접 서빙하므로 WAS 왕복과 SSH 터널 트래픽이 줄고,
|
||||
# 아직 배포되지 않은 파일은 @was 폴백으로 그대로 나가서 전환 중에도 깨지지 않는다.
|
||||
set -euo pipefail
|
||||
|
||||
PUBKEY=${1:-}
|
||||
[ -n "$PUBKEY" ] || { echo "사용법: $0 '<공개키>'"; exit 1; }
|
||||
echo "$PUBKEY" | grep -q "^ssh-" || { echo "공개키 형식이 아니다"; exit 1; }
|
||||
|
||||
DEV_IP=101.79.17.164
|
||||
DOMAIN=csv.wise.ai.kr
|
||||
STATIC_ROOT=/var/www/$DOMAIN/static
|
||||
VHOST=/etc/nginx/conf.d/$DOMAIN.conf
|
||||
TS=$(date +%Y%m%d_%H%M%S)
|
||||
|
||||
# ------------------------------------------------------------ 1. 키 등록
|
||||
echo "=== 1. 배포 키 등록 ==="
|
||||
AK=/root/.ssh/authorized_keys
|
||||
mkdir -p /root/.ssh && chmod 700 /root/.ssh && touch "$AK"
|
||||
cp -f "$AK" "$AK.bak_$TS"
|
||||
|
||||
# rsync를 써야 하므로 restrict(명령 실행 전면 차단)는 쓸 수 없다.
|
||||
# 대신 출발지 IP를 개발서버로 고정하고 부가 기능은 모두 끈다.
|
||||
OPTS="from=\"$DEV_IP\",no-agent-forwarding,no-port-forwarding,no-x11-forwarding,no-pty"
|
||||
KEY_BODY=$(echo "$PUBKEY" | awk '{print $2}')
|
||||
if grep -q "$KEY_BODY" "$AK"; then
|
||||
echo "이미 등록됨 — 건너뜀"
|
||||
else
|
||||
echo "$OPTS $PUBKEY" >> "$AK"
|
||||
echo "등록 완료 (출발지 $DEV_IP 로 제한)"
|
||||
fi
|
||||
chmod 600 "$AK"
|
||||
|
||||
# -------------------------------------------------- 2. 정적 디렉토리
|
||||
echo
|
||||
echo "=== 2. 정적 리소스 디렉토리 ==="
|
||||
mkdir -p "$STATIC_ROOT"
|
||||
chown -R nginx:nginx "/var/www/$DOMAIN" 2>/dev/null || chown -R root:root "/var/www/$DOMAIN"
|
||||
ls -ld "$STATIC_ROOT"
|
||||
|
||||
# ------------------------------------------------------ 3. vhost 전환
|
||||
echo
|
||||
echo "=== 3. nginx 정적 경로 전환 ==="
|
||||
cp -f "$VHOST" "$VHOST.bak_$TS"
|
||||
echo "백업: $VHOST.bak_$TS"
|
||||
|
||||
if grep -q "location @was" "$VHOST"; then
|
||||
echo "이미 전환됨 — 건너뜀"
|
||||
else
|
||||
# 기존 정적 location 블록(프록시)을 로컬 우선 + 폴백 구조로 교체한다.
|
||||
python3 - "$VHOST" "$STATIC_ROOT" <<'PY'
|
||||
import re, sys
|
||||
path, static_root = sys.argv[1], sys.argv[2]
|
||||
src = open(path, encoding='utf-8').read()
|
||||
|
||||
old = re.search(
|
||||
r'\n[ \t]*# ?정적[^\n]*\n[ \t]*location ~\* \^/\(images\|css\|js\|fonts\|new\)/ \{.*?\n[ \t]*\}\n',
|
||||
src, re.S)
|
||||
if not old:
|
||||
old = re.search(r'\n[ \t]*location ~\* \^/\(images\|css\|js\|fonts\|new\)/ \{.*?\n[ \t]*\}\n', src, re.S)
|
||||
if not old:
|
||||
print("정적 location 블록을 찾지 못했다 — 수동 확인 필요")
|
||||
sys.exit(1)
|
||||
|
||||
new = f'''
|
||||
# 정적 리소스: 운영 웹서버가 직접 서빙하고, 없으면 WAS로 폴백한다.
|
||||
# 배포(rsync)로 채워지는 경로 — 아직 없는 파일도 @was 덕분에 깨지지 않는다.
|
||||
location ~* ^/(images|css|js|fonts|new)/ {{
|
||||
root {static_root};
|
||||
try_files $uri @was;
|
||||
expires 10m;
|
||||
add_header Cache-Control "public, max-age=600";
|
||||
access_log off;
|
||||
}}
|
||||
|
||||
# 정적 폴백 — 아직 배포되지 않은 파일은 개발 WAS에서 가져온다
|
||||
location @was {{
|
||||
proxy_pass http://127.0.0.1:8088;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
proxy_read_timeout 300s;
|
||||
}}
|
||||
'''
|
||||
open(path, 'w', encoding='utf-8').write(src[:old.start()] + new + src[old.end():])
|
||||
print("정적 경로 전환 완료")
|
||||
PY
|
||||
fi
|
||||
|
||||
echo
|
||||
echo "=== nginx 검증 ==="
|
||||
if nginx -t; then
|
||||
systemctl reload nginx
|
||||
echo "반영 완료"
|
||||
else
|
||||
cp -f "$VHOST.bak_$TS" "$VHOST"
|
||||
echo "설정 오류 → 백업 복구하고 중단"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo
|
||||
echo "=== 확인 ==="
|
||||
curl -s -o /dev/null -w "https://$DOMAIN/ → %{http_code}\n" --max-time 30 "https://$DOMAIN/"
|
||||
40
deploy/web/arko-was-tunnel.service
Normal file
40
deploy/web/arko-was-tunnel.service
Normal file
@ -0,0 +1,40 @@
|
||||
# arko WAS 터널 — 웹서버(utimsurpai.cafe24.com)에서 개발서버 Tomcat으로
|
||||
# 설치 위치: /etc/systemd/system/arko-was-tunnel.service
|
||||
#
|
||||
# 왜 터널인가:
|
||||
# WAS(101.79.17.164)는 NAT 뒤에 있고 8088은 포워딩되지 않는다(22/80/443만 열림).
|
||||
# Tomcat도 127.0.0.1에만 바인딩되어 있다. 포트를 공개로 여는 대신,
|
||||
# 웹서버가 아웃바운드 SSH로 터널을 열어 자기 쪽 127.0.0.1:8088 을 WAS의 Tomcat에 잇는다.
|
||||
# - NAT 변경 불필요, 구간 암호화, Tomcat이 인터넷에 직접 노출되지 않음
|
||||
# - 같은 서버의 uiws-tunnel(5432)과 동일한 방식
|
||||
#
|
||||
# 키는 WAS의 authorized_keys에서 restrict,permitopen="127.0.0.1:8088" 로 묶여 있어
|
||||
# 셸 접근은 불가능하고 이 포트 외에는 열 수 없다.
|
||||
[Unit]
|
||||
Description=SSH tunnel to arko DEV WAS (101.79.17.164:8088)
|
||||
After=network-online.target
|
||||
Wants=network-online.target
|
||||
Before=nginx.service
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
ExecStart=/usr/bin/ssh -N -T \
|
||||
-o ExitOnForwardFailure=yes \
|
||||
-o ServerAliveInterval=30 \
|
||||
-o ServerAliveCountMax=3 \
|
||||
-o StrictHostKeyChecking=accept-new \
|
||||
-o UserKnownHostsFile=/root/.ssh/known_hosts \
|
||||
-o IdentitiesOnly=yes \
|
||||
-i /root/.ssh/id_arko_tunnel \
|
||||
-L 127.0.0.1:8088:127.0.0.1:8088 \
|
||||
root@101.79.17.164
|
||||
|
||||
# 끊기면 계속 재연결한다 — 개발서버가 재부팅되는 일이 잦다(2026-07-29 하루 두 번)
|
||||
Restart=always
|
||||
RestartSec=10
|
||||
|
||||
User=root
|
||||
Group=root
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
@ -1,22 +1,12 @@
|
||||
# csv.wise.ai.kr — arko_renual 웹 티어 (별도 웹서버에 설치)
|
||||
# csv.wise.ai.kr — arko_renual 웹 티어 (utimsurpai.cafe24.com / 211.37.173.197)
|
||||
#
|
||||
# 구성: 브라우저 → [웹서버] nginx 443 → [WAS서버 101.79.17.164] Tomcat 8088
|
||||
# DB는 WAS서버의 MariaDB(csv)를 그대로 사용한다. 웹서버는 DB에 접근하지 않는다.
|
||||
# 구성: 브라우저 → nginx 443 → [SSH 터널] 127.0.0.1:8088 → WAS(101.79.17.164) Tomcat
|
||||
# DB는 WAS서버의 MariaDB(csv)를 그대로 쓴다. 이 서버는 DB에 접근하지 않는다.
|
||||
#
|
||||
# 설치 위치: /etc/nginx/sites-available/csv.wise.ai.kr.conf
|
||||
# → /etc/nginx/sites-enabled/ 에 심볼릭 링크
|
||||
# 설치 위치: /etc/nginx/conf.d/csv.wise.ai.kr.conf (이 서버는 sites-enabled를 쓰지 않는다)
|
||||
#
|
||||
# 선행 조건:
|
||||
# 1) csv.wise.ai.kr A 레코드 → 이 웹서버 IP (현재 미등록)
|
||||
# 2) WAS서버에서 8088을 이 웹서버 IP에만 개방 (deploy/web/02-was-expose.sh)
|
||||
# 3) HTTP로 먼저 올린 뒤 certbot --nginx 가 SSL 블록을 주입
|
||||
|
||||
# WAS 백엔드 — 설치 시 실제 도달 가능한 주소로 바꿀 것
|
||||
# 같은 사설망이면 10.0.1.6:8088, 공인망 경유면 101.79.17.164:8088
|
||||
upstream arko_was {
|
||||
server 101.79.17.164:8088;
|
||||
keepalive 16;
|
||||
}
|
||||
# 127.0.0.1:8088 은 arko-was-tunnel.service 가 만들어 준다.
|
||||
# 터널이 죽으면 502가 나므로 장애 시 `systemctl status arko-was-tunnel` 부터 확인할 것.
|
||||
|
||||
server {
|
||||
server_name csv.wise.ai.kr;
|
||||
@ -24,16 +14,15 @@ server {
|
||||
# 자원봉사 활동사진·첨부파일 업로드가 있어 기본 1m로는 부족하다
|
||||
client_max_body_size 100m;
|
||||
|
||||
# 개발서버이므로 검색엔진 색인 차단
|
||||
# 개발 환경이므로 검색엔진 색인 차단
|
||||
add_header X-Robots-Tag "noindex, nofollow" always;
|
||||
|
||||
access_log /var/log/nginx/csv.wise.ai.kr.access.log;
|
||||
error_log /var/log/nginx/csv.wise.ai.kr.error.log;
|
||||
|
||||
location / {
|
||||
proxy_pass http://arko_was;
|
||||
proxy_pass http://127.0.0.1:8088;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Connection "";
|
||||
|
||||
# Host를 그대로 넘겨야 WAS가 csv.wise.ai.kr 기준으로 링크를 만든다
|
||||
proxy_set_header Host $host;
|
||||
@ -53,11 +42,10 @@ server {
|
||||
proxy_buffers 8 16k;
|
||||
}
|
||||
|
||||
# 정적 리소스 — 웹서버에서 짧게 캐시 (WAS 왕복을 줄인다)
|
||||
# 정적 리소스는 브라우저 캐시만 짧게 준다(개발 환경이라 길게 잡지 않음)
|
||||
location ~* ^/(images|css|js|fonts|new)/ {
|
||||
proxy_pass http://arko_was;
|
||||
proxy_pass http://127.0.0.1:8088;
|
||||
proxy_set_header Host $host;
|
||||
proxy_cache_valid 200 10m;
|
||||
expires 10m;
|
||||
add_header Cache-Control "public, max-age=600";
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user