feat: Docker 셀프호스팅 전체 스택 구현#61
Open
hyoda wants to merge 2 commits into
Open
Conversation
Docker Compose 기반으로 OTU 전체 스택(Next.js + Supabase 7개 서비스)을 셀프호스팅할 수 있는 인프라를 구현한다. 주요 구성: - 3단계 멀티스테이지 Dockerfile (deps → builder → runner) - docker-compose.yml (소스 빌드), docker-compose.prod.yml (사전 빌드 이미지) - Caddy 리버스 프록시 (자동 HTTPS via Let's Encrypt) - Kong API Gateway (auth/rest/realtime/storage 라우팅) - otu.sh CLI (install/start/stop/upgrade/backup) - install-remote.sh 원클릭 설치 스크립트 - docker/entrypoint.sh 멱등 마이그레이션 + seed + 런타임 환경변수 치환 - GHCR 이미지 빌드/배포 CI/CD 워크플로우 보안: - DB_ENC_KEY: AES-128 호환 16바이트 랜덤 생성 (openssl rand -hex 8) - Kong entrypoint: 템플릿 파일 존재 + ANON_KEY/SERVICE_ROLE_KEY 빈값 검증 - 마이그레이션 VERSION 숫자 검증, FILENAME psql -v 파라미터 바인딩 (SQL injection 방지) - MIGRATION_FAIL_FAST 옵션으로 마이그레이션 실패 시 앱 시작 차단 빌드 안정성: - node:20-alpine3.21 태그 고정 (재현 가능한 빌드) - Docker healthcheck: 127.0.0.1 사용 (Alpine wget IPv6 해석 문제 방지) - entrypoint.sh set -e 환경에서 psql 실패 시 exit code 안전 캡처 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
셀프호스팅 환경에서 앱 코드가 동작하도록 AI Provider 분기와
Vercel 전용 모듈 처리를 추가한다.
AI Provider 추상화:
- AIProvider 타입 ('gateway' | 'openai') 및 getAIProvider() 함수 추가
- askLLM, captioning, titling 라우트에서 provider별 모델 분기
- src/functions/ai.js 임베딩에서 provider별 모델 선택
- runtime 'nodejs' 변경 (셀프호스팅 환경 Node.js 모듈 호환)
Vercel 전용 모듈 처리 (stub 방식):
- middleware.ts, supabase/utils/middleware.ts는 upstream과 100% 동일하게 유지
- Docker 빌드 시에만 @vercel/flags, @vercel/functions의 JS 구현을
no-op stub으로 교체 (Dockerfile RUN cp 단계)
- .d.ts 타입 선언은 원본 유지 → TypeScript 빌드 보장
- Vercel 배포에는 영향 없음 (Dockerfile을 사용하지 않으므로)
기타:
- next.config.js output: 'standalone' 설정 (Docker 빌드용)
- BlockNoteEditor/utils.ts 에러 메시지 개선
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Contributor
🔍 PR #61 종합 리뷰 결과리뷰 범위: +2495/-46 라인, 31개 파일 (신규 23개, 수정 8개) 🔴 Critical Issues (11건) - 머지 전 반드시 수정 필요보안 관련
에러 핸들링
🟡 Important Issues (11건) - 권장 수정
💡 Suggestions (10건)
✅ Positive Observations
📋 권장 조치 순서머지 전 반드시
머지 전 권장
🤖 Claude Code로 자동 생성된 리뷰입니다 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Docker Compose 기반으로 OTU 전체 스택(Next.js + Supabase 7개 서비스 + Caddy)을 셀프호스팅할 수 있는 인프라를 구현합니다.
PR #31 2차 리뷰 피드백 반영 현황
이 PR은 PR #31의 2차 리뷰 피드백(Critical 3건 + Important 6건 + Suggestion 5건)을 모두 반영하여 upstream/main 최신 코드 기반으로 재구현한 것입니다.
Critical (3건 — 모두 반영)
DB_ENC_KEY하드코딩 제거openssl rand -hex 8로 AES-128 호환 16바이트 랜덤 생성.docker-compose.yml,generate-keys.sh,otu.sh모두 환경변수 참조로 변경MIGRATION_FAIL_FAST옵션docker/entrypoint.sh에서MIGRATION_FAIL_FAST=true시 마이그레이션 실패 카운터 > 0이면exit 1으로 앱 시작 차단ANON_KEY/SERVICE_ROLE_KEY빈값 검증 추가Important (6건 — 4건 반영, 2건 기반영/범위 밖)
/app/.next디렉토리 존재 확인 후 WARNING 로그 출력psql -v version="$VERSION" -v name="$FILENAME"파라미터 바인딩 사용Suggestion (5건 — 모두 반영)
node:20-alpine3.21사용install-remote.sh상단에 주의사항 추가.env.example에서 "브라우저 구현에 따라 다를 수 있으며" 문구 보완핵심 설계 결정: Vercel 의존성 처리 (stub 방식)
문제
upstream 코드의
middleware.ts와supabase/utils/middleware.ts에서@vercel/flags(reportValue)와@vercel/functions(ipAddress)를 static import하고 있습니다. 셀프호스팅(Docker) 환경에서는 이 패키지가 정상 동작하지 않습니다.검토한 접근법
require()+ try/catch로 MODULE_NOT_FOUND 처리채택한 방식 상세
장점:
middleware.ts,supabase/utils/middleware.ts가 upstream/main과 100% 동일 → 머지 충돌 없음.d.ts타입 선언은 원본 유지 → TypeScript 빌드 보장배포 테스트 결과
otu.hyoda.kr(AWS Lightsail, Ubuntu 22.04)에서 실제 배포 테스트를 수행했습니다.서비스 상태
테스트 중 발견/수정한 이슈
entrypoint.shgit 실행 권한 누락chmod +x반영set -e+$()서브쉘에서 psql 실패 시 즉시 종료&& RC=0 || RC=$?패턴으로 안전 캡처Bad key sizeopenssl rand -hex 8로 변경127.0.0.1사용영향 범위 및 머지 시 고려사항
Vercel 배포 영향
getAIProvider()분기 추가.AI_PROVIDER환경변수가 없으면 기본값'gateway'로 기존 동작과 동일output: 'standalone'추가 — Vercel은 이 설정을 무시하고 자체 빌드 파이프라인을 사용하므로 동작에 영향 없음. 단, Vercel 팀에서 이 설정이 의도하지 않은 동작을 유발하는지 확인 필요AIProvider타입과getAIProvider(),canUseAI(),getAIDisabledReason()등 새 함수 추가. 기존 함수 시그니처 변경 없음반드시 확인
output: 'standalone'이 Vercel 빌드에 영향을 주는지AI_PROVIDER환경변수 미설정 시 기존 gateway 모드로 fallback되는지@vercel/flags@2.6.3→flags로 rename 권고. 별도 이슈로 대응 필요가급적 확인
docker compose --env-file docker/.env config)otu.sh install로컬 모드 정상 동작참고
@lingui/swc-plugin미설치로 인한 테스트 실패는 기존 이슈 (이 PR과 무관)PERSONAL_SAAS_GUIDE.md는 이 PR에 포함되지 않음파일 목록
신규 (23개)
Docker 인프라
.dockerignore— 빌드 제외 패턴Dockerfile— 3단계 멀티스테이지 빌드docker-compose.yml— 개발/소스 빌드 구성docker-compose.prod.yml— GHCR 사전 빌드 이미지 구성docker/.env.example— 환경변수 템플릿docker/caddy/Caddyfile— 리버스 프록시 (자동 HTTPS)docker/db/Dockerfile— PostgreSQL + pgvector + pgroongadocker/db/init-extensions.sql— DB 확장 초기화docker/db/init-roles.sh— Supabase 역할 비밀번호 설정docker/entrypoint.sh— 앱 시작 (마이그레이션 + seed + 환경변수 치환)docker/generate-keys.sh— 보안 키 생성 스크립트docker/kong/entrypoint.sh— Kong 환경변수 치환 + 검증docker/kong/kong.yml— Kong 선언적 라우팅 설정docker/lib-jwt.sh— JWT 생성 공통 라이브러리docker/stubs/@vercel/flags/dist/index.js— Vercel flags ESM stubdocker/stubs/@vercel/flags/dist/index.cjs— Vercel flags CJS stubdocker/stubs/@vercel/functions/index.js— Vercel functions CJS stubdocker/volumes/db/init/00-init-extensions.sql— 볼륨 마운트용 초기화 SQLCLI, 문서, CI/CD
otu.sh— 셀프호스팅 CLI (install/start/stop/upgrade/backup)install-remote.sh— 원클릭 설치 스크립트docs/self-hosting.md— 셀프호스팅 가이드.github/workflows/docker-publish.yml— GHCR 이미지 빌드/배포수정 (8개)
.gitignoredocker/.env,backups/추가next.config.jsoutput: 'standalone'추가src/functions/ai/config.tsAIProvider타입,getAIProvider()함수 추가src/functions/ai.jsapp/api/ai/askLLM/openai/route.tsxapp/api/ai/captioning/route.tsapp/api/ai/titling/route.tsapp/api/ai/similaritySearch/route.tsxTest plan
otu.hyoda.kr실배포 테스트 완료 (7개 서비스 전체 healthy)AI_PROVIDER미설정 시 gateway fallback)bash otu.sh install로컬 모드)🤖 Generated with Claude Code
Closes #30