#!/bin/bash # ============================================================================ # scripts/deploy-nas.sh # D3RO Voice — Automated NAS Docker Deployment & Packaging Script (Bash) # ============================================================================ set -e : "${JWT_SECRET:?JWT_SECRET is required}" : "${JWT_ISSUER:?JWT_ISSUER is required}" : "${JWT_AUDIENCE:?JWT_AUDIENCE is required}" : "${ADMIN_BOOTSTRAP_TOKEN:?ADMIN_BOOTSTRAP_TOKEN is required}" : "${D3RO_API_TOKEN:?D3RO_API_TOKEN is required}" : "${ADMIN_SESSION_SECRET:?ADMIN_SESSION_SECRET is required}" : "${API_SERVER_URL:?API_SERVER_URL is required}" : "${CORS_ALLOWED_ORIGINS:?CORS_ALLOWED_ORIGINS is required}" : "${ALLOWED_HOSTS:?ALLOWED_HOSTS is required}" : "${SUPABASE_URL:?SUPABASE_URL is required}" : "${SUPABASE_SERVICE_ROLE_KEY:?SUPABASE_SERVICE_ROLE_KEY is required}" # Web app (@d3ro/web) build args — NEXT_PUBLIC_* values are baked into the bundle at build time. : "${NEXT_PUBLIC_SUPABASE_URL:?NEXT_PUBLIC_SUPABASE_URL is required}" : "${NEXT_PUBLIC_SUPABASE_ANON_KEY:?NEXT_PUBLIC_SUPABASE_ANON_KEY is required}" for value in \ "$JWT_SECRET" \ "$JWT_ISSUER" \ "$JWT_AUDIENCE" \ "$ADMIN_BOOTSTRAP_TOKEN" \ "$D3RO_API_TOKEN" \ "$ADMIN_SESSION_SECRET" \ "$API_SERVER_URL" \ "$CORS_ALLOWED_ORIGINS" \ "$ALLOWED_HOSTS" \ "$SUPABASE_URL" \ "$SUPABASE_SERVICE_ROLE_KEY" \ "$NEXT_PUBLIC_SUPABASE_URL" \ "$NEXT_PUBLIC_SUPABASE_ANON_KEY" \ "${NEXT_PUBLIC_PAYPLE_CLIENT_KEY:-}"; do case "$value" in *$'\n'*|*$'\r'*) echo "Deployment values must be single-line" >&2; exit 1 ;; esac done if [ "${#D3RO_API_TOKEN}" -lt 32 ]; then echo "D3RO_API_TOKEN must contain at least 32 characters" >&2 exit 1 fi SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" ROOT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)" NAS_HOST="${1:-}" NAS_USER="${2:-yunchan}" NAS_PATH="${3:-/volume1/docker/d3ro}" PORT="${4:-5000}" RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' CYAN='\033[0;36m' NC='\033[0m' echo -e "${CYAN}========================================================${NC}" echo -e "${CYAN} D3RO Voice — NAS Docker Deployment & Packaging Tool ${NC}" echo -e "${CYAN}========================================================${NC}" OUT_DIR="$ROOT_DIR/out/nas-package" mkdir -p "$OUT_DIR" echo -e "\n${YELLOW}[1/4] Building D3RO Voice API & BackOffice Docker Image...${NC}" docker build -t d3ro-voice-api:latest -f "$ROOT_DIR/apps/api-server/Dockerfile" "$ROOT_DIR/apps/api-server" echo -e "${GREEN}Docker image built: d3ro-voice-api:latest${NC}" echo -e "\n${YELLOW}[1.5/4] Building D3RO Voice Next.js Admin CRM Image...${NC}" docker build -t d3ro-voice-admin:latest -f "$ROOT_DIR/apps/admin/Dockerfile" "$ROOT_DIR" echo -e "${GREEN}Docker image built: d3ro-voice-admin:latest${NC}" echo -e "\n${YELLOW}[1.6/4] Building D3RO Voice Next.js Web App Image (/app)...${NC}" if [ -z "${NEXT_PUBLIC_PAYPLE_CLIENT_KEY:-}" ]; then echo -e "${YELLOW}NEXT_PUBLIC_PAYPLE_CLIENT_KEY is empty: Payple checkout will be disabled in the web app.${NC}" fi docker build -t d3ro-voice-web:latest -f "$ROOT_DIR/apps/web/Dockerfile" \ --build-arg "NEXT_PUBLIC_SUPABASE_URL=$NEXT_PUBLIC_SUPABASE_URL" \ --build-arg "NEXT_PUBLIC_SUPABASE_ANON_KEY=$NEXT_PUBLIC_SUPABASE_ANON_KEY" \ --build-arg "NEXT_PUBLIC_PAYPLE_CLIENT_KEY=${NEXT_PUBLIC_PAYPLE_CLIENT_KEY:-}" \ "$ROOT_DIR" echo -e "${GREEN}Docker image built: d3ro-voice-web:latest${NC}" TAR_PATH="$OUT_DIR/d3ro-voice-api.tar" ADMIN_TAR_PATH="$OUT_DIR/d3ro-voice-admin.tar" WEB_TAR_PATH="$OUT_DIR/d3ro-voice-web.tar" echo -e "\n${YELLOW}[2/4] Exporting Docker Images to Archives...${NC}" docker save -o "$TAR_PATH" d3ro-voice-api:latest docker save -o "$ADMIN_TAR_PATH" d3ro-voice-admin:latest docker save -o "$WEB_TAR_PATH" d3ro-voice-web:latest echo -e "${GREEN}Image archives exported: $TAR_PATH, $ADMIN_TAR_PATH, $WEB_TAR_PATH${NC}" echo -e "\n${YELLOW}[3/4] Packaging NAS deployment files...${NC}" cp "$ROOT_DIR/docker-compose.nas.yml" "$OUT_DIR/docker-compose.yml" cp "$ROOT_DIR/scripts/nas-control.sh" "$OUT_DIR/nas-control.sh" chmod +x "$OUT_DIR/nas-control.sh" cat < "$OUT_DIR/.env" PORT=$PORT DATA_PATH=./data JWT_SECRET=$JWT_SECRET JWT_ISSUER=$JWT_ISSUER JWT_AUDIENCE=$JWT_AUDIENCE ADMIN_BOOTSTRAP_TOKEN=$ADMIN_BOOTSTRAP_TOKEN D3RO_API_TOKEN=$D3RO_API_TOKEN ADMIN_SESSION_SECRET=$ADMIN_SESSION_SECRET API_SERVER_URL=$API_SERVER_URL CORS_ALLOWED_ORIGINS=$CORS_ALLOWED_ORIGINS ALLOWED_HOSTS=$ALLOWED_HOSTS SUPABASE_URL=$SUPABASE_URL SUPABASE_SERVICE_ROLE_KEY=$SUPABASE_SERVICE_ROLE_KEY TZ=Asia/Seoul EOF chmod 600 "$OUT_DIR/.env" cat < "$OUT_DIR/README.txt" ======================================================================== D3RO Voice — Standalone NAS Deployment Package ======================================================================== [Synology / QNAP / Linux NAS 배포 방법] 1. 이 폴더의 모든 파일 (d3ro-voice-api.tar, d3ro-voice-admin.tar, d3ro-voice-web.tar, docker-compose.yml, .env, nas-control.sh)을 NAS의 Docker 작업 폴더 (예: /volume1/docker/d3ro)에 업로드합니다. 2. NAS SSH 터미널에 접속하여 해당 폴더로 이동합니다: cd /volume1/docker/d3ro 3. Docker 이미지를 로드합니다: docker load < d3ro-voice-api.tar docker load < d3ro-voice-admin.tar docker load < d3ro-voice-web.tar 4. 서비스를 시작합니다: ./nas-control.sh start (또는 docker compose up -d) 5. 브라우저에서 접속 확인: - 관리자: http://:3001 (공개 주소 https://admin.chanpaca.net) - API Swagger: http://:$PORT/swagger - 헬스체크: http://:$PORT/health - 웹앱: http://:3002/app/login (공개 주소 https://d3ro.chanpaca.net/app 는 사이트 브리지 워커 경유) EOF echo -e "${GREEN}NAS Deployment Package ready at: $OUT_DIR${NC}" if [ -n "$NAS_HOST" ]; then echo -e "\n${YELLOW}[4/4] Deploying to Remote NAS ($NAS_USER@$NAS_HOST:$NAS_PATH)...${NC}" ssh "$NAS_USER@$NAS_HOST" "mkdir -p $NAS_PATH/data" scp -O "$TAR_PATH" "$ADMIN_TAR_PATH" "$WEB_TAR_PATH" "$OUT_DIR/docker-compose.yml" "$OUT_DIR/.env" "$OUT_DIR/nas-control.sh" "$NAS_USER@$NAS_HOST:$NAS_PATH/" ssh "$NAS_USER@$NAS_HOST" "cd $NAS_PATH && chmod +x nas-control.sh && docker load < d3ro-voice-api.tar && docker load < d3ro-voice-admin.tar && docker load < d3ro-voice-web.tar && docker compose down 2>/dev/null || true; docker compose up -d" echo -e "\n${GREEN}========================================================${NC}" echo -e "${GREEN} NAS Deployment Completed Successfully!${NC}" echo -e "${CYAN} Access your D3RO Cloud Service at:${NC}" echo -e " - Portal: http://$NAS_HOST:$PORT/" echo -e " - Admin: http://$NAS_HOST:$PORT/admin" echo -e " - Swagger: http://$NAS_HOST:$PORT/swagger" echo -e " - Health: http://$NAS_HOST:$PORT/health" echo -e " - Web App: http://$NAS_HOST:3002/app/login" echo -e "${GREEN}========================================================${NC}" else echo -e "\n${GREEN}========================================================${NC}" echo -e "${GREEN} NAS Package Build Complete!${NC}" echo -e " Package location: $OUT_DIR" echo -e " To deploy automatically via SSH, run:" echo -e " ./scripts/deploy-nas.sh " echo -e "${GREEN}========================================================${NC}" fi