본문으로 건너뛰기

커스텀 도메인 화이트 라벨 라우팅 사고

이 회고에서는 2026년 7월 12일 커스텀 도메인 라우팅 사건을 다룹니다. 핵심 불변성은 간단했습니다. 테넌트 화이트 라벨 도메인은 정식 lumie-edu.com 마케팅 콘텐츠를 렌더링해서는 안 됩니다. 원래 미들웨어 경로는 커스텀 도메인 확인 시간이 초과되거나 null를 반환할 때마다 해당 불변성을 위반했습니다.

테넌트 경로 누출을 완전히 제거한 호스트 기반 후속 조치는 Host-Native Custom Domain Routing에 문서화되어 있습니다.

컨텍스트

Lumie는 두 가지 URL 모델을 통해 동일한 테넌트 랜딩을 제공합니다.

  • https://lumie-edu.com/joossameng와 같은 정식 호스트와 테넌트 경로
  • https://joossameng.com/와 같은 테넌트 소유 호스트.

라우팅 결정은 프런트엔드에 있습니다.

  • lumie-frontend/proxy.ts
  • lumie-frontend/src/shared/lib/customDomain.ts

초기 커스텀 도메인 경로는 런타임 테넌트 조회에 의존했습니다. 조회가 누락되면 요청은 호스트 경계에서 멈추지 않고 일반 공개 경로를 따라 계속될 수 있었습니다.

무엇이 깨졌거나 변경되었는지

사건은 다음과 같이 단계적으로 진행되었습니다.

  • https://joossameng.com/는 정식 Lumie 랜딩 페이지를 거의 표시하지 않습니다.
  • 첫 번째 수정은 더 안전했지만 여전히 런타임 조회에 너무 의존했습니다. 해석 실패 시 503Cache-Control: no-store를 반환하도록 바꿨지만, 닫힌 상태로 실패하는 모델이 완성된 것은 아니었습니다.
  • 유효한 인증 및 앱 URL은 커스텀 도메인 허용 목록, 특히 /auth/refresh?returnTo=%2Fadmin/${customId}?auth=login에서 공백을 드러냈습니다.
  • 디버깅 시간의 한 부분은 배포 상태 모호성이었습니다. 프로덕션이 새 이미지를 출시하기 전에 허용 목록 수정 사항이 git에 존재했습니다.

근본 원인

확인된 근본 원인은 프런트엔드 프록시의 페일오픈 라우팅 결정이었습니다.

lumie-frontend/src/shared/lib/customDomain.ts는 여전히 당시의 주요 구성 요소를 보여줍니다.

  • CUSTOM_DOMAIN_TENANT_MAP를 사용하여 호스트-테넌트 매핑을 구성했습니다.
  • resolveCustomDomainTenant(host)를 통한 대체 런타임 조회
  • CUSTOM_DOMAIN_RESOLVE_TIMEOUT_MS를 통한 제한된 조회 시간 초과.

지속 가능한 교훈은 "시간 초과를 늘리는 것"이 아니었습니다. "해결되지 않은 커스텀 도메인 호스트가 표준 공개 경로를 통과하지 못하게 하십시오."였습니다.

해결

최종 디자인은 현재 저장소 상태에서 볼 수 있습니다.

결정적 호스트 매핑

lumie-infra/applications/lumie/frontend/common-values.yaml 세트:

  • CUSTOM_DOMAIN_RESOLUTION_ENABLED
  • CUSTOM_DOMAIN_RESOLVE_TIMEOUT_MS
  • CUSTOM_DOMAIN_TENANT_MAP

이는 대체 조회를 고려하기도 전에 운영자 관리 커스텀 도메인을 결정적으로 만듭니다.

실패 시 닫힘 프록시 동작

현재 lumie-frontend/proxy.ts:

  • 전달하기 전에 스푸핑 가능한 테넌트 및 사용자 헤더를 제거합니다.
  • 신뢰할 수 있는 테넌트 헤더를 사용하여 구성된 커스텀 도메인 루트 요청을 전달합니다.
  • 구성된 커스텀 도메인에서 /api/*, /auth/refresh, /admin*/dashboard*를 허용합니다.
  • /login, /register/signup를 루트 쿼리 기반 인증 URL로 리디렉션합니다.
  • 구성된 커스텀 도메인에 존재해서는 안 되는 정식 마케팅 또는 테넌트 경로 경로에 대해 404를 반환합니다.
  • 해결되지 않은 부트스트랩 요청에 대해 정식 Lumie 콘텐츠를 제공하는 대신 503를 반환합니다.

라우팅 경계에 대한 테스트 적용 범위

라우팅 불변성은 다음 위치에 고정되어 있습니다.

  • lumie-frontend/src/shared/lib/middlewareCustomDomain.test.ts
  • lumie-frontend/src/shared/lib/apiProxyCustomDomain.test.ts
  • lumie-frontend/src/shared/lib/apiProxyRoute.test.ts

이러한 테스트는 장애 시 닫힌 루트 처리, 신뢰할 수 있는 헤더 삽입, 정식 페이지 유출에 대한 404, 구성된 도메인에서 허용된 인증 새로 고침 흐름 등 사고 중에 실패한 특정 동작을 다룹니다.

예방

  • 호스트 자체를 화이트 라벨 도메인의 보안 및 브랜드 경계로 취급합니다.
  • 운영자 관리 커스텀 도메인에는 구성된 호스트 맵을 우선 사용합니다. 도메인별 런타임 조회는 핫패스의 기준이 아니라 전환용 폴백으로 유지합니다.
  • 커스텀 도메인 요청을 안전하게 해결할 수 없을 때마다 no-store 응답으로 실패 처리됩니다.
  • 라우팅 수정이 미들웨어 동작에 따라 달라지는 경우 병합 코드뿐만 아니라 프로덕션 이미지 롤아웃을 확인합니다.