#!/bin/bash # # CaStAD Production Server Startup Script # Target: castad1.ktenterprise.net # Version: 3.4.0 # # ═══════════════════════════════════════════════════════════════ # 설정 (필요시 수정) # ═══════════════════════════════════════════════════════════════ APP_NAME="castad" APP_DIR="$(cd "$(dirname "$0")" && pwd)" NODE_PORT=3001 # Express 백엔드 포트 INSTAGRAM_PORT=5001 # Instagram Python 서비스 포트 LOG_DIR="$APP_DIR/logs" PID_DIR="$APP_DIR/pids" # 색상 정의 GREEN='\033[0;32m' RED='\033[0;31m' YELLOW='\033[1;33m' CYAN='\033[0;36m' BOLD='\033[1m' NC='\033[0m' # ═══════════════════════════════════════════════════════════════ # 함수 # ═══════════════════════════════════════════════════════════════ log() { echo -e "${GREEN}[CaStAD]${NC} $(date '+%Y-%m-%d %H:%M:%S') $1"; } error() { echo -e "${RED}[ERROR]${NC} $(date '+%Y-%m-%d %H:%M:%S') $1"; } warn() { echo -e "${YELLOW}[WARN]${NC} $(date '+%Y-%m-%d %H:%M:%S') $1"; } info() { echo -e "${CYAN}[INFO]${NC} $(date '+%Y-%m-%d %H:%M:%S') $1"; } # 디렉토리 생성 init_dirs() { mkdir -p "$LOG_DIR" "$PID_DIR" mkdir -p "$APP_DIR/server/downloads" mkdir -p "$APP_DIR/server/temp" } # 포트 사용 중인지 확인 is_port_in_use() { lsof -i:$1 >/dev/null 2>&1 } # PID 파일에서 프로세스 확인 is_running() { local pid_file="$1" if [ -f "$pid_file" ]; then local pid=$(cat "$pid_file") if ps -p "$pid" > /dev/null 2>&1; then return 0 fi fi return 1 } # ═══════════════════════════════════════════════════════════════ # Instagram 서비스 관리 # ═══════════════════════════════════════════════════════════════ start_instagram() { local pid_file="$PID_DIR/instagram.pid" if is_running "$pid_file"; then info "Instagram 서비스가 이미 실행 중입니다 (PID: $(cat $pid_file))" return 0 fi if [ ! -f "$APP_DIR/server/instagram/instagram_service.py" ]; then warn "Instagram 서비스 파일 없음 - 건너뜁니다" return 1 fi log "Instagram 서비스 시작 중 (포트: $INSTAGRAM_PORT)..." # Python 캐시 삭제 find "$APP_DIR/server/instagram" -name "*.pyc" -delete 2>/dev/null find "$APP_DIR/server/instagram" -name "__pycache__" -type d -exec rm -rf {} + 2>/dev/null # Python 의존성 확인 if ! python3 -c "import instagrapi" 2>/dev/null; then warn "Instagram Python 의존성 설치 중..." pip3 install --break-system-packages -q -r "$APP_DIR/server/instagram/requirements.txt" 2>/dev/null || \ pip3 install -q -r "$APP_DIR/server/instagram/requirements.txt" 2>/dev/null fi # 백그라운드 실행 cd "$APP_DIR/server/instagram" nohup python3 instagram_service.py >> "$LOG_DIR/instagram.log" 2>&1 & echo $! > "$pid_file" cd "$APP_DIR" sleep 2 if curl -s http://localhost:$INSTAGRAM_PORT/health >/dev/null 2>&1; then info "Instagram 서비스 시작됨 (PID: $(cat $pid_file))" return 0 else error "Instagram 서비스 시작 실패" rm -f "$pid_file" return 1 fi } stop_instagram() { local pid_file="$PID_DIR/instagram.pid" if is_running "$pid_file"; then local pid=$(cat "$pid_file") log "Instagram 서비스 중지 중 (PID: $pid)..." kill "$pid" 2>/dev/null sleep 1 kill -9 "$pid" 2>/dev/null rm -f "$pid_file" info "Instagram 서비스 중지됨" else info "Instagram 서비스가 실행 중이 아닙니다" fi } # ═══════════════════════════════════════════════════════════════ # Node.js 백엔드 관리 # ═══════════════════════════════════════════════════════════════ start_backend() { local pid_file="$PID_DIR/backend.pid" if is_running "$pid_file"; then info "백엔드가 이미 실행 중입니다 (PID: $(cat $pid_file))" return 0 fi if is_port_in_use $NODE_PORT; then error "포트 $NODE_PORT 가 이미 사용 중입니다!" error "다른 프로세스 확인: lsof -i:$NODE_PORT" return 1 fi log "백엔드 서버 시작 중 (포트: $NODE_PORT)..." cd "$APP_DIR/server" # 환경변수 설정 export NODE_ENV=production export PORT=$NODE_PORT export FRONTEND_URL="https://castad1.ktenterprise.net" # 백그라운드 실행 nohup node index.js >> "$LOG_DIR/backend.log" 2>&1 & echo $! > "$pid_file" cd "$APP_DIR" sleep 3 if curl -s http://localhost:$NODE_PORT/api/health >/dev/null 2>&1; then info "백엔드 서버 시작됨 (PID: $(cat $pid_file))" return 0 else # 헬스체크 없어도 프로세스가 있으면 OK if is_running "$pid_file"; then info "백엔드 서버 시작됨 (PID: $(cat $pid_file))" return 0 fi error "백엔드 서버 시작 실패 - 로그 확인: $LOG_DIR/backend.log" rm -f "$pid_file" return 1 fi } stop_backend() { local pid_file="$PID_DIR/backend.pid" if is_running "$pid_file"; then local pid=$(cat "$pid_file") log "백엔드 서버 중지 중 (PID: $pid)..." kill "$pid" 2>/dev/null sleep 2 kill -9 "$pid" 2>/dev/null rm -f "$pid_file" info "백엔드 서버 중지됨" else info "백엔드 서버가 실행 중이 아닙니다" fi } # ═══════════════════════════════════════════════════════════════ # 빌드 # ═══════════════════════════════════════════════════════════════ build_frontend() { log "프론트엔드 빌드 중..." cd "$APP_DIR" # 의존성 확인 if [ ! -d "node_modules" ]; then log "npm 패키지 설치 중..." npm install --legacy-peer-deps --silent fi # 빌드 npm run build if [ $? -eq 0 ]; then info "프론트엔드 빌드 완료 (dist/ 폴더)" return 0 else error "프론트엔드 빌드 실패" return 1 fi } # ═══════════════════════════════════════════════════════════════ # 메인 명령어 # ═══════════════════════════════════════════════════════════════ do_start() { echo "" echo -e "${BOLD}${CYAN}╔════════════════════════════════════════════════════════╗${NC}" echo -e "${BOLD}${CYAN}║ CaStAD v3.4.0 - Production Server ║${NC}" echo -e "${BOLD}${CYAN}║ Target: castad1.ktenterprise.net ║${NC}" echo -e "${BOLD}${CYAN}╚════════════════════════════════════════════════════════╝${NC}" echo "" init_dirs # 환경변수 파일 확인 if [ ! -f "$APP_DIR/.env" ]; then error ".env 파일이 없습니다! .env.example을 참고하여 생성해주세요." return 1 fi # .env 로드 set -a source "$APP_DIR/.env" set +a # 서버 의존성 확인 if [ ! -d "$APP_DIR/server/node_modules" ]; then log "서버 npm 패키지 설치 중..." cd "$APP_DIR/server" && npm install --legacy-peer-deps --silent && cd "$APP_DIR" fi # 빌드 확인 if [ ! -d "$APP_DIR/dist" ]; then warn "dist 폴더가 없습니다. 빌드를 먼저 실행하세요: ./startserver.sh build" fi # 서비스 시작 start_instagram start_backend echo "" echo -e "${CYAN}═══════════════════════════════════════════════════════════${NC}" echo -e " ${BOLD}상태${NC}: RUNNING" echo -e " ${BOLD}백엔드${NC}: http://localhost:${NODE_PORT}" echo -e " ${BOLD}Instagram${NC}: http://localhost:${INSTAGRAM_PORT}" echo -e " ${BOLD}로그${NC}: ${LOG_DIR}/" echo -e "${CYAN}═══════════════════════════════════════════════════════════${NC}" echo "" echo -e " ${YELLOW}Nginx 리버스 프록시 설정 필요:${NC}" echo -e " location / { proxy_pass http://127.0.0.1:${NODE_PORT}; }" echo "" } do_stop() { echo "" log "CaStAD 서비스 중지 중..." stop_backend stop_instagram info "모든 서비스 중지 완료" echo "" } do_restart() { do_stop sleep 2 do_start } do_status() { echo "" echo -e "${BOLD}CaStAD 서비스 상태${NC}" echo -e "${CYAN}───────────────────────────────────────${NC}" # 백엔드 if is_running "$PID_DIR/backend.pid"; then echo -e " 백엔드: ${GREEN}실행 중${NC} (PID: $(cat $PID_DIR/backend.pid))" else echo -e " 백엔드: ${RED}중지됨${NC}" fi # Instagram if is_running "$PID_DIR/instagram.pid"; then echo -e " Instagram: ${GREEN}실행 중${NC} (PID: $(cat $PID_DIR/instagram.pid))" else echo -e " Instagram: ${RED}중지됨${NC}" fi # 포트 상태 echo "" echo -e "${CYAN}포트 상태:${NC}" if is_port_in_use $NODE_PORT; then echo -e " 포트 $NODE_PORT: ${GREEN}사용 중${NC}" else echo -e " 포트 $NODE_PORT: ${YELLOW}사용 안함${NC}" fi if is_port_in_use $INSTAGRAM_PORT; then echo -e " 포트 $INSTAGRAM_PORT: ${GREEN}사용 중${NC}" else echo -e " 포트 $INSTAGRAM_PORT: ${YELLOW}사용 안함${NC}" fi echo "" } do_logs() { local service="${1:-backend}" local log_file="$LOG_DIR/${service}.log" if [ -f "$log_file" ]; then echo -e "${CYAN}=== $service 로그 (최근 50줄) ===${NC}" tail -50 "$log_file" echo "" echo -e "${YELLOW}실시간 로그 보기: tail -f $log_file${NC}" else error "로그 파일 없음: $log_file" fi } show_help() { echo "" echo -e "${BOLD}CaStAD 프로덕션 서버 관리 스크립트${NC}" echo "" echo -e "${CYAN}사용법:${NC}" echo " ./startserver.sh " echo "" echo -e "${CYAN}명령어:${NC}" echo " start - 모든 서비스 시작" echo " stop - 모든 서비스 중지" echo " restart - 모든 서비스 재시작" echo " status - 서비스 상태 확인" echo " build - 프론트엔드 빌드" echo " logs - 백엔드 로그 보기" echo " logs instagram - Instagram 서비스 로그 보기" echo "" echo -e "${CYAN}설정:${NC}" echo " 백엔드 포트: $NODE_PORT" echo " Instagram 포트: $INSTAGRAM_PORT" echo " 로그 디렉토리: $LOG_DIR" echo "" echo -e "${CYAN}예시:${NC}" echo " ./startserver.sh build # 먼저 빌드" echo " ./startserver.sh start # 서비스 시작" echo " ./startserver.sh status # 상태 확인" echo "" } # ═══════════════════════════════════════════════════════════════ # 메인 # ═══════════════════════════════════════════════════════════════ case "$1" in start) do_start ;; stop) do_stop ;; restart) do_restart ;; status) do_status ;; build) build_frontend ;; logs) do_logs "$2" ;; *) show_help ;; esac