Files
AutonetSellCar/DEPLOYMENT_GUIDE.md
AutonetSellCar Deploy b1afea79d9 Add SOLD OUT badge and improve deployment docs
- Add SOLD OUT overlay on car detail page image
- Add SOLD OUT badge next to car name
- Add Sold Out status in Admin Cars detail view
- Add soldout field to Car TypeScript interface
- Create PRODUCTION_VALUES.md for deployment reference
- Update CLAUDE.md with CRITICAL deployment section
- Update TROUBLESHOOTING.md with recurring errors

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

Co-Authored-By: Claude <noreply@anthropic.com>
2026-01-03 09:05:16 +09:00

30 KiB

AutonetSellCar.com 배포 가이드

이 문서는 시스템 아키텍처와 코드 수정부터 운영 배포까지의 전체 과정을 설명합니다.

중요: 배포 전 반드시 PRODUCTION_VALUES.md의 값을 확인하세요! 반복되는 오류 해결은 TROUBLESHOOTING.md를 참고하세요.


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 컨테이너

# PostgreSQL 컨테이너 정보 확인
docker exec postgres-primary env | grep POSTGRES

# 출력:
# POSTGRES_USER=admin
# POSTGRES_PASSWORD=roskfl@1122
# POSTGRES_DB=mongolcar  (컨테이너 기본 DB, AutonetSellCar는 autonet DB 사용!)

4.2 데이터베이스 생성

# 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 외부 접속 설정 확인

# 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:

# 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:

@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 마이그레이션

# 개발 서버(서버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)

# 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

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: ./agent
    container_name: carmodoo-agent
    volumes:
      - ./agent/.env:/app/.env:ro
    networks:
      - autonet-production-network

networks:
  autonet-production-network:
    driver: bridge

5.3 주요 Docker 명령어

# 전체 시작
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)

# 로컬 개발 서버 실행
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

git status
git add .
git commit -m "feat: 기능 설명"
git push staging main

Step 3: 스테이징 테스트

# 서버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: 운영 배포

# 서버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 인코딩 적용
│   ├── agent/
│   │   └── .env                  # Carmodoo 로그인 정보
│   └── docker-compose.production.yml
│
├── releases/                     # 롤백용 백업
│   ├── 20241230_140000/
│   └── 20241230_150000/
│
└── scripts/
    ├── deploy-staging.sh
    └── deploy.sh

8. 환경변수 설정

운영 서버 backend/.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

운영 서버 agent/.env

# Carmodoo 딜러 포탈 로그인 정보
CARMODOO_USER_ID=01033315258
CARMODOO_PASSWORD=alskfl@1122

# Backend API 연결 (Docker 네트워크 내부)
API_SERVER_URL=http://autonet-backend:8000/api

⚠️ 중요: carmodoo-agent는 이 환경변수가 없으면 로그인 실패로 계속 재시작됩니다.


9. Git 기반 배포가 필요한 이유

9.1 문제 상황 (Git 미사용 시)

[서버4 - 로컬 개발]              [서버2 - 운영 서버]
     소스코드 A                      소스코드 A
         │                               │
         │                          직접 수정 → 소스코드 B (예: 번역 수정)
         │                               │
         └────── docker build ───────────┘
                      │
                      ▼
                소스코드 A로 덮어씀
                (B 변경사항 사라짐!)

원인:

  • 서버2에서 직접 코드를 수정함
  • 서버4에서 docker build를 하면 서버4의 소스코드로 컨테이너가 다시 빌드됨
  • 서버2에서 수정한 내용이 서버4에는 없으므로 → 변경사항이 사라짐

9.2 해결 방법 (Git 기반 배포)

[서버4 - 로컬 개발]                        [서버2 - 운영 서버]
     소스코드 수정
         │
    git commit
         │
    git push staging ────────────────→ Git Bare Repository
                                                │
                                          post-receive hook (자동)
                                                │
                                                ▼
                                          소스코드 복사 + docker build
                                                │
                                                ▼
                                          스테이징 컨테이너 실행
                                                │
                                          검증 후 deploy.sh promote
                                                │
                                                ▼
                                          운영 컨테이너 실행

9.3 핵심 원칙

이전 (문제) 현재 (해결)
서버2에서 직접 수정 서버4에서만 수정
수정 후 바로 docker build git commit → git push
변경 이력 없음 Git으로 버전 관리
롤백 불가 deploy.sh rollback으로 롤백 가능

9.4 올바른 배포 워크플로우

# 1. 서버4에서 코드 수정 (로컬 개발)
code frontend/src/app/page.tsx

# 2. 로컬 테스트
npm run dev

# 3. Git 커밋
git add .
git commit -m "fix: 번역 수정"

# 4. 스테이징 배포 (자동 - post-receive hook)
git push staging main

# 5. 스테이징 검증
# http://192.168.0.202:3001 (frontend)
# http://192.168.0.202:8001/docs (backend)

# 6. 운영 승격
ssh damon@192.168.0.202 "/opt/autonet/scripts/deploy.sh promote"

⚠️ 중요: 서버2에서 직접 코드를 수정하지 마세요! 모든 변경은 서버4에서 Git을 통해 배포해야 합니다.


10. 문제 해결

PostgreSQL 연결 오류

# 에러: 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 네트워크 충돌

# 에러: 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

컨테이너 이름 충돌

# 에러: 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 모듈 없음

# 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

carmodoo-agent 계속 재시작

# 에러 확인
docker logs carmodoo-agent --tail 20

# 에러: User ID and password are required
# 원인: agent/.env 파일 없음 또는 환경변수 미설정

# 해결:
# 1. .env 파일 생성
cat > /opt/autonet/production/agent/.env << 'EOF'
CARMODOO_USER_ID=01033315258
CARMODOO_PASSWORD=alskfl@1122
API_SERVER_URL=http://autonet-backend:8000/api
EOF

# 2. 컨테이너 재생성 (.env 마운트 적용)
docker stop carmodoo-agent && docker rm carmodoo-agent
docker run -d --name carmodoo-agent \
  --restart unless-stopped \
  --network autonet-production-network \
  -v /opt/autonet/production/agent/.env:/app/.env:ro \
  production-carmodoo-agent

11. 빠른 참조 명령어

╔═══════════════════════════════════════════════════════════════════════════════╗
║  개발 (서버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                                                           # 종료          ║
╚═══════════════════════════════════════════════════════════════════════════════╝

12. 체크리스트

최초 서버 설정

  • 서버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-31