#!/bin/bash # # SAM React 배포 스크립트 (standalone 모드) # 사용법: ./deploy.sh [dev|prod] # # standalone 빌드: node_modules 없이 server.js 단독 실행 가능 # 서버 메모리 절약 + 빌드 시간 로컬 활용 # set -e # 에러 발생 시 중단 # =========================================== # 설정 # =========================================== ENV="${1:-dev}" BUILD_FILE="next-standalone.tar.gz" # 개발 서버 설정 DEV_SSH="hskwon@114.203.209.83" DEV_PATH="/home/webservice/react" DEV_PORT="3001" # 운영 서버 설정 (추후 설정) # PROD_SSH="user@prod-server" # PROD_PATH="/var/www/react" # PROD_PORT="3000" # 환경별 설정 선택 case $ENV in dev) SSH_TARGET=$DEV_SSH REMOTE_PATH=$DEV_PATH APP_PORT=$DEV_PORT ;; prod) echo "❌ 운영 환경은 아직 설정되지 않았습니다." exit 1 ;; *) echo "❌ 알 수 없는 환경: $ENV" echo "사용법: ./deploy.sh [dev|prod]" exit 1 ;; esac # =========================================== # 함수 정의 # =========================================== log() { echo "" echo "==========================================" echo "$1" echo "==========================================" } error() { echo "" echo "❌ 에러: $1" exit 1 } # =========================================== # 1. 빌드 # =========================================== log "Step 1/5: 로컬 빌드" # .env.local 백업 (.env.production 으로 빌드하기 위해) if [ -f .env.local ]; then echo " .env.local 백업..." mv .env.local .env.local.bak fi # 빌드 실행 echo " npm run build..." npm run build || { # 빌드 실패 시 .env.local 복원 if [ -f .env.local.bak ]; then mv .env.local.bak .env.local fi error "빌드 실패" } # .env.local 복원 if [ -f .env.local.bak ]; then echo " .env.local 복원..." mv .env.local.bak .env.local fi # standalone 빌드 확인 if [ ! -f .next/standalone/server.js ]; then error "standalone 빌드 결과물이 없습니다. next.config.ts에 output: 'standalone' 설정을 확인하세요." fi echo " 빌드 완료" # =========================================== # 2. 압축 (standalone + static + public) # =========================================== log "Step 2/5: 압축" rm -f $BUILD_FILE # standalone 결과물 + static 파일 + public 폴더 압축 echo " standalone 빌드 압축 중..." COPYFILE_DISABLE=1 tar -czf $BUILD_FILE \ .next/standalone \ .next/static \ public FILE_SIZE=$(ls -lh $BUILD_FILE | awk '{print $5}') echo " 압축 완료: $BUILD_FILE ($FILE_SIZE)" # =========================================== # 3. 업로드 # =========================================== log "Step 3/5: 서버 업로드" echo " $SSH_TARGET:$REMOTE_PATH 로 업로드 중..." scp $BUILD_FILE $SSH_TARGET:$REMOTE_PATH/ echo " 업로드 완료" # =========================================== # 4. 원격 배포 실행 # =========================================== log "Step 4/5: 서버 배포" echo " 서버에서 배포 실행 중..." ssh $SSH_TARGET << REMOTE_EOF set -e cd $REMOTE_PATH echo " 기존 프로세스 종료..." lsof -ti:$APP_PORT | xargs kill 2>/dev/null || true sleep 2 echo " 기존 .next 백업..." rm -rf .next.bak mv .next .next.bak 2>/dev/null || true echo " 압축 해제..." tar xzf $BUILD_FILE echo " standalone 배치..." # static 파일을 standalone 안으로 복사 cp -r .next/static .next/standalone/.next/static # public 폴더를 standalone 안으로 복사 cp -r public .next/standalone/public # .env.production 복사 (서버 환경변수) cp .env.production .next/standalone/.env.production 2>/dev/null || true echo " 앱 시작..." cd .next/standalone PORT=$APP_PORT HOSTNAME=0.0.0.0 nohup node server.js > /tmp/sam-react.log 2>&1 & sleep 3 # 실행 확인 if lsof -ti:$APP_PORT > /dev/null 2>&1; then echo " 포트 $APP_PORT 에서 정상 실행 중" else echo " 앱 시작 실패! 로그:" tail -20 /tmp/sam-react.log # 롤백 echo " 롤백 중..." cd $REMOTE_PATH rm -rf .next mv .next.bak .next 2>/dev/null || true exit 1 fi # 정리 cd $REMOTE_PATH rm -f $BUILD_FILE rm -rf .next.bak echo " 서버 배포 완료" REMOTE_EOF # =========================================== # 5. 정리 # =========================================== log "Step 5/5: 로컬 정리" rm -f $BUILD_FILE # =========================================== # 완료 # =========================================== echo "" echo "==========================================" echo "배포 완료!" echo "==========================================" echo "환경: $ENV" echo "서버: $SSH_TARGET" echo "경로: $REMOTE_PATH" echo "포트: $APP_PORT" echo "시간: $(date '+%Y-%m-%d %H:%M:%S')" echo "로그: ssh $SSH_TARGET 'tail -f /tmp/sam-react.log'" echo "=========================================="