Files
AutonetSellCar/DEPLOYMENT_GUIDE.md
AutonetSellCar Deploy e661d91c72 fix: banner translations and deployment improvements
- Add translateCarName import from i18n.ts for proper multilingual support
- Change default API language from 'ko' to 'en' for hero banners
- Add checkbox column for Local Cars banner registration
- Update Dockerfile with Playwright dependencies
- Add PostgreSQL migration script
- Add banner translation fix script

🤖 Generated with [Claude Code](https://claude.ai/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-31 10:41:42 +09:00

582 lines
26 KiB
Markdown

# AutonetSellCar.com 배포 가이드
이 문서는 시스템 아키텍처와 코드 수정부터 운영 배포까지의 전체 과정을 설명합니다.
---
## 1. 시스템 아키텍처 개요
```
┌─────────────────────────────────────────────────────────────────────────────────┐
│ AutonetSellCar.com 시스템 아키텍처 │
└─────────────────────────────────────────────────────────────────────────────────┘
┌─────────────────┐
│ 인터넷 │
│ 59.14.158.123 │
└────────┬────────┘
┌──────────────────┼──────────────────┐
│ │ │
▼ ▼ ▼
autonetsellcar.com autonetsellcar.com autonetsellcar.com
/ /api /uploads
│ │ │
└──────────────────┼──────────────────┘
┌─────────────────────────────────────────────────────────────────────────────────┐
│ 서버1 (192.168.0.201) │
│ 인프라 서버 │
│ ┌─────────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────────────┐ │
│ │ Nginx Proxy │ │ PostgreSQL │ │ Redis │ │ Portainer/Grafana │ │
│ │ Manager │ │ :5432 │ │ :6379 │ │ Prometheus │ │
│ │ :80/:443 │ │ │ │ │ │ │ │
│ │ │ │ DB: autonet │ │ │ │ │ │
│ └────────┬────────┘ └──────┬──────┘ └──────┬──────┘ └─────────────────────┘ │
│ │ │ │ │
└───────────┼──────────────────┼────────────────┼──────────────────────────────────┘
│ │ │
│ └────────┬───────┘
│ │
▼ ▼
┌─────────────────────────────────────────────────────────────────────────────────┐
│ 서버2 (192.168.0.202) │
│ 애플리케이션 서버 │
│ │
│ ┌─────────────────────────────────────────────────────────────────────────┐ │
│ │ Production Environment │ │
│ │ ┌──────────────────┐ ┌──────────────────┐ ┌──────────────────┐ │ │
│ │ │ autonet-frontend │ │ autonet-backend │ │ carmodoo-agent │ │ │
│ │ │ Next.js 14 │───▶│ FastAPI │───▶│ Playwright │ │ │
│ │ │ :3000 │ │ :8000 │ │ PDF/Spec 조회 │ │ │
│ │ └──────────────────┘ └────────┬─────────┘ └──────────────────┘ │ │
│ │ │ │ │
│ │ │ PostgreSQL/Redis │ │
│ │ └──────────────────────────────────────┼───┼──▶ 서버1
│ └─────────────────────────────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────────────────────────┐ │
│ │ Staging Environment │ │
│ │ ┌──────────────────┐ ┌──────────────────┐ │ │
│ │ │ frontend-staging │ │ backend-staging │ │ │
│ │ │ :3001 │ │ :8001 │ │ │
│ │ └──────────────────┘ └──────────────────┘ │ │
│ └─────────────────────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────────────────┐
│ 서버4 (개발 PC) │
│ │
│ D:\Workspace\claudeCode\AutonetSellCar.com\ │
│ ├── frontend/ (Next.js) │
│ ├── backend/ (FastAPI) │
│ └── carmodoo-agent/ │
│ │
│ 로컬 테스트: localhost:3000 / localhost:8000 │
│ │
└─────────────────────────────────────────────────────────────────────────────────┘
```
---
## 2. 서버별 역할 및 구성
### 서버1 (192.168.0.201) - 인프라 서버
| 서비스 | 포트 | 역할 |
|--------|------|------|
| Nginx Proxy Manager | 80, 443, 81 | 리버스 프록시, SSL 인증서 관리 |
| PostgreSQL | 5432 | 메인 데이터베이스 (autonet) |
| Redis | 6379 | 캐시, 세션 관리 |
| Portainer | 9000 | Docker 관리 UI |
| Prometheus | 9090 | 메트릭 수집 |
| Grafana | 3000 | 모니터링 대시보드 |
### 서버2 (192.168.0.202) - 애플리케이션 서버
| 컨테이너 | 포트 | 역할 |
|----------|------|------|
| autonet-frontend | 3000 | Next.js 프론트엔드 (운영) |
| autonet-backend | 8000 | FastAPI 백엔드 (운영) |
| carmodoo-agent | - | Playwright 기반 PDF/스펙 조회 |
| autonet-frontend-staging | 3001 | 스테이징 프론트엔드 |
| autonet-backend-staging | 8001 | 스테이징 백엔드 |
---
## 3. 도메인 및 라우팅 설정
```
┌─────────────────────────────────────────────────────────────────────────────────┐
│ Nginx Proxy Manager 설정 │
└─────────────────────────────────────────────────────────────────────────────────┘
autonetsellcar.com (SSL: Let's Encrypt)
├── / ──▶ 192.168.0.202:3000 (Frontend)
├── /api/* ──▶ 192.168.0.202:8000 (Backend)
│ └── Custom Location: /api
│ Forward: http://192.168.0.202:8000
└── /uploads/* ──▶ 192.168.0.202:8000 (Backend Static)
└── Custom Location: /uploads
Forward: http://192.168.0.202:8000
설정 방법:
┌─────────────────────────────────────────────────────────────────────────┐
│ 1. Nginx Proxy Manager (http://192.168.0.201:81) 접속 │
│ 2. Proxy Hosts > autonetsellcar.com 선택 │
│ 3. Custom Locations 탭에서 /api, /uploads 추가 │
│ - Location: /api │
│ - Scheme: http │
│ - Forward Hostname: 192.168.0.202 │
│ - Forward Port: 8000 │
└─────────────────────────────────────────────────────────────────────────┘
```
---
## 4. PostgreSQL 설정
### 4.1 서버1 PostgreSQL Docker 컨테이너
```bash
# PostgreSQL 컨테이너 정보 확인
docker exec postgres-primary env | grep POSTGRES
# 출력:
# POSTGRES_USER=admin
# POSTGRES_PASSWORD=roskfl@1122
# POSTGRES_DB=mongolcar
```
### 4.2 데이터베이스 생성
```bash
# autonet 데이터베이스 생성
docker exec -it postgres-primary psql -U admin -d postgres -c "CREATE DATABASE autonet;"
# 비밀번호 재설정 (필요시)
docker exec -it postgres-primary psql -U admin -d postgres -c "ALTER USER admin PASSWORD 'roskfl@1122';"
```
### 4.3 외부 접속 설정 확인
```bash
# pg_hba.conf 확인 (외부 접속 허용)
docker exec postgres-primary cat /var/lib/postgresql/data/pg_hba.conf | grep -v "^#" | grep -v "^$"
# 필수 설정:
# host all all all scram-sha-256
```
### 4.4 백엔드 PostgreSQL 연결 설정
**backend/.env:**
```env
# Database
USE_SQLITE=False
DB_HOST=192.168.0.201
DB_PORT=5432
DB_NAME=autonet
DB_USER=admin
DB_PASSWORD=roskfl@1122
```
**backend/app/config.py:**
```python
@property
def DATABASE_URL(self) -> str:
if self.USE_SQLITE:
base_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
db_path = os.path.join(base_dir, "autonet.db")
return f"sqlite:///{db_path}"
# URL-encode password for special characters like @ # etc
from urllib.parse import quote_plus
encoded_password = quote_plus(self.DB_PASSWORD)
return f"postgresql://{self.DB_USER}:{encoded_password}@{self.DB_HOST}:{self.DB_PORT}/{self.DB_NAME}"
```
### 4.5 SQLite → PostgreSQL 마이그레이션
```bash
# 개발 서버(서버4)에서 실행
cd D:\Workspace\claudeCode\AutonetSellCar.com\backend
# psycopg2 설치
venv\Scripts\pip.exe install psycopg2-binary
# 마이그레이션 스크립트 실행
venv\Scripts\python.exe migrate_to_postgres.py
```
**마이그레이션 스크립트 주요 기능:**
- PostgreSQL에 테이블 자동 생성 (SQLAlchemy 모델 기반)
- SQLite boolean (0/1) → PostgreSQL boolean (true/false) 변환
- FK 제약조건 임시 비활성화 후 데이터 이전
- Sequence 자동 리셋
---
## 5. Docker Compose 설정
### 5.1 Docker Compose v2 설치 (서버2)
```bash
# Docker 공식 저장소 추가
sudo apt-get update
sudo apt-get install ca-certificates curl gnupg -y
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
sudo chmod a+r /etc/apt/keyrings/docker.gpg
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
$(. /etc/os-release && echo "$VERSION_CODENAME") stable" | \
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
# Docker Compose 플러그인 설치
sudo apt-get update
sudo apt-get install docker-compose-plugin -y
# 버전 확인
docker compose version
```
### 5.2 docker-compose.production.yml
```yaml
services:
frontend:
build: ./frontend
container_name: autonet-frontend
ports:
- "3000:3000"
environment:
- NODE_ENV=production
- NEXT_PUBLIC_API_URL=https://autonetsellcar.com
depends_on:
- backend
networks:
- autonet-production-network
backend:
build: ./backend
container_name: autonet-backend
ports:
- "8000:8000"
environment:
- ENV=production
env_file:
- ./backend/.env
volumes:
- ./backend/uploads:/app/uploads
networks:
- autonet-production-network
carmodoo-agent:
build: ./carmodoo-agent
container_name: carmodoo-agent
networks:
- autonet-production-network
networks:
autonet-production-network:
driver: bridge
```
### 5.3 주요 Docker 명령어
```bash
# 전체 시작
docker compose -f docker-compose.production.yml up -d
# 특정 서비스 재빌드 (캐시 없이)
docker compose -f docker-compose.production.yml build backend --no-cache
docker compose -f docker-compose.production.yml up -d backend
# 로그 확인
docker logs autonet-backend --tail 50 -f
# 컨테이너 상태
docker ps
# 전체 중지 및 제거
docker compose -f docker-compose.production.yml down
# 네트워크/볼륨 문제 시
docker rm -f autonet-backend autonet-frontend carmodoo-agent
docker network rm autonet-production-network
docker compose -f docker-compose.production.yml up -d
```
---
## 6. 배포 흐름
```
┌─────────────────────────────────────────────────────────────────────────────────┐
│ 배포 파이프라인 │
└─────────────────────────────────────────────────────────────────────────────────┘
┌──────────────┐ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│ 1. 개발 │ ───▶ │ 2. 커밋 │ ───▶ │ 3. 스테이징 │ ───▶ │ 4. 운영 │
│ (서버4) │ │ & Push │ │ 테스트 │ │ 배포 │
└──────────────┘ └──────────────┘ └──────────────┘ └──────────────┘
│ │ │ │
▼ ▼ ▼ ▼
코드 수정 git commit Docker 빌드 promote
로컬 테스트 git push staging :3001/:8001 :3000/:8000
```
### Step 1: 개발 (서버4)
```bash
# 로컬 개발 서버 실행
cd backend && venv\Scripts\activate
uvicorn app.main:app --reload --port 8000
cd frontend
npm run dev
# 테스트: http://localhost:3000
```
### Step 2: Git Commit & Push
```bash
git status
git add .
git commit -m "feat: 기능 설명"
git push staging main
```
### Step 3: 스테이징 테스트
```bash
# 서버2 SSH 접속 후
cd /opt/autonet/staging
docker compose -f docker-compose.staging.yml build --no-cache
docker compose -f docker-compose.staging.yml up -d
# 테스트 URL
# Frontend: http://192.168.0.202:3001
# Backend: http://192.168.0.202:8001/docs
```
### Step 4: 운영 배포
```bash
# 서버2에서
cd /opt/autonet/production
docker compose -f docker-compose.production.yml build --no-cache
docker compose -f docker-compose.production.yml up -d
# 또는 스크립트 사용
/opt/autonet/scripts/deploy.sh promote
# 운영 URL
# https://autonetsellcar.com
# https://autonetsellcar.com/api/docs
```
---
## 7. 디렉토리 구조
```
서버2 (/opt/autonet/)
├── git/
│ └── autonet.git/ # Bare Git Repository
│ └── hooks/
│ └── post-receive # 자동 배포 훅
├── staging/ # 스테이징 환경
│ ├── frontend/
│ ├── backend/
│ │ └── .env # 스테이징 환경변수
│ └── docker-compose.staging.yml
├── production/ # 운영 환경
│ ├── frontend/
│ ├── backend/
│ │ ├── .env # 운영 환경변수 (PostgreSQL)
│ │ ├── requirements.txt # psycopg2-binary 포함
│ │ └── app/
│ │ └── config.py # URL 인코딩 적용
│ ├── carmodoo-agent/
│ └── docker-compose.production.yml
├── releases/ # 롤백용 백업
│ ├── 20241230_140000/
│ └── 20241230_150000/
└── scripts/
├── deploy-staging.sh
└── deploy.sh
```
---
## 8. 환경변수 설정
### 운영 서버 backend/.env 전체
```env
# Database (PostgreSQL)
USE_SQLITE=False
DB_HOST=192.168.0.201
DB_PORT=5432
DB_NAME=autonet
DB_USER=admin
DB_PASSWORD=roskfl@1122
# Redis
REDIS_HOST=192.168.0.201
REDIS_PORT=6379
REDIS_PASSWORD=
# JWT
SECRET_KEY=your-secret-key-change-in-production
# App
DEBUG=False
# Azure Translator
AZURE_TRANSLATOR_KEY=your-azure-key
AZURE_TRANSLATOR_REGION=southeastasia
# Email (SMTP)
SMTP_HOST=smtp.gmail.com
SMTP_PORT=587
SMTP_USER=autonetsellcar@gmail.com
SMTP_PASSWORD=your-app-password
SMTP_FROM_EMAIL=autonetsellcar@gmail.com
SMTP_FROM_NAME=AutonetSellCar
# Verification
VERIFICATION_CODE_EXPIRE_MINUTES=10
EMAIL_VERIFICATION_REQUIRED=True
```
---
## 9. 문제 해결
### PostgreSQL 연결 오류
```bash
# 에러: could not translate host name "1122@192.168.0.201"
# 원인: 비밀번호에 @ 문자가 URL 구분자로 인식됨
# 해결: config.py에서 URL 인코딩 적용
from urllib.parse import quote_plus
encoded_password = quote_plus(self.DB_PASSWORD)
```
### Docker 네트워크 충돌
```bash
# 에러: network was found but has incorrect label
docker compose -f docker-compose.production.yml down
docker network rm autonet-production-network
docker compose -f docker-compose.production.yml up -d
```
### 컨테이너 이름 충돌
```bash
# 에러: container name is already in use
docker rm -f autonet-backend autonet-frontend carmodoo-agent
docker compose -f docker-compose.production.yml up -d
```
### psycopg2 모듈 없음
```bash
# requirements.txt에 추가
psycopg2-binary # PostgreSQL production
# 또는 직접 추가
echo "psycopg2-binary" >> /opt/autonet/production/backend/requirements.txt
docker compose -f docker-compose.production.yml build backend --no-cache
```
### Mixed Content 에러
```
# 에러: Mixed Content - HTTPS 페이지에서 HTTP API 호출
# 해결: Frontend 빌드 시 HTTPS API URL 사용
NEXT_PUBLIC_API_URL=https://autonetsellcar.com
```
---
## 10. 빠른 참조 명령어
```
╔═══════════════════════════════════════════════════════════════════════════════╗
║ 개발 (서버4) ║
╠═══════════════════════════════════════════════════════════════════════════════╣
║ git status # 변경 파일 확인 ║
║ git add . # 스테이징 ║
║ git commit -m "message" # 커밋 ║
║ git push staging main # 서버2로 푸시 ║
╚═══════════════════════════════════════════════════════════════════════════════╝
╔═══════════════════════════════════════════════════════════════════════════════╗
║ 운영 (서버2) ║
╠═══════════════════════════════════════════════════════════════════════════════╣
║ docker ps # 실행 중인 컨테이너 ║
║ docker logs autonet-backend --tail 50 # 백엔드 로그 ║
║ docker compose -f docker-compose.production.yml up -d # 시작 ║
║ docker compose -f docker-compose.production.yml down # 중지 ║
║ docker compose -f docker-compose.production.yml build --no-cache # 재빌드 ║
╚═══════════════════════════════════════════════════════════════════════════════╝
╔═══════════════════════════════════════════════════════════════════════════════╗
║ PostgreSQL (서버1) ║
╠═══════════════════════════════════════════════════════════════════════════════╣
║ docker exec -it postgres-primary psql -U admin -d autonet # DB 접속 ║
║ \dt # 테이블 목록 ║
║ \q # 종료 ║
╚═══════════════════════════════════════════════════════════════════════════════╝
```
---
## 11. 체크리스트
### 최초 서버 설정
- [ ] 서버1: PostgreSQL 컨테이너 실행 중
- [ ] 서버1: autonet 데이터베이스 생성
- [ ] 서버1: 외부 접속 허용 (pg_hba.conf)
- [ ] 서버1: Nginx Proxy Manager SSL 설정
- [ ] 서버1: Custom Location (/api, /uploads) 설정
- [ ] 서버2: Docker Compose v2 설치
- [ ] 서버2: backend/.env PostgreSQL 설정
- [ ] 서버2: requirements.txt에 psycopg2-binary 추가
- [ ] 서버2: config.py URL 인코딩 적용
### 배포 전
- [ ] 로컬 테스트 완료
- [ ] git status로 변경 파일 확인
- [ ] 커밋 메시지 작성
### 배포 후
- [ ] docker ps로 컨테이너 상태 확인
- [ ] docker logs로 에러 확인
- [ ] https://autonetsellcar.com 접속 테스트
- [ ] API 응답 확인 (/api/docs)
---
**최종 업데이트**: 2024-12-30