TripFit ์๋ฒ์ ๋ก์ปฌ ๊ฐ๋ฐ ๊ตฌ๋, EC2 4๋ ์ธํ๋ผ ๋ฐฐํฌ ์ ์ฐจ, HTTPS ์ธ์ฆ์ ๋ฐ๊ธ ๋ฐ ์ด์ ์คํฌ๋ฆฝํธ ์คํ๋ฒ์ ๋ค๋ฃจ๋ ๊ฐ์ด๋๋ค. ๊ฐ ์๋ฒ๋ณ ๊ธฐ๋ ์์, Let's Encrypt TLS ๋ฐ๊ธ, CI/CD ์๋ ๋ฐฐํฌ ํ๋ฆ, ์คํ ์ด ์ฌ์ฌ ์ OAuth ์ฝ์ ๋ฑ๋ก ์ฒดํฌ๋ฆฌ์คํธ๋ฅผ ์ค๋ช
ํ๋ค. ์์ธ ์ธํ๋ผ ์ฌ์ ๋ฐ ํ๊ฒฝ ๋ณ์(GitHub Secrets) ์ ์ฒด ๋ชฉ๋ก์ deploy/environment-reference.md๋ฅผ ์ฐธ๊ณ ํ๋ค.
| ๊ด๋ จ ๋ฌธ์ | ์ฉ๋ |
|---|---|
environment-reference.md |
์ธํ๋ผ ์ฌ์ ๋ฐ ํ๊ฒฝ ๋ณ์(Secrets) ์ ์ฒด ํ (SSOT) |
docs/decisions/002-domain-split-vercel-api.md |
๋๋ฉ์ธ ๋ถ๋ฆฌ ํ์ |
docs/architecture.md |
ํ๋กํยทddl-autoยท๋ ์ด์ด |
ec2-split-deployment.md |
VPCยทSGยท1โ2 EC2 ์ฌํ |
holiday-api-setup.md |
๊ณตํด์ผ API ์ธ์ฆํค ๋ฐ๊ธยท๋ฑ๋กยท๊ฒ์ฆ |
.claude/rules/deployment.md |
์์ด์ ํธ ๋ฐฐํฌ ๊ฐ๋๋ ์ผ |
์ญํ ๋ณ๋ก ๋ถ๋ฆฌ๋์ด ์์ต๋๋ค.
| ๋๋ฉ์ธ | ํธ์คํ | ์ด repo |
|---|---|---|
tripfit.online |
Vercel (React/Next.js) | ํ๋ก ํธ ์ ์ฅ์ โ EC2์ frontend ์ปจํ ์ด๋ ์์ |
api.tripfit.online |
EC2 A (Nginx + Spring Boot) | deploy/app/, deploy/nginx/ |
grafana.tripfit.online |
EC2 C (Nginx + Grafana) | deploy/monitoring/ โ ์ด์์ฉ, ํด๋ผ์ด์ธํธ ์ฑ๊ณผ ๋ฌด๊ด |
Route 53
tripfit.onlineโ Vercel DNS (CNAME/A, Vercel ๋์๋ณด๋ ์๋ด ๋ฐ๋ฆ)api.tripfit.onlineโ EC2 A Elastic IP (A ๋ ์ฝ๋)grafana.tripfit.onlineโ EC2 C Elastic IP (A ๋ ์ฝ๋)
ํ๋ก ํธ ํ๊ฒฝ ๋ณ์ (Vercel)
NEXT_PUBLIC_API_BASE_URL=https://api.tripfit.online์์ธ: docs/decisions/002-domain-split-vercel-api.md
| ๊ฒฝ๋ก | ์๋ฒ | ์ค๋ช |
|---|---|---|
app/ |
EC2 A | Nginx(:80/443) + Certbot + Spring Boot API |
nginx/ |
EC2 A | api.tripfit.online ๋ฆฌ๋ฒ์ค ํ๋ก์ |
mysql/ |
EC2 B | MySQL 8.0 ์ ์ฉ |
monitoring/ |
EC2 C | Loki(:3100) + Grafana(:3000) โ A/B ์ปจํ ์ด๋ ๋ก๊ทธ ์์งยท์กฐํ |
redis/ |
EC2 D | Redis(:6379) โ refresh token ์ ์ฅ์ + ๊ณตํด์ผ ์บ์, sg-app์์๋ง ์ ๊ทผ |
../docker-compose.yml |
๋ก์ปฌ | App build + MySQL (--profile edge ์ API Nginx) |
์์ธ ๋คํธ์ํฌยทSG: ec2-split-deployment.md
cp .env.example .env
docker compose up -d # MySQL๋ง
./gradlew bootRun # Spring (localhost:8080, .env ๋ก๋)Spring๊น์ง Docker๋ก ๊ฒ์ฆํ ๋๋ง:
docker compose --profile app up -d --build
./scripts/verify-deploy.shcd deploy/mysql
cp .env.example .env
docker compose up -dํ๋ก๋น์ ๋ ์๋ฃ(2026-08-10) โ TP-redis(i-06fb8540484834192), A/B/C์ ๋์ผ VPCยท์๋ธ๋ทยทํคํ์ด, t3.micro. Private IP 172.31.38.246, ๋ณด์ ๊ทธ๋ฃน TP-redis๊ฐ 6379๋ฅผ sg-app(TP-server)์์๋ง ํ์ฉ. Elastic IP ์์ โ App๋ง ์ฌ์ค IP๋ก ์ ๊ทผํ๊ณ ์ธ๋ถ ๋๋ฉ์ธ์ด ํ์ ์๋ ๋ด๋ถ ์ธํ๋ผ๋ผ EC2 A/C์ ๋ค๋ฆ.
cd deploy/redis
cp .env.example .env
docker compose up -d์ต์ด 1ํ ์๋ ๋ถํธ์คํธ๋ฉ ์ ์ฉ โ TLS ๋ฐ๊ธ๊น์ง ๋๋ด๊ณ ๋๋ฉด ์ดํ ๋ฐฐํฌ๋ main push โ CI/CD๊ฐ GitHub Secrets๋ง์ผ๋ก ์ฒ๋ฆฌํ๋ค (์๋ ํ๊ฒฝ ๋ณ์ ์ ). .env๋ ์ด ์ต์ด ์ค์ ๊ณผ ์๋ ์ฌ๋ฐฐํฌ(ec2-deploy-app.sh ๋จ๋
์คํ) ๋๋ง ์ด๋ค.
cd deploy/app
cp .env.example .env
# .env: MYSQL_HOST, GHCR_IMAGE
export SPRING_DATASOURCE_USERNAME=...
export SPRING_DATASOURCE_PASSWORD=...
export CERTBOT_EMAIL=codus5068@naver.com
# private GHCR: export GHCR_PAT=... GHCR_USERNAME=...
../../scripts/setup-api-https.sh๋๋ ๋จ๊ณ๋ณ:
../../scripts/ec2-deploy-app.sh # nginx + certbot + app (์์ self-signed)
../../scripts/init-letsencrypt.sh # Let's Encrypt ์ค์ ์ธ์ฆ์
VERIFY_TLS=true ../../scripts/verify-deploy-app.sh๊ฒ์ฆ:
curl -fsSI https://api.tripfit.online/health
curl -fsSI https://api.tripfit.online/api/v1/... # API ๊ตฌํ ํ์คํ ๊ตฌ์ฑ (deploy/app/docker-compose.yml)
| ์๋น์ค | ์ญํ |
|---|---|
nginx |
api.tripfit.online :80/:443 โ app:8080 |
certbot |
LE ๋ฐ๊ธยท12h ๊ฐฑ์ ์๋ |
app |
Spring Boot (GHCR), 127.0.0.1:8080๋ง ๋ฐ์ธ๋ฉ |
cron ๊ฐฑ์ (๊ฐฑ์ ์ nginx reload ํฌํจ):
0 3 * * * cd /path/to/TripFit-server/deploy/app && /path/to/TripFit-server/scripts/renew-letsencrypt.sh../../scripts/setup-api-https.sh --skip-tls๊ฒฐ์ ๊ทผ๊ฑฐ: docs/decisions/009-observability-logging.md (Issue #77). A/B์ ๊ฐ์ VPCยท์๋ธ๋ทยทํคํ์ด ์ฌ์ฌ์ฉ, ๋ณ๋ t3.micro. Elastic IP ๋ณด์ (EC2 A์ ๋์ผ ์ด์ โ Grafana URLยทSSH๊ฐ ์ธ์คํด์ค ์ฌ์์์ ํ๋ค๋ฆฌ์ง ์๋๋ก).
cd deploy/monitoring
cp .env.example .env # GRAFANA_ADMIN_PASSWORD ์ฑ์ฐ๊ธฐ
docker compose up -dHTTPS (EC2 A deploy/app์ ๋์ผ ํจํด โ nginx+certbot, Let's Encrypt)
export DEPLOY_DIR=$(pwd)/deploy/monitoring
export CERTBOT_DOMAIN=grafana.tripfit.online
../../scripts/ensure-ssl-certs.sh # ์์ self-signed (nginx 443 ๊ธฐ๋์ฉ)
docker compose up -d
CERTBOT_EMAIL=codus5068@naver.com ../../scripts/init-letsencrypt.sh- ์คํ:
nginx(:80/:443) โgrafana(๋ด๋ถ127.0.0.1:3000๋ง ๋ฐ์ธ๋ฉ, ๊ณต๊ฐ ๋ ธ์ถ ์์),certbot(๋ฐ๊ธยท๊ฐฑ์ ),loki(:3100, A/B๊ฐ pushํ๋ ๋์ โ ์ง์ ๋ธ๋ผ์ฐ์ ์กฐํ ๋์ ์๋). - Route 53:
grafana.tripfit.onlineA โ EC2 C Elastic IP. SG๋ 22/80/443๋ง ๊ณต๊ฐ, 3100์ A/B SG๋ก๋ง ์ ํ. - cron ๊ฐฑ์ (A์ ๋์ผ ์คํฌ๋ฆฝํธ, ๋๋ฉ์ธ๋ง ๋ค๋ฆ):
0 3 * * * DEPLOY_DIR=/home/ubuntu/monitoring CERTBOT_DOMAIN=grafana.tripfit.online /home/ubuntu/scripts/renew-letsencrypt.sh - A/B ์ชฝ ์ต์ด 1ํ ํ์ ์์
โ Loki๊ฐ ๋จ๊ธฐ ์ ์ AยทB์์ ๊ฐ๊ฐ ์คํํด์ผ
docker compose up -d๊ฐdriver: loki๋ก ์ฑ๊ณตํ๋ค:(์ด๋ฏธdocker plugin install grafana/loki-docker-driver:latest --alias loki --grant-all-permissions
deploy/app/docker-compose.yml,deploy/mysql/docker-compose.yml์๋จ ์ฃผ์์๋ ๋์ผ ์๋ด๊ฐ ์์.) - ๋ก๊ทธ ๋ณด์กด:
deploy/monitoring/loki-config.yaml์retention_period(ํ์ 3์ผ, ๋์คํฌ 6.7GB ์ ์ฝ) + compactor๊ฐ ์๋ ์ญ์ โ ๋ณ๋ cron ๋ถํ์. - ํ๋ก ํธ ๊ณต์ ๊ณ์ : IP ์ ํ ๋์ Grafana Viewer role ์ฝ๊ธฐ ์ ์ฉ ๊ณ์ ์ ๋ฐ๊ธํ๋ค(์ฌํยท์นดํ ๋ฑ IP๊ฐ ๋งค๋ฒ ๋ฐ๋๋ ํ๋ก ํธ ํ๊ฒฝ์ IP ํ์ดํธ๋ฆฌ์คํธ๋ ๋ง์ง ์์). ๊ณ์ ์ถ๊ฐ ๋ฐ๊ธ์ admin์ผ๋ก ๋ก๊ทธ์ธ ํ Administration โ Users ๋๋:
curl -u admin:$GRAFANA_ADMIN_PASSWORD -X POST https://grafana.tripfit.online/api/admin/users \ -H 'Content-Type: application/json' \ -d '{"name":"<์ด๋ฆ>","login":"<์์ด๋>","email":"<์์ด๋>@tripfit.local","password":"<๋น๋ฐ๋ฒํธ>"}' # ๊ธฐ๋ณธ org role์ด Viewer๋ผ ๋ณ๋ ์ค์ ์์ด๋ ์ฝ๊ธฐ ์ ์ฉ์ด์ง๋ง, ๋ช ์์ ์ผ๋ก ํ์ธํ๋ ค๋ฉด: curl -u admin:$GRAFANA_ADMIN_PASSWORD -X PATCH https://grafana.tripfit.online/api/org/users/<id> \ -H 'Content-Type: application/json' -d '{"role":"Viewer"}'
- ๊ธฐ๋ณธ ๋์๋ณด๋ "TripFit ์๋น์ค ๋ก๊ทธ ๊ฐ์"(
uid: tripfit-overview)๊ฐ ํ ๋์๋ณด๋๋ก ์ค์ ๋์ด ์๋ค โ ์๋ฌ/๊ฒฝ๊ณ ๊ฑด์, nginx 4xx/5xx, app ์๋ฌยท๊ฒฝ๊ณ ยท์ ์ฒด ๋ก๊ทธ ์คํธ๋ฆผ, nginx ์ค๋ฅ ์๋ต ๋ก๊ทธ. Explore ํญ์์ ์ง์ LogQL ์กฐํ๋ ๊ฐ๋ฅ. - CI/CD ๋์ ์๋ โ
mainpush ์๋ ๋ฐฐํฌ๋ EC2 A(app)๋ง ๋ค๋ฃฌ๋ค. EC2 C๋ ์ ๋ช ๋ น์ผ๋ก ์๋ ๋ฐฐํฌยท๊ฐฑ์ . - ์ด ์๋ฒ๋ A/B์ ๋ฌ๋ฆฌ git ์ฒดํฌ์์์ด ์๋๋ผ
~/monitoringยท~/scripts์ ํ์ผ์ ์ง์ ์ฌ๋ฆฐ ์ํ โ ํฅํ git ์ฒดํฌ์์์ผ๋ก ์ ํ ๊ถ์ฅ(009 ํ์ ์์ ).
์ ํ๋ฆฌ์ผ์ด์
์คํ ๋ฐ ๋ฐฐํฌ์ ํ์ํ GitHub Actions Secrets 32๊ฐ ์ ์ฒด ๋ชฉ๋ก๊ณผ ๊ธฐ๋ณธ๊ฐ, ํ์ ์ฌ๋ถ๋ deploy/environment-reference.md์์ ๊ด๋ฆฌํฉ๋๋ค.
- ์๋ ์ฃผ์
:
mainpush โ CI/CD deploy ๋จ๊ณ์์ GitHub Secrets๋ฅผ SSH ์ธ์ ํ๊ฒฝ ๋ณ์๋ก ์ฃผ์ ๋ฐ์ EC2์์exportํdocker compose up -d๋ฅผ ์คํํฉ๋๋ค. ํ ๋ฒ ๋ฑ๋กํด๋๋ฉด ์ดํ ๋ฐฐํฌ๋ GitHub Secrets๋ง ๊ฐฑ์ ํ๋ฉด ๋๋ฉฐ, EC2์ SSH๋ก ์ ์ํดdeploy/app/.env๋ฅผ ์์ฑํ๊ฑฐ๋ ์์ ํ ํ์๊ฐ ์์ต๋๋ค. - Fail-Fast ํ์ ๋ณ์: ํ์๋ก ์ง์ ๋ Secret์ด ๋ฏธ๋ฑ๋ก์ธ ์ฑ๋ก push๋๋ฉด CI/CD ๋ฐฐํฌ ๋จ๊ณ๊ฐ ์ฆ์ ์คํจํฉ๋๋ค. ์ด๋ค ๋ณ์๊ฐ ํ์์ธ์ง๋
environment-reference.md์ ํ๊ฐ SSOT โ ๋ชฉ๋ก์ ์ด ๋ฌธ์์ ์ฎ๊ฒจ ์ ์ง ์์ต๋๋ค(์์ชฝ์ ๋๋ฉด ํ์ชฝ๋ง ๊ณ ์ณค์ ๋ ์ด๊ธ๋ฉ๋๋ค). - Fail-Safe ํธ์คํธ ๋ณ์: ๋ชจ๋ํฐ๋ง(EC2 C)ยทRedis(EC2 D) ํธ์คํธ ๋ณ์๋ Secret ๋ฏธ์ค์ ์์๋ compose ๊ธฐ๋ณธ๊ฐ์ผ๋ก ์ปจํ
์ด๋๊ฐ ์ ์ ๊ธฐ๋๋๋๋ก ์ฒ๋ฆฌ๋ผ ์์ต๋๋ค. ์ฌ์ค IP๊ฐ ๋ฐ๋๋ฉด GitHub Secret๊ณผ compose ๊ธฐ๋ณธ๊ฐ์ ํจ๊ป ๊ฐฑ์ ํด์ผ ํฉ๋๋ค โ ๋ณ์๋ช
ยทํ์ฌ ๊ธฐ๋ณธ๊ฐ์
environment-reference.md์ฐธ์กฐ. FRONTEND_IMAGE์ฌ์ฉ ๊ธ์ง:FRONTEND_IMAGE์ฌ์ฉํ์ง ์์ โ ํ๋ก ํธ๋ Vercel. EC2์ ํ๋ก ํธ์๋ ์ปจํ ์ด๋๊ฐ ์์ผ๋ฏ๋ก ๋ณ์๋ฅผ ์ฌ์ฉํ๊ฑฐ๋ ์ถ๊ฐํ์ง ์์ต๋๋ค.- ์๋ ๋ฐฐํฌ ๋ฐ ๋ก์ปฌ:
scripts/ec2-deploy-app.sh์๋ ์คํ์ด๋ ๋ก์ปฌ docker compose ์์๋.env๋๋export๋ก ๊ฐ์ ์ ๋ฌํฉ๋๋ค (deploy/app/.env.example๋ฐ ๋ฃจํธ.env์ฐธ๊ณ ). - ์ ์ฒด ํ๊ฒฝ ๋ณ์ ํ ๋ฐ ์์ธ ์ค๋ช
:
deploy/environment-reference.md์ฐธ์กฐ
์ GOOGLE_CLIENT_ID๋ฅยทKAKAO_ADMIN_KEY๋ env(GitHub Secrets)์ ๊ฐ๋ง ๋ฑ๋กํ๋ฉด ๋์ง๋ง, ๊ฐ ์์
๋ก๊ทธ์ธ ์ฝ์(Google Cloud ConsoleยทApple DeveloperยทKakao Developers ๋ฑ) ์ชฝ ์ค์ ์ ๋ณ๋๋ก ์ฑ์์ผ ์ค์ ๋ก๊ทธ์ธ์ด ๋์ํ๋ค. ์ฝ๋ยท๊ฒ์ฆ ๋ก์ง(GoogleTokenVerifierยทAppleTokenVerifierยทKakaoTokenVerifierยทOAuthProperties)์ ์ด๋ฏธ ์๋ฃ๋ ์ํ โ ์๋๋ ์ฝ์ ๋ด๋น์๊ฐ ์ฝ์ ํ๋ฉด์์ ์ง์ ๋ฑ๋กํ๋ฉด ๋๋ ํญ๋ชฉ๋ฟ์ด๋ค.
๋ฏธ๋ฑ๋ก ์ํ๋ก๋ redirect_uri_mismatchยทDEVELOPER_ERROR ๋ฑ์ผ๋ก ๋ก๊ทธ์ธ ์์ฒด๊ฐ ์คํจํ๋ฏ๋ก ์คํ ์ด ์ฌ์ฌ ์ ์ถ ์ ๋ฐ๋์ ํ์ธ. (๊ณผ๊ฑฐ GitHub Issue #62๋ก ์ถ์ ํ๋ ์ฒดํฌ๋ฆฌ์คํธ์์ผ๋ 2026-08-02๋ถ๋ก ์ด์๋ฅผ ๋ซ๊ณ ์ด ๋ฌธ์๋ฅผ SSOT๋ก ํตํฉํ๋ค โ ์๋๊ฐ ์ต์ ์ํ.)
๋ด๋น ๊ตฌ๋ถ:
| ๋ด๋น | ํ์ํ ๊ฒ |
|---|---|
| ๋ฐฑ์๋ | ์ฝ๋ ๋ณ๊ฒฝ ์์ โ ๊ฐ ์ฝ์์ ์ค์ ๊ฐ ์ ๋ ฅ๋ง(๊ณ์ ์ ๊ทผ ๊ถํ ํ์) |
| ํ๋ก ํธ | ์ต์ข ์๋น์ค ๋๋ฉ์ธยท์ฝ๋ฐฑ ๋ผ์ฐํธ(๋ฆฌ๋ค์ด๋ ์ URI๋ก ๋ฑ๋ก๋ ๊ฒฝ๋ก) ํ์ ํด์ ์ ๋ฌ โ Google/Kakao Redirect URIยท๋ค์ดํฐ๋ธ ์ฑ ํคยทํจํค์ง๋ช ์ ์ด๋ฏธ ์ฝ๋ ํ์ธ์ผ๋ก ์ ๋ฌ ์๋ฃ |
| ๋น๋ ํ๊ฒฝ ๋ด๋น์ | Android ๋๋ฒ๊ทธยท๋ฆด๋ฆฌ์ฆ keystore์ SHA-1(Google)ยทํค ํด์(Kakao) ์ถ์ถ โ ๋ฆฌํฌ์ keystore๊ฐ ์์ด ์ฝ์ ๋ด๋น์๊ฐ ๋์ ํ ์ ์์ |
| Apple/Google ๊ณ์ ๋ด๋น์ | App Store ID๋ App Store Connect ์ฑ ๋ฑ๋ก ์๋ฃ ํ์๋ง ๋ฐ๊ธ โ ๊ฒ์ ๋ด๋น์๊ฐ ๊ฐ ์ ๋ฌ |
๊ธฐ์กด ๋ก๊ทธ์ธ์ฉ GCP ํ๋ก์ ํธ์ APIs & Services โ Credentials์์ ์๋ 3๊ฐ Client(์ด๋ฏธ ๋ฐ๊ธ๋ผ ์์)๋ฅผ ๊ฐ๊ฐ ์ฐ๋ค.
| Client ํ์ | ๋์ env | ์ง๊ธ ๋ฑ๋กํ ๊ฒ | ์์ |
|---|---|---|---|
| Web application | GOOGLE_CLIENT_ID |
์น์ธ๋ ์๋ฐ์คํฌ๋ฆฝํธ ์๋ณธ(https://tripfit.online) + ์น์ธ๋ ๋ฆฌ๋ค์ด๋ ์
URI(ํ๋ก ํธ ์ฝ๋ฐฑ ๊ฒฝ๋ก) |
ํ๋ก ํธ ์ต์ข ๋๋ฉ์ธยท์ฝ๋ฐฑ ๋ผ์ฐํธ ํ์ ํ |
| Android | GOOGLE_CLIENT_ID_ANDROID |
ํจํค์ง๋ช
com.tripfit.app + SHA-1 ์ธ์ฆ์ ์ง๋ฌธ(๋๋ฒ๊ทธยท๋ฆด๋ฆฌ์ฆ ๊ฐ๊ฐ) |
SHA-1 ํ๋ณด ์ฆ์ |
| iOS | GOOGLE_CLIENT_ID_IOS |
๋ฒ๋ค ID com.tripfit.app + App Store ID(์ ํ ํ๋) |
์ฑ App Store ๊ฒ์ ํ |
SHA-1 ํ๋ณด ๋ฐฉ๋ฒ โ ๋ฆฌํฌ์ keystore๊ฐ ์์ด ์ฝ์ ๋ด๋น์๊ฐ ์ง์ ๋ฝ์ ์ ์๋ค. ๋น๋ ํ๊ฒฝ(Android Studio/CI) ๋ด๋น์์๊ฒ ์๋ ๋ช ๋ น ์คํ์ ์์ฒญ:
keytool -list -v -keystore ~/.android/debug.keystore -alias androiddebugkey -storepass android -keypass android | grep SHA1๋ฆด๋ฆฌ์ฆ keystore๋ ๋ณ๋ ๋ณด์ ์๊ฐ ๋์ผ ๋ช ๋ น์ผ๋ก ์ถ์ถ(Google Play App Signing์ ์ฐ๋ฉด Play Console์ "์ฑ ๋ฌด๊ฒฐ์ฑ โ ์ฑ ์๋ช " ๋ฉ๋ด์์๋ ํ์ธ ๊ฐ๋ฅ).
๊ฐ ์ผ์น ํ์ธ: apps/app(๋ค์ดํฐ๋ธ ์ฑ)์ GOOGLE_WEB_CLIENT_ID, apps/web์ NEXT_PUBLIC_GOOGLE_CLIENT_ID, ๋ฐฑ์๋ GOOGLE_CLIENT_ID ์ธ ๊ฐ์ด ์ ๋ถ ๊ฐ์ Web Client ID๋ฅผ ๊ฐ๋ฆฌ์ผ์ผ ํ๋ค โ ํ๋๋ผ๋ ๋ค๋ฅด๋ฉด ๊ทธ ๊ฒฝ๋ก๋ง aud mismatch๋ก ๋ก๊ทธ์ธ์ด ์คํจํ๋ค.
Calendar ์ ์ฉ Client(GOOGLE_CALENDAR_CLIENT_ID) ๋ฐ๊ธ์ ์ง๊ธ ์ ํด๋ ๋๋ค โ Calendar FE ์ฐฉ์ ์์ ์ google-calendar-client-id-separation.md "GCP ์ฝ์ ๊ฐ์ด๋" ์ ์ฐธ๊ณ .
์ฑ ๋์๋ณด๋(developers.kakao.com โ ๋ด ์ ํ๋ฆฌ์ผ์ด์
โ ํด๋น ์ฑ)์์:
| ๋ฉ๋ด | ๋ฑ๋กํ ๊ฒ |
|---|---|
| ์ฑ ์ค์ โ ํ๋ซํผ | Android ํจํค์ง๋ช
com.tripfit.app + ํค ํด์(์๋ ๋ช
๋ น), iOS ๋ฒ๋ค ID com.tripfit.app, ๋ค์ดํฐ๋ธ ์ฑ ํค๊ฐ 6a686bacf5c3efba84a1cc8d0e655cd5์ ์ผ์นํ๋์ง ํ์ธ |
| ์นด์นด์ค ๋ก๊ทธ์ธ โ ํ์ฑํ ์ค์ | ON |
| ์นด์นด์ค ๋ก๊ทธ์ธ โ Redirect URI | https://tripfit.online/auth/kakao/callback(์ด์) + http://localhost:3000/auth/kakao/callback(๋ก์ปฌ) โ ํ๊ฒฝ B(๋ชจ๋ฐ์ผ ์น/๋ฐ์คํฌํฑ ๋ธ๋ผ์ฐ์ ) JS SDK ๋ฆฌ๋ค์ด๋ ํธ ํ๋ก์ฐ์ฉ |
| ์นด์นด์ค ๋ก๊ทธ์ธ โ ๋์ํญ๋ชฉ | ๋๋ค์ยทํ๋กํ ์ฌ์ง ํ์ฑํ(์ ํ ๋์๋ก ์ถฉ๋ถ), ์ด๋ฉ์ผ์ ํ์ ์ ํ์ฑํ โ ๊บผ์ ธ ์์ผ๋ฉด ๋ฐฑ์๋๋ ํด๋น ํ๋๋ฅผ null๋ก ๋ฐ์(๋ก๊ทธ์ธ ์์ฒด๋ ์ ๊นจ์ง) |
| ๋ณด์ โ Admin Key | ์ด๋ฏธ ๋ฐ๊ธ ์๋ฃ ์ํ โ KAKAO_ADMIN_KEY GitHub Secret์ ๋ฑ๋ก๋ผ ์๋์ง๋ง ์ฌํ์ธ |
ํค ํด์ ํ๋ณด ๋ฐฉ๋ฒ (Google SHA-1๊ณผ ๊ฐ์ keystore ํ์):
keytool -exportcert -alias androiddebugkey -keystore ~/.android/debug.keystore -storepass android | openssl sha1 -binary | openssl base64๋ฆด๋ฆฌ์ฆ์ฉ์ ๋ฆด๋ฆฌ์ฆ keystore๋ก ๋์ผ ๋ช ๋ น์ ์คํํด ๋ณ๋ ๋ฑ๋ก.
.github/workflows/ci-cd.yml โ main push โ GHCR push โ EC2 A deploy (app + nginx + certbot)
deploy ์ ์ GitHub Secrets ์ ๋ถ๊ฐ app ์ปจํ
์ด๋์ ์๋ ์ฃผ์
๋๋ค โ EC2 ์ชฝ .env ์ ๋ฌด์ ๋ฌด๊ดํ๊ฒ ๋์ํ๋ค.
EC2 B(MySQL)ยทEC2 C(๋ชจ๋ํฐ๋ง)๋ ์ด ํ์ดํ๋ผ์ธ ๋ฐ โ ์ต์ด ์ค์ ยท์ฌ๋ฐฐํฌ ๋ชจ๋ ์๋(deploy/mysql/, deploy/monitoring/ ์ ์ฐธ๊ณ ).
| ์คํฌ๋ฆฝํธ | ์ฌ์ฉ ์์ |
|---|---|
scripts/verify-deploy.sh |
๋ก์ปฌ compose |
scripts/setup-api-https.sh |
๋ฐฐํฌ + LE ๋ฐ๊ธ ์ผ๊ด (๊ถ์ฅ) |
scripts/ec2-deploy-app.sh |
pull + up (์์ self-signed) |
scripts/init-letsencrypt.sh |
LE ์ต์ด ๋ฐ๊ธ (api.tripfit.online) |
scripts/renew-letsencrypt.sh |
๊ฐฑ์ + nginx reload (cron) |
scripts/verify-deploy-app.sh |
EC2 A ๊ฒ์ฆ (VERIFY_TLS=true) |