Flutter + Spring Boot Docker 배포 트러블슈팅 기록
앱 Duo를 개발하면서 겪은 배포 트러블슈팅을 기록한다.
들어가며
앱 Duo를 개발하면서 겪은 배포 트러블슈팅을 기록한다.
Flutter로 iOS/Android 앱을 만들고, Spring Boot 백엔드를 Docker로 VPS에 올리는 구조였다. 윈도우 환경이라 Xcode 없이 Codemagic으로 iOS 빌드를 처리했고, 소셜 로그인은 카카오 · 구글 · 애플 세 가지를 지원했다.
Android는 멀쩡히 잘 됐는데 iOS만 소셜 로그인이 전부 막혀있었다.
원인을 파고들다 보니 서버 .env 변수 누락, 각 플랫폼 콘솔 미설정, Firebase 미등록까지
한꺼번에 터져있는 상황이었다. 하나씩 잡은 과정을 아래에 정리한다.
목차
- 서버 기동 실패 - 환경변수 누락
- iOS 소셜 로그인 전체 실패
- 카카오 로그인 수정
- 구글 로그인 수정
- 애플 로그인 수정
- Firebase iOS 앱 등록
- .env 파싱 오류
- 최종 체크리스트
1. 서버 기동 실패 - 환경변수 누락
증상
BeanCreationException: Error creating bean with name 'webhookController'
Caused by: PlaceholderResolutionException:
Could not resolve placeholder 'revenuecat.webhook.secret'
Spring Boot 앱이 시작조차 되지 않음.
원인
.env 파일에 REVENUECAT_WEBHOOK_SECRET 변수가 누락된 상태로 배포됨.
Spring Boot는 @Value("${revenuecat.webhook.secret}") 주입 실패 시 컨텍스트 초기화를 중단함.
해결
# .env에 추가
REVENUECAT_WEBHOOK_SECRET=your_secret_here
docker compose down
docker compose up -d
docker logs -f duo-api
교훈
배포 전 .env.example 파일을 관리해서 필요한 환경변수 목록을 문서화해둘 것.
2. iOS 소셜 로그인 전체 실패
증상
{error: invalid_request, error_description: IOS bundleId validation failed.}
- iOS: 카카오 / 구글 / 애플 로그인 모두 실패
- Android: 정상 동작
원인 분석
| 항목 | 상태 |
|---|---|
.env iOS Bundle ID 변수 | 누락 |
| 카카오 개발자 콘솔 iOS 등록 | 미등록 |
| Google Cloud Console iOS 클라이언트 | 미생성 |
| Apple Sign In with Apple 키 | 미생성 |
Bundle ID 확인
Codemagic → 앱 선택 → iOS code signing → Bundle identifier에서 확인.
com.misnawk.duo
.env에 추가
KAKAO_IOS_BUNDLE_ID=com.misnawk.duo
APPLE_BUNDLE_ID=com.misnawk.duo
3. 카카오 로그인 수정
원인
카카오 개발자 콘솔의 네이티브 앱 키에 iOS 정보가 등록되지 않음.
Android 패키지/키 해시만 등록된 상태였음.
해결
developers.kakao.com
→ 앱 설정 → 앱 → 플랫폼 키
→ 네이티브 앱 키 "duo" → ⋮ → 수정
→ iOS Bundle ID: com.misnawk.duo 입력 → 저장
4. 구글 로그인 수정
원인
Google Cloud Console에 iOS용 OAuth 2.0 클라이언트가 생성되지 않음.
기존 Info.plist의 URL Scheme 값이 잘못된 상태였음.
해결 1 - Google Cloud Console iOS 클라이언트 생성
console.cloud.google.com
→ APIs & Services → Credentials
→ + CREATE CREDENTIALS → OAuth client ID
→ Application type: iOS
→ Bundle ID: com.misnawk.duo
→ 생성
해결 2 - Firebase에서 GoogleService-Info.plist 다운로드
Google Cloud Console이 아닌 Firebase Console에서 받아야 전체 항목이 포함됨.
console.firebase.google.com
→ 프로젝트 설정 → 내 앱
→ iOS 앱 추가 (com.misnawk.duo)
→ GoogleService-Info.plist 다운로드
→ ios/Runner/ 에 교체
해결 3 - Info.plist URL Scheme 교체
<key>CFBundleURLSchemes</key>
<array>
<!-- Firebase plist의 REVERSED_CLIENT_ID 값으로 교체 -->
<string>com.googleusercontent.apps.903473547061-7q4iqnldv35ktmsql2ri8i7pv8b9qvuv</string>
<!-- 카카오 그대로 유지 -->
<string>kakao9c38d5f22cd49e39d0511d0b0da8cf2d</string>
</array>
⚠️ Google Cloud Console에서 별도로 만든 클라이언트 ID와 Firebase의 REVERSED_CLIENT_ID는 다를 수 있음. Firebase 기준으로 통일할 것.
5. 애플 로그인 수정
원인
Apple Developer Console에 Sign In with Apple 키가 생성되지 않음.
서버 .env에 Apple 관련 변수 전체 누락.
해결 1 - Apple Developer Console 키 생성
developer.apple.com
→ Certificates, Identifiers & Profiles → Keys
→ + 버튼
→ Key Name: DuoSignInKey
→ Sign In with Apple ✅ 체크
→ Configure → Primary App ID: com.misnawk.duo
→ Continue → Register
→ .p8 파일 다운로드 (1회만 가능, 즉시 저장)
→ Key ID 메모
해결 2 - Team ID 확인
developer.apple.com
→ 우측 상단 계정 클릭
→ Membership details → Team ID (10자리)
해결 3 - .env에 추가
APPLE_BUNDLE_ID=com.misnawk.duo
APPLE_TEAM_ID=XXXXXXXXXX
APPLE_KEY_ID=XXXXXXXXXX
APPLE_PRIVATE_KEY="-----BEGIN PRIVATE KEY-----\n내용\n-----END PRIVATE KEY-----"
6. Firebase iOS 앱 등록
문제
Firebase 프로젝트에 Android 앱(com.company.duo)만 등록되어 있고 iOS 앱이 없었음.
해결
console.firebase.google.com → 프로젝트 설정
→ 내 앱 → 앱 추가 → iOS 아이콘
→ Bundle ID: com.misnawk.duo 입력
→ GoogleService-Info.plist 다운로드
→ ios/Runner/GoogleService-Info.plist 교체
→ git push → Codemagic 빌드
7. .env 파싱 오류
증상
failed to read /opt/duo-api/.env: line 35:
unexpected character "/" in variable name "MIGTAgEAMBMGByqGSM49..."
원인
.p8 Private Key를 .env에 멀티라인으로 그대로 붙여넣으면 Docker Compose가 파싱 실패함.
해결
줄바꿈을 \n으로 교체하고 전체를 큰따옴표로 감쌀 것.
# 잘못된 방법
APPLE_PRIVATE_KEY=-----BEGIN PRIVATE KEY-----
MIGTAgEA...
-----END PRIVATE KEY-----
# 올바른 방법
APPLE_PRIVATE_KEY="-----BEGIN PRIVATE KEY-----\nMIGTAgEA...\n-----END PRIVATE KEY-----"
PowerShell로 변환:
(Get-Content "AuthKey_XXXXXXXXXX.p8" -Raw).Replace("`r`n", "\n").Replace("`n", "\n")
8. 최종 체크리스트
.env 필수 변수 목록
# DB
DB_USERNAME=
DB_PASSWORD=
DB_NAME=duo
# 카카오
KAKAO_IOS_BUNDLE_ID=com.misnawk.duo
# 구글
GOOGLE_WEB_CLIENT_ID=
# 애플
APPLE_BUNDLE_ID=com.misnawk.duo
APPLE_TEAM_ID=
APPLE_KEY_ID=
APPLE_PRIVATE_KEY=""
# RevenueCat
REVENUECAT_WEBHOOK_SECRET=
# 기타
JWT_SECRET=
PORT=7070
플랫폼별 설정 파일 위치
| 파일 | 위치 | 용도 |
|---|---|---|
GoogleService-Info.plist | ios/Runner/ | iOS 구글 로그인 |
google-services.json | android/app/ | Android 구글 로그인 |
Info.plist | ios/Runner/ | URL Scheme 등록 |
.env | 서버 루트 | 서버 환경변수 |
docker-compose.yml 권장 설정 (healthcheck 포함)
db:
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${DB_USERNAME} -d ${DB_NAME:-duo}"]
interval: 10s
timeout: 5s
retries: 5
api:
depends_on:
db:
condition: service_healthy