diff --git a/README.md b/README.md index 8947e02..67684fb 100644 --- a/README.md +++ b/README.md @@ -45,19 +45,19 @@ EXPO_PUBLIC_SOUNDLOG_API_SOURCE=server EXPO_PUBLIC_SOUNDLOG_API_BASE_URL=/api/so ``` Vercel web 배포는 브라우저 API 호출을 같은 origin에서 처리하도록 -`https://soundlog.shop/api/soundlog` rewrite proxy를 사용합니다. 브라우저와 네이티브 앱은 별도 `api` 서브도메인을 쓰지 않습니다. Vercel 내부 rewrite 대상은 -`SOUNDLOG_API_ORIGIN` 환경변수로 관리하며, 이 값은 최신 SoundLogServer origin이어야 합니다. `vercel.mjs`의 build command가 +`https://soundlog.shop/api/soundlog` rewrite proxy를 사용합니다. Vercel 내부 rewrite 대상은 +`SOUNDLOG_API_ORIGIN` 환경변수로 관리하며, 이 값은 최신 SoundLogServer origin(`https://api.soundlog.shop`)이어야 합니다. `vercel.mjs`의 build command가 `EXPO_PUBLIC_SOUNDLOG_API_SOURCE=server`와 `EXPO_PUBLIC_SOUNDLOG_API_BASE_URL=/api/soundlog`를 주입합니다. -네이티브 실배포 빌드는 `https://soundlog.shop/api/soundlog` HTTPS 프록시를 사용합니다. 로그인은 Soundlog 자체 이메일/비밀번호 계정으로 처리합니다. +네이티브 실배포 빌드는 `api.soundlog.shop` 서브도메인을 직접 호출합니다(GCP VM 위 Caddy가 HTTPS를 종료). 로그인은 Soundlog 자체 이메일/비밀번호 계정으로 처리합니다. ## 테스트 설치 빌드 -`development`, `preview` EAS profile은 HTTPS Vercel API proxy를 바라보도록 설정되어 있습니다. +`development`, `preview` EAS profile은 `api.soundlog.shop`을 직접 바라보도록 설정되어 있습니다. - Web: `https://soundlog.shop` -- API: `https://soundlog.shop/api/soundlog` +- API: `https://api.soundlog.shop` - API source: `server` - auth: Soundlog 자체 이메일/비밀번호 로그인 - iOS/Android: HTTPS API만 사용 @@ -67,7 +67,7 @@ Mock API로 되돌리는 런타임 경로는 제거했습니다. 화면 상태 API origin이 최신 서버인지 확인하려면 아래처럼 실행합니다. ```bash -SOUNDLOG_API_ORIGIN=http://:4000 npm run check:api-origin +SOUNDLOG_API_ORIGIN=https://api.soundlog.shop npm run check:api-origin ``` 이 검사는 로그인 필수 API도 함께 확인하므로 `SOUNDLOG_CHECK_EMAIL`, @@ -80,7 +80,7 @@ Android 지인 테스트용 내부 배포 빌드는 아래 명령으로 생성 npx eas build --profile preview --platform android ``` -iOS는 TestFlight 또는 ad hoc 기기 등록이 필요합니다. App Store/TestFlight에 올릴 production profile도 현재는 `https://soundlog.shop/api/soundlog`을 사용합니다. +iOS는 TestFlight 또는 ad hoc 기기 등록이 필요합니다. App Store/TestFlight에 올릴 production profile도 현재는 `https://api.soundlog.shop`을 사용합니다. ## 문서 diff --git a/docs/README.md b/docs/README.md index b4ec0f7..27d0ffb 100644 --- a/docs/README.md +++ b/docs/README.md @@ -30,7 +30,7 @@ Soundlog 문서는 목적별로 관리합니다. 공모전 기획, RN 프론트 ## Deployment -- [soundlog.shop 배포 설정](deployment/SOUNDLOG_SHOP_DOMAIN.md): Gabia DNS, Vercel, EC2 API 도메인, EAS env 설정 기준 +- [soundlog.shop 배포 설정](deployment/SOUNDLOG_SHOP_DOMAIN.md): Gabia DNS, Vercel, GCP API 도메인, EAS env 설정 기준 ## Legacy Mock API diff --git a/docs/deployment/SOUNDLOG_SHOP_DOMAIN.md b/docs/deployment/SOUNDLOG_SHOP_DOMAIN.md index e23d09f..eca1619 100644 --- a/docs/deployment/SOUNDLOG_SHOP_DOMAIN.md +++ b/docs/deployment/SOUNDLOG_SHOP_DOMAIN.md @@ -6,7 +6,8 @@ Soundlog 운영/테스트 도메인은 아래 구조로 사용합니다. | --- | --- | --- | | `soundlog.shop` | Vercel | Expo web frontend | | `www.soundlog.shop` | Vercel | Frontend alias | -| `soundlog.shop/api/soundlog` | Vercel rewrite | Express API proxy | +| `api.soundlog.shop` | GCP Compute Engine | Express API (Caddy로 HTTPS 직접 종료) | +| `soundlog.shop/api/soundlog` | Vercel rewrite | 웹 빌드 전용 API 프록시 (브라우저 CORS 회피) | ## Gabia DNS @@ -16,8 +17,9 @@ Gabia DNS 관리툴에서 아래 레코드를 설정합니다. | --- | --- | --- | | `A` | `@` | `76.76.21.21` | | `CNAME` | `www` | `cname.vercel-dns.com.` | +| `A` | `api` | `34.64.116.40` | -별도 `api` 서브도메인은 사용하지 않습니다. API 컨테이너는 EC2 `4000` 포트에서 동작하고, Vercel이 `https://soundlog.shop/api/soundlog/:path*` 요청을 EC2 API로 rewrite합니다. +API 컨테이너는 GCP VM(`soundlog-api`, `asia-northeast3-a`)의 Docker Compose 스택에서 동작하고, VM 위의 Caddy가 `api.soundlog.shop`에 대한 Let's Encrypt 인증서를 자동으로 발급해 HTTPS를 직접 종료합니다. `api` A 레코드가 GCP 정적 IP를 가리키기 전까지는 인증서 발급이 되지 않으므로 `https://api.soundlog.shop`은 동작하지 않습니다. ## Vercel @@ -26,23 +28,23 @@ Vercel project domain에 아래 도메인을 추가합니다. - `soundlog.shop` - `www.soundlog.shop` -Web build는 `vercel.mjs`에서 `EXPO_PUBLIC_SOUNDLOG_API_BASE_URL=/api/soundlog`를 주입합니다. `/api/soundlog/:path*` 요청은 Vercel이 서버 사이드에서 `SOUNDLOG_API_ORIGIN`으로 rewrite합니다. +Web build는 `vercel.mjs`에서 `EXPO_PUBLIC_SOUNDLOG_API_BASE_URL=/api/soundlog`를 주입합니다. `/api/soundlog/:path*` 요청은 Vercel이 서버 사이드에서 `SOUNDLOG_API_ORIGIN`으로 rewrite합니다. 이 프록시는 브라우저 fetch가 same-origin이 되도록 웹 빌드에서만 사용하며, 모바일 앱은 `api.soundlog.shop`을 직접 호출합니다. Vercel 환경변수에 아래 값을 설정합니다. ```dotenv -SOUNDLOG_API_ORIGIN=http://:4000 +SOUNDLOG_API_ORIGIN=https://api.soundlog.shop ``` -브라우저와 앱이 호출하는 공개 API URL은 계속 `https://soundlog.shop/api/soundlog`입니다. `SOUNDLOG_API_ORIGIN`은 Vercel 서버 사이드 rewrite에서만 쓰이는 내부 origin입니다. +브라우저가 호출하는 공개 API URL은 계속 `https://soundlog.shop/api/soundlog`입니다. `SOUNDLOG_API_ORIGIN`은 Vercel 서버 사이드 rewrite에서만 쓰이는 내부 origin입니다. ## EAS app env -`development`, `preview`, `production` profile은 `soundlog.shop` HTTPS Vercel proxy를 사용합니다. +`development`, `preview`, `production` profile은 `api.soundlog.shop`을 직접 호출합니다. ```dotenv EXPO_PUBLIC_SOUNDLOG_API_SOURCE=server -EXPO_PUBLIC_SOUNDLOG_API_BASE_URL=https://soundlog.shop/api/soundlog +EXPO_PUBLIC_SOUNDLOG_API_BASE_URL=https://api.soundlog.shop ``` Production profile은 추가로 약관/개인정보 URL과 지원 메일을 설정합니다. @@ -60,7 +62,9 @@ DNS와 HTTPS 설정이 끝나면 아래 명령으로 확인합니다. ```bash dig +short soundlog.shop A dig +short www.soundlog.shop CNAME +dig +short api.soundlog.shop A curl -I https://soundlog.shop +curl https://api.soundlog.shop/v1/health curl https://soundlog.shop/api/soundlog/v1/health npm run check:deployed-web -- https://soundlog.shop ``` @@ -70,8 +74,8 @@ npm run check:deployed-web -- https://soundlog.shop `SOUNDLOG_CHECK_PASSWORD`를 지정해 고정 검증 계정으로 실행합니다. 값을 지정하지 않으면 스크립트가 `@soundlog.test` 임시 계정을 생성합니다. -EC2 origin을 직접 검증하려면 아래 명령을 실행합니다. 이 검사는 `/openapi.yaml`, fallback 장소 source, Spotify 메타데이터 제거 여부까지 확인하므로 예전 백엔드로 잘못 붙은 경우 실패합니다. +GCP origin을 직접 검증하려면 아래 명령을 실행합니다. 이 검사는 `/openapi.yaml`, fallback 장소 source, Spotify 메타데이터 제거 여부까지 확인하므로 예전 백엔드로 잘못 붙은 경우 실패합니다. ```bash -SOUNDLOG_API_ORIGIN=http://:4000 npm run check:api-origin +SOUNDLOG_API_ORIGIN=https://api.soundlog.shop npm run check:api-origin ``` diff --git a/eas.json b/eas.json index 52657f3..99ec8a1 100644 --- a/eas.json +++ b/eas.json @@ -8,21 +8,21 @@ "developmentClient": true, "distribution": "internal", "env": { - "EXPO_PUBLIC_SOUNDLOG_API_BASE_URL": "https://soundlog.shop/api/soundlog", + "EXPO_PUBLIC_SOUNDLOG_API_BASE_URL": "https://api.soundlog.shop", "EXPO_PUBLIC_SOUNDLOG_API_SOURCE": "server" } }, "preview": { "distribution": "internal", "env": { - "EXPO_PUBLIC_SOUNDLOG_API_BASE_URL": "https://soundlog.shop/api/soundlog", + "EXPO_PUBLIC_SOUNDLOG_API_BASE_URL": "https://api.soundlog.shop", "EXPO_PUBLIC_SOUNDLOG_API_SOURCE": "server" } }, "production": { "autoIncrement": true, "env": { - "EXPO_PUBLIC_SOUNDLOG_API_BASE_URL": "https://soundlog.shop/api/soundlog", + "EXPO_PUBLIC_SOUNDLOG_API_BASE_URL": "https://api.soundlog.shop", "EXPO_PUBLIC_SOUNDLOG_API_SOURCE": "server", "EXPO_PUBLIC_SOUNDLOG_PRIVACY_URL": "https://soundlog.shop/legal/privacy", "EXPO_PUBLIC_SOUNDLOG_SUPPORT_EMAIL": "support@soundlog.shop", diff --git a/scripts/check-api-origin.js b/scripts/check-api-origin.js index dab7c13..445a1fa 100644 --- a/scripts/check-api-origin.js +++ b/scripts/check-api-origin.js @@ -5,7 +5,7 @@ const apiOrigin = (process.argv[2] || process.env.SOUNDLOG_API_ORIGIN || '').rep let authHeaderPromise; if (!apiOrigin) { - console.error('Usage: npm run check:api-origin -- http://:4000'); + console.error('Usage: npm run check:api-origin -- https://api.soundlog.shop'); process.exit(1); } diff --git a/scripts/check-server-web-export.js b/scripts/check-server-web-export.js index fd65fdb..1e3ecf6 100644 --- a/scripts/check-server-web-export.js +++ b/scripts/check-server-web-export.js @@ -200,7 +200,7 @@ function verifyBundle(bundleText) { assertExcludes( bundleText, /http:\/\/\d+\.\d+\.\d+\.\d+:4000/, - 'Server web export must not inline a direct EC2 HTTP API URL.', + 'Server web export must not inline a direct raw-IP HTTP API URL.', ); [ ['authMockHandlers', 'Server web export must not include auth mock handlers.'], diff --git a/scripts/require-vercel-api-origin.js b/scripts/require-vercel-api-origin.js index 13b1024..11c219e 100644 --- a/scripts/require-vercel-api-origin.js +++ b/scripts/require-vercel-api-origin.js @@ -3,12 +3,11 @@ const apiOrigin = process.env.SOUNDLOG_API_ORIGIN?.replace(/\/+$/, ''); const staleOrigins = new Set([ 'http://52.79.185.121:4000', - 'https://api.soundlog.shop', ]); if (!apiOrigin) { console.error( - 'SOUNDLOG_API_ORIGIN is required for Vercel builds. Set it to the current SoundLogServer origin, for example http://:4000.', + 'SOUNDLOG_API_ORIGIN is required for Vercel builds. Set it to the current SoundLogServer origin, for example https://api.soundlog.shop.', ); process.exit(1); }