5.4 KiB
Vignette 배포 가이드 — "아무 데나 설치 가능한" Docker 구성
목표: 어떤 호스트(네 PC / 학교 서버 / 클라우드 VM)든 docker compose up -d 한 방으로 뜨고, 옮길 때 환경변수 몇 줄만 바꾼다.
1. 한 방 실행
cd infra
cp .env.example .env # 값 채우기(아래 표)
docker compose up -d
# web/api/db/rag/proxy 컨테이너 기동. http://localhost:8080
전부 컨테이너: web(React/nginx) · api(FastAPI) · db(postgres16+pgvector) · rag(BGE-M3+reranker) · proxy(Caddy, TLS·SSE·WSS).
2. 핵심 — "엔진"만 컨테이너 밖 (이식성의 열쇠)
AI provider는 모두 호스트 엔진 게이트웨이 뒤에 둔다. 게이트웨이가 Claude CLI·Anthropic API·Codex CLI·Agy CLI의 모델 탐색과 실행을 맡고, 컨테이너 API는 ENGINE_URL/ENGINE_MODE로 게이트웨이와 provider를 선택한다. CLI는 호스트 인증을 재사용하고 API 키는 게이트웨이 호스트에만 주입한다.
설정 경로 3가지(사용자 선택):
- yml / .env —
infra/.env의ENGINE_URL·ENGINE_MODE(기본·운영) - docker compose —
docker compose run -e ENGINE_MODE=claude_api ...즉석 오버라이드 - 설정 페이지(관리자 UI) — 런타임에 provider·연결 주소·사용 가능 모델·추론 강도를 선택한다. 게이트웨이가 확인하지 못한 조합은 저장하지 않는다.
| 시나리오 | ENGINE_MODE | ENGINE_URL |
|---|---|---|
| 네 PC 운영 (Claude CLI) | claude_cli |
http://host.docker.internal:9099 |
| 네 PC 운영 (Codex CLI, 기본 Terra/Medium) | codex_cli |
http://host.docker.internal:9099 |
| 네 PC 운영 (Agy CLI, 기본 Gemini 3.6 Flash/High) | agy_cli |
http://host.docker.internal:9099 |
| 클라우드/타호스트 이전 | claude_api |
http://host.docker.internal:9099 (ANTHROPIC_API_KEY는 게이트웨이 호스트에 주입) |
| 원격 엔진 PC | 위 provider 중 설치·인증된 항목 | http://<엔진PC-IP>:9099 |
호스트 게이트웨이는
apps/api/engine_gateway/에 있으며 컨테이너 밖에서 실행한다. Claude CLI는 상주 멀티턴 풀을, Codex/Agy는 각 CLI를,claude_api는 Anthropic API를 호출한다. 관리자 UI의 모델 목록은 이 게이트웨이의GET /v1/capabilities가 소유한다.
3. 환경변수 (.env)
| 변수 | 설명 |
|---|---|
POSTGRES_PASSWORD |
DB 비밀번호(필수) |
SESSION_SECRET |
세션 서명키(필수, 랜덤) |
AUTH_ALLOWED_EMAIL_DOMAINS |
Google 로그인 허용 이메일 도메인(JSON 배열). 기본 ["hs.ac.kr","twentyoz.kr"]. Google Console authorized domains가 아니라 서버에서 email/hd claim으로 강제 |
FRONTEND_ORIGIN_MAP |
API callback host → frontend origin 매핑(JSON 객체). 기본 api-vignette.chanpaca.net → vignette.chanpaca.net, api-vnet.18ka.net → vnet.18ka.net |
OPENAI_API_KEY |
음성(STT/TTS) |
ANTHROPIC_API_KEY |
claude_api provider용. API 컨테이너가 아니라 엔진 게이트웨이 호스트에 주입 |
ENGINE_MODE / ENGINE_URL |
provider와 엔진 게이트웨이 위치(위 표) |
SITE_ADDRESS |
외부노출 도메인(예: vignette.chanpaca.net). 비우면 로컬 :80 |
ACME_EMAIL |
외부노출 시 Let's Encrypt 자동 TLS용 |
HTTP_PORT/HTTPS_PORT |
호스트 포트 매핑 |
4. 외부 공유 (chanpaca.net, 교수 테스트)
두 가지 — 호스트 상황에 맞게:
- Caddy 자동 TLS: 공인 IP·도메인 있으면
SITE_ADDRESS=vignette.chanpaca.net+ACME_EMAIL→ Caddy가 인증서 자동 발급.
4.1 vnet.18ka.net 공개 경로
vnet.18ka.net을 공개 Google OAuth로 쓰려면 세 조건이 같이 맞아야 한다.
- DNS:
vnet.18ka.net은 웹,api-vnet.18ka.net은 API로 라우팅되어야 한다. - API 설정:
CORS_ORIGINS에https://vnet.18ka.net,FRONTEND_ORIGIN_MAP에api-vnet.18ka.net=https://vnet.18ka.net이 있어야 한다. - Google Cloud Console: Authorized redirect URI에
https://api-vnet.18ka.net/auth/callback을 추가해야 한다.
현재 이 저장소의 코드와 scripts/start-public-runtime.ps1은 2번을 회귀 테스트와 기본값으로 고정한다. 1번과 3번은 외부 콘솔/도메인 소유자 설정이다.
- Cloudflare/Tailscale 터널: 공인 IP 없을 때(네 PC). 단 음성 SSE/WSS는 버퍼링 충돌이 있어 Caddyfile에서
flush_interval -1로 흘려보냄(red team F-07 반영). 터널도 SSE 무버퍼 경로 분리 권장.
5. 스케일업 / 이전
- 수직: compose 그대로, 호스트 사양만 키움.
- 수평:
docker compose up --scale api=3(api 무상태 설계 전제, 세션은 DB/Redis). proxy가 라운드로빈. - 이전:
pgdata·ragmodels볼륨만 새 호스트로 옮기고.env채워up. (rag 모델 캐시 볼륨 덕에 재다운로드 0) - 클라우드: 동일 compose.
ENGINE_MODE=claude_api와 게이트웨이 주소를 지정하고 게이트웨이 호스트에ANTHROPIC_API_KEY를 주입한다.
6. 데이터 주권 / 보안
- DB는 NAS PostgreSQL(국내). 미성년 사례데이터는 repo·이미지에 절대 미포함(
.gitignore). - 외부 LLM 전송 전 PII 마스킹 미들웨어 통과(red team F-03).
- proxy 인증 게이트 뒤에서만 SSE/WSS 노출(무인증 IDOR 차단, F-20).
현 단계: 구성 골격(compose·Dockerfile·Caddy) 완비. 앱 코드(apps/web, apps/api) 채워지면 그대로 빌드된다.