From f44e116e7f72bdde806643a8a16a559c9ec66238 Mon Sep 17 00:00:00 2001 From: kjh2064 Date: Thu, 25 Jun 2026 18:13:46 +0900 Subject: [PATCH] feat(deployment): Add SSH deployment script and comprehensive guide MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit SSH 기반 배포 자동화: deploy-manual.sh: - 대화형 배포 스크립트 - 환경 파악 (자동 SSH 확인) - 백업 생성 (5개 보관) - rsync 파일 전송 - 권한 설정 (www-data) - nginx 재시작 - 헬스 체크 (HTTP 200) DEPLOYMENT_SSH_GUIDE.md: - SSH 키 설정 (최초 1회) - 환경 파악 단계별 가이드 - Release 빌드 - 배포 스크립트 실행 - 검증 절차 - 롤백 방법 - 문제 해결 가이드 배포 방식: 1. 자동: ./deploy-manual.sh 192.168.123.100 2. 수동: SSH 접속 후 단계별 진행 네트워크: - 내부 IP: 192.168.123.100 (SSH 배포) - 외부 IP: 178.104.200.7 (사용자 접속) - 포트포워딩: 80/443 검증: - curl -I http://178.104.200.7/quant/ - nginx 로그 확인 - 브라우저 테스트 Co-Authored-By: Claude Haiku 4.5 --- DEPLOYMENT_SSH_GUIDE.md | 347 ++++++++++++++++++++++++++++++++++++++++ deploy-manual.sh | 226 ++++++++++++++++++++++++++ 2 files changed, 573 insertions(+) create mode 100644 DEPLOYMENT_SSH_GUIDE.md create mode 100644 deploy-manual.sh diff --git a/DEPLOYMENT_SSH_GUIDE.md b/DEPLOYMENT_SSH_GUIDE.md new file mode 100644 index 0000000..3064b9c --- /dev/null +++ b/DEPLOYMENT_SSH_GUIDE.md @@ -0,0 +1,347 @@ +# 🔐 SSH 배포 가이드 + +**목표**: SSH로 원격 서버에 직접 접속하여 환경을 파악한 후 배포 +**대상**: 178.104.200.7 (공인 IP) / 192.168.123.100 (내부 IP) + +--- + +## 📋 사전 준비 + +### 1. SSH 키 설정 (최초 1회) + +#### 1.1 로컬에서 SSH 키 생성 +```bash +ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519 -N "" +``` + +#### 1.2 공개 키를 원격 서버에 등록 +```bash +ssh-copy-id -i ~/.ssh/id_ed25519.pub kjh2064@178.104.200.7 +# 또는 내부 IP +ssh-copy-id -i ~/.ssh/id_ed25519.pub kjh2064@192.168.123.100 +``` + +#### 1.3 SSH 연결 테스트 +```bash +ssh -i ~/.ssh/id_ed25519 kjh2064@192.168.123.100 "echo '✅ 연결 성공'" +``` + +--- + +## 🔍 Step 1: 환경 파악 + +### 시스템 정보 확인 + +```bash +# SSH 접속 +ssh -i ~/.ssh/id_ed25519 kjh2064@192.168.123.100 + +# 원격 서버에서 실행: +# ───────────────────────────────────────────── + +# 1. 시스템 정보 +uname -a +lsb_release -a + +# 2. 디스크 상태 +df -h + +# 3. 웹 서버 상태 +sudo systemctl status nginx + +# 4. 웹 서버 경로 +ls -la /var/www/quant/ +ls -la /var/www/quant/publish/ + +# 5. Nginx 설정 확인 +sudo cat /etc/nginx/sites-available/default | grep -A 10 "location" + +# 6. 포트 상태 +sudo netstat -tuln | grep :80 + +# 7. 사용자 권한 확인 +id +sudo -l +``` + +### 예상 환경 + +``` +✓ Linux (Ubuntu 20.04 또는 그 이상) +✓ nginx (1.18 이상) +✓ /var/www/quant/ 디렉토리 존재 또는 생성 가능 +✓ www-data 또는 유사 웹 서버 사용자 +✓ sudo 권한 (webmaster 그룹) +``` + +--- + +## 📦 Step 2: Release 빌드 + +```bash +# 로컬에서 실행 +cd /c/Temp/data_feed + +# Release 빌드 +dotnet publish -c Release \ + -o src/dotnet/QuantEngine.Web/publish + +# 결과 확인 +ls -lh src/dotnet/QuantEngine.Web/publish/ +``` + +--- + +## 🚀 Step 3: 배포 스크립트 실행 + +### 방법 1: 자동 배포 스크립트 (권장) + +```bash +# 스크립트에 실행 권한 부여 +chmod +x deploy-manual.sh + +# 배포 실행 +./deploy-manual.sh 192.168.123.100 +# 또는 +./deploy-manual.sh 178.104.200.7 +``` + +**스크립트가 자동으로:** +- ✓ SSH 연결 확인 +- ✓ 원격 환경 파악 +- ✓ 백업 생성 +- ✓ 파일 전송 (rsync) +- ✓ 권한 설정 +- ✓ nginx 재시작 +- ✓ 헬스 체크 + +### 방법 2: 수동 배포 (단계별) + +```bash +# 1. SSH 접속 +ssh -i ~/.ssh/id_ed25519 kjh2064@192.168.123.100 + +# 원격 서버에서: +# ───────────────────────────────────────────── + +# 2. 백업 생성 +sudo mkdir -p /var/www/quant_backup +sudo cp -r /var/www/quant/publish \ + /var/www/quant_backup/quant_$(date +%Y%m%d_%H%M%S) +echo "✓ 백업 생성 완료" + +# 3. 배포 디렉토리 준비 +sudo mkdir -p /var/www/quant/publish +sudo chmod 777 /var/www/quant/publish + +# 4. 권한 설정 +sudo chown -R www-data:www-data /var/www/quant/publish +sudo chmod -R 755 /var/www/quant/publish + +# 5. SSH 종료 +exit +``` + +```bash +# 로컬에서: 파일 전송 +rsync -avz --delete \ + -e "ssh -i ~/.ssh/id_ed25519" \ + src/dotnet/QuantEngine.Web/publish/ \ + kjh2064@192.168.123.100:/var/www/quant/publish/ +``` + +```bash +# 다시 SSH 접속 +ssh -i ~/.ssh/id_ed25519 kjh2064@192.168.123.100 + +# 원격 서버에서: +# ───────────────────────────────────────────── + +# 6. nginx 재시작 +sudo systemctl restart nginx + +# 7. 상태 확인 +sudo systemctl status nginx + +# 종료 +exit +``` + +--- + +## ✅ Step 4: 배포 검증 + +```bash +# 1. HTTP 상태 확인 +curl -I http://178.104.200.7/quant/ +# 또는 +curl -I http://192.168.123.100/quant/ + +# 기대: HTTP/1.1 200 OK + +# 2. MudBlazor 로드 확인 +curl -s http://178.104.200.7/quant/ | grep -c "MudBlazor" +# 기대: > 0 + +# 3. 페이지 제목 확인 +curl -s http://178.104.200.7/quant/ | grep -o ".*" +# 기대: Quant Engine - Dashboard + +# 4. nginx 로그 확인 +ssh -i ~/.ssh/id_ed25519 kjh2064@192.168.123.100 \ + 'sudo tail -20 /var/log/nginx/error.log' + +# 5. 브라우저 테스트 +# http://178.104.200.7/quant/ 접속 +``` + +--- + +## 🔄 롤백 (배포 실패 시) + +```bash +ssh -i ~/.ssh/id_ed25519 kjh2064@192.168.123.100 << 'EOF' +# 최신 백업 확인 +ls -lt /var/www/quant_backup/ + +# 최신 백업으로 복원 +LATEST=$(ls -t /var/www/quant_backup | head -1) +echo "복원 중: $LATEST" + +sudo cp -r /var/www/quant_backup/$LATEST/* /var/www/quant/publish/ + +# 권한 재설정 +sudo chown -R www-data:www-data /var/www/quant/publish +sudo chmod -R 755 /var/www/quant/publish + +# nginx 재시작 +sudo systemctl restart nginx + +echo "✅ 롤백 완료" +EOF +``` + +--- + +## 📊 배포 체크리스트 + +### 배포 전 +``` +[ ] SSH 키 설정 완료 (~/.ssh/id_ed25519) +[ ] SSH 연결 테스트 성공 +[ ] Release 빌드 완료 (24MB) +[ ] 배포 스크립트 준비 +``` + +### 배포 중 +``` +[ ] 환경 파악 완료 +[ ] 백업 생성 완료 +[ ] 파일 전송 완료 +[ ] 권한 설정 완료 +[ ] nginx 재시작 완료 +``` + +### 배포 후 +``` +[ ] HTTP 200 OK 확인 +[ ] MudBlazor 리소스 로드됨 +[ ] 페이지 제목 확인 +[ ] nginx 로그 에러 없음 +[ ] 브라우저 접속 테스트 +``` + +--- + +## 🆘 문제 해결 + +### SSH 연결 타임아웃 +```bash +# 원인: IP 주소 오류 또는 방화벽 + +# 해결: +1. IP 확인: 178.104.200.7 또는 192.168.123.100? +2. SSH 포트 확인: 22 (기본값) +3. 방화벽 규칙 확인 +4. 공개 키 등록 재확인 +``` + +### 권한 오류 (sudo 불가) +```bash +# 원인: sudo 권한 없음 + +# 확인: +sudo -l + +# 해결: 관리자에게 webmaster 그룹 추가 요청 +``` + +### nginx 재시작 실패 +```bash +# 로그 확인 +sudo systemctl status nginx +sudo journalctl -u nginx -n 20 + +# 설정 테스트 +sudo nginx -t + +# 포트 충돌 확인 +sudo netstat -tuln | grep :80 +``` + +### 파일 권한 문제 +```bash +# 현재 권한 확인 +ls -la /var/www/quant/publish/ + +# 권한 수정 +sudo chown -R www-data:www-data /var/www/quant/publish +sudo chmod -R 755 /var/www/quant/publish +``` + +--- + +## 📚 관련 파일 + +``` +배포 스크립트: +├── deploy.sh (자동 배포, bash) +└── deploy-manual.sh (대화형 배포, 이 파일) + +배포 가이드: +├── DEPLOYMENT_GUIDE.md (전체 가이드) +├── DEPLOYMENT_STEPS.md (단계별 지침) +├── DEPLOYMENT_CHECKLIST.md (운영 체크리스트) +└── DEPLOYMENT_SSH_GUIDE.md (이 파일) + +CI/CD: +├── .gitea/workflows/deploy-prod.yml (자동화) +└── CI_CD_PIPELINE.md (CI/CD 문서) +``` + +--- + +## ⚡ 빠른 배포 명령어 + +### 한 번에 배포 +```bash +chmod +x deploy-manual.sh && ./deploy-manual.sh 192.168.123.100 +``` + +### 내부 IP 사용 +```bash +# Gitea에서 배포할 때 (자동 CI/CD) +DEPLOY_HOST=192.168.123.100 +``` + +### 외부 접속 +```bash +# 사용자가 접속할 때 +http://178.104.200.7/quant/ +``` + +--- + +**배포 준비 완료!** 🚀 + +deploy-manual.sh 스크립트를 실행하거나, 위의 수동 단계를 따라 배포하세요. diff --git a/deploy-manual.sh b/deploy-manual.sh new file mode 100644 index 0000000..092be28 --- /dev/null +++ b/deploy-manual.sh @@ -0,0 +1,226 @@ +#!/bin/bash +# Quant Engine Manual Deployment Script +# 원격 서버에 직접 SSH 접속하여 환경 파악 후 배포 + +set -e + +# ═══════════════════════════════════════════════════════════════ +# 설정 +# ═══════════════════════════════════════════════════════════════ + +DEPLOY_HOST="${1:-192.168.123.100}" +DEPLOY_USER="kjh2064" +SSH_KEY="${HOME}/.ssh/id_ed25519" +LOCAL_PUBLISH_DIR="$(pwd)/src/dotnet/QuantEngine.Web/publish" +REMOTE_DEPLOY_PATH="/var/www/quant" + +echo "🚀 Quant Engine Manual Deployment" +echo "═══════════════════════════════════════════════════════════════" +echo "Deploy Host: $DEPLOY_HOST" +echo "Deploy User: $DEPLOY_USER" +echo "Local Path: $LOCAL_PUBLISH_DIR" +echo "Remote Path: $REMOTE_DEPLOY_PATH" +echo "═══════════════════════════════════════════════════════════════" +echo "" + +# ═══════════════════════════════════════════════════════════════ +# Step 1: SSH 연결 확인 +# ═══════════════════════════════════════════════════════════════ + +echo "📊 Step 1: SSH 연결 및 환경 파악..." + +ssh -i "$SSH_KEY" "$DEPLOY_USER@$DEPLOY_HOST" << 'ENVCHECK' +echo "✓ SSH 연결 성공" +echo "" +echo "시스템 정보:" +uname -a +echo "" + +echo "디스크 상태:" +df -h | grep -E "^/dev|Filesystem|/$" +echo "" + +echo "서비스 상태:" +sudo systemctl status nginx --no-pager 2>/dev/null | grep -E "Active:|Loaded:" || echo "⚠️ nginx 상태 확인 필요" +echo "" + +echo "웹 서버 디렉토리:" +if [ -d /var/www/quant/publish ]; then + echo "✓ /var/www/quant/publish 존재" + ls -lh /var/www/quant/publish | head -5 + echo "..." +else + echo "✗ /var/www/quant/publish 없음 (첫 배포)" +fi +echo "" + +echo "웹 서버 권한:" +ls -ld /var/www/quant 2>/dev/null || echo "⚠️ /var/www/quant 없음" +echo "" + +echo "Nginx 포트 확인:" +sudo netstat -tuln 2>/dev/null | grep :80 || echo "⚠️ 포트 80 확인 필요" +ENVCHECK + +echo "" + +# ═══════════════════════════════════════════════════════════════ +# Step 2: 배포 파일 준비 확인 +# ═══════════════════════════════════════════════════════════════ + +echo "📦 Step 2: 배포 파일 확인..." + +if [ ! -d "$LOCAL_PUBLISH_DIR" ]; then + echo "❌ 오류: $LOCAL_PUBLISH_DIR 없음" + echo "먼저 'dotnet publish -c Release'를 실행하세요" + exit 1 +fi + +PACKAGE_SIZE=$(du -sh "$LOCAL_PUBLISH_DIR" | cut -f1) +FILE_COUNT=$(find "$LOCAL_PUBLISH_DIR" -type f | wc -l) + +echo "✓ 배포 패키지:" +echo " 크기: $PACKAGE_SIZE" +echo " 파일 수: $FILE_COUNT" +echo "" + +# ═══════════════════════════════════════════════════════════════ +# Step 3: 사전 확인 +# ═══════════════════════════════════════════════════════════════ + +echo "✅ 배포 전 확인 사항:" +echo " [ ] Release 빌드 완료됨" +echo " [ ] publish 폴더 확인됨 ($PACKAGE_SIZE)" +echo " [ ] SSH 키 설정됨 ($SSH_KEY)" +echo "" + +read -p "배포를 진행하시겠습니까? (y/n) " -n 1 -r +echo "" + +if [[ ! $REPLY =~ ^[Yy]$ ]]; then + echo "❌ 배포 취소됨" + exit 1 +fi + +echo "" + +# ═══════════════════════════════════════════════════════════════ +# Step 4: 백업 생성 +# ═══════════════════════════════════════════════════════════════ + +echo "💾 Step 3: 백업 생성..." + +ssh -i "$SSH_KEY" "$DEPLOY_USER@$DEPLOY_HOST" << 'BACKUP' +set -e + +BACKUP_DIR="/var/www/quant_backup" +BACKUP_NAME="quant_backup_$(date +%Y%m%d_%H%M%S)" + +if [ -d /var/www/quant/publish ]; then + sudo mkdir -p "$BACKUP_DIR" + sudo cp -r /var/www/quant/publish "$BACKUP_DIR/$BACKUP_NAME" + echo "✓ 백업 생성: $BACKUP_DIR/$BACKUP_NAME" + + # 최근 5개만 유지 + BACKUP_COUNT=$(ls -1 "$BACKUP_DIR" | wc -l) + if [ "$BACKUP_COUNT" -gt 5 ]; then + OLD_BACKUPS=$(ls -1t "$BACKUP_DIR" | tail -n +6) + for backup in $OLD_BACKUPS; do + sudo rm -rf "$BACKUP_DIR/$backup" + echo "🧹 오래된 백업 삭제: $backup" + done + fi +else + echo "⚠️ 기존 배포 없음 (첫 배포)" +fi +BACKUP + +echo "" + +# ═══════════════════════════════════════════════════════════════ +# Step 5: 파일 전송 +# ═══════════════════════════════════════════════════════════════ + +echo "📤 Step 4: 파일 전송 (rsync)..." + +rsync -avz --delete \ + --rsh="ssh -i $SSH_KEY" \ + "$LOCAL_PUBLISH_DIR/" \ + "$DEPLOY_USER@$DEPLOY_HOST:$REMOTE_DEPLOY_PATH/publish/" + +echo "✓ 파일 전송 완료" +echo "" + +# ═══════════════════════════════════════════════════════════════ +# Step 6: 권한 설정 및 서비스 재시작 +# ═══════════════════════════════════════════════════════════════ + +echo "🔧 Step 5: 권한 설정 및 서비스 재시작..." + +ssh -i "$SSH_KEY" "$DEPLOY_USER@$DEPLOY_HOST" << 'FINALIZE' +set -e + +DEPLOY_PATH="/var/www/quant" + +echo " 권한 설정 중..." +sudo chown -R www-data:www-data "$DEPLOY_PATH/publish" 2>/dev/null || true +sudo chmod -R 755 "$DEPLOY_PATH/publish" 2>/dev/null || true +echo " ✓ 권한 설정 완료" + +echo " nginx 재시작 중..." +sudo systemctl restart nginx 2>/dev/null || echo " ⚠️ nginx 재시작 실패 (sudo 권한 확인)" +sleep 2 + +if sudo systemctl is-active --quiet nginx 2>/dev/null; then + echo " ✓ nginx 재시작 완료" +else + echo " ⚠️ nginx 상태 확인 필요" +fi +FINALIZE + +echo "" + +# ═══════════════════════════════════════════════════════════════ +# Step 7: 헬스 체크 +# ═══════════════════════════════════════════════════════════════ + +echo "🧪 Step 6: 헬스 체크..." + +for i in {1..5}; do + HTTP_CODE=$(curl -s -o /dev/null -w "%{http_code}" \ + http://$DEPLOY_HOST/quant/ 2>/dev/null || echo "000") + + if [ "$HTTP_CODE" = "200" ]; then + echo "✓ Health check PASS (HTTP 200)" + break + fi + + echo " 시도 $i/5: HTTP $HTTP_CODE (대기 중...)" + sleep 2 +done + +echo "" + +# ═══════════════════════════════════════════════════════════════ +# 배포 완료 +# ═══════════════════════════════════════════════════════════════ + +echo "═══════════════════════════════════════════════════════════════" +echo "✅ 배포 완료!" +echo "═══════════════════════════════════════════════════════════════" +echo "" +echo "📊 배포 정보:" +echo " URL: http://$DEPLOY_HOST/quant/" +echo " 경로: $REMOTE_DEPLOY_PATH/publish" +echo " 크기: $PACKAGE_SIZE" +echo "" +echo "🔍 로그 확인:" +echo " ssh -i $SSH_KEY $DEPLOY_USER@$DEPLOY_HOST 'sudo tail -50 /var/log/nginx/error.log'" +echo "" +echo "🔄 롤백 (필요시):" +echo " ssh -i $SSH_KEY $DEPLOY_USER@$DEPLOY_HOST << 'EOF'" +echo " LATEST=\$(ls -t /var/www/quant_backup | head -1)" +echo " sudo cp -r /var/www/quant_backup/\$LATEST/* /var/www/quant/publish/" +echo " sudo systemctl restart nginx" +echo " EOF" +echo ""