Framer 사이트 하나를 여러 브랜드 도메인 루트로 보여주기
회사에서 관리하는 공식 홈페이지는 Framer로 만들어져 있고, 그 안에 여러 프로덕트 섹션이 경로로 분리되어 있습니다. 예를 들어 www.cplat.io/pallang, www.cplat.io/pointingai 같은 식입니다.
그러다 마케팅에서 요청이 들어왔습니다.
"팔랑 브랜드 도메인을 따로 샀거든.
pallang.io만 치면 팔랑 페이지가 바로 뜨도록 해 줘."
말은 쉽습니다. 근데 Framer는 도메인 하나당 사이트 하나가 기본입니다. 한 Framer 사이트 안의 특정 경로만 떼어서 다른 도메인 루트에 매달려면 손을 좀 써야 합니다.

간단한 대안들은 왜 탈락했나
제일 먼저 떠오르는 옵션들입니다.
1) Framer에서 pallang.io를 해당 페이지에 직접 매핑
Framer는 "한 도메인 = 한 사이트" 가 원칙입니다. 같은 Framer 계정의 특정 서브페이지만 따로 다른 도메인의 루트로 노출시키는 옵션은 제공되지 않습니다. 이걸 하려면 팔랑 페이지를 별도 Framer 사이트로 분리해야 하는데, 마케팅에서 편집 통합성을 잃고 싶지 않다고 했습니다.
2) 301 리다이렉트
pallang.io 치면 www.cplat.io/pallang 으로 보내면 됩니다. 구현은 한 줄. 근데 문제는 사용자 브라우저 주소창이 cplat.io로 바뀌어 버린다는 점입니다. 브랜드 도메인 산 의미가 없어집니다.
3) <iframe>으로 감싸기
SEO는 포기해야 하고 모바일 viewport·스크롤 이슈가 따라옵니다. 선택지 자체를 접었습니다.

선택한 접근: CloudFront 리버스 프록시 + path rewrite
투명하게 프록시하되, 주소창은 pallang.io로 유지합니다. 사용자 요청을 CloudFront가 받고, 오리진에는 /pallang 경로로 요청을 전달해서 Framer 사이트의 해당 섹션을 반환합니다.
대략 이런 그림입니다.
주소창은 pallang.io/ 그대로입니다. 응답은 Framer의 /pallang 페이지입니다.
Lambda@Edge가 아닌 CloudFront Functions를 쓴 이유
AWS에서 요청 경로 재작성하는 데 두 가지 옵션이 있습니다.

- Lambda@Edge: Node.js 런타임. 임의 로직·HTTP 호출·무거운 가공 가능. 대신 실행 비용과 콜드 스타트, us-east-1 배포 등 부담이 있습니다.
- CloudFront Functions: JavaScript 서브셋. 실행 시간 1ms 이하, Lambda@Edge 대비 훨씬 저렴. 뷰어 요청 / 응답에서 경량 URL·헤더 재작성만 가능하지만, 이 케이스엔 딱 그 용도입니다.
경로 몇 글자 붙이는 게 전부인데 Lambda@Edge를 쓰는 건 "망치로 파리 잡기"입니다. CloudFront Functions로 갔습니다.
실제 함수 코드
viewer-request 단계에 붙어 있는 rewrite 함수 본문입니다.
세 분기가 다 필요합니다. 그 이유는 다음 섹션에서 설명합니다.
마주친 함정들
1. Trailing slash에서 404가 난다
초기 구현은 아주 단순했습니다. "루트면 /pallang, 아니면 앞에 /pallang 붙이기" 두 분기만. 그런데 pallang.io/notice/ 처럼 끝에 /가 붙는 URL에서 404가 떨어졌습니다.
원인은 오리진인 Framer가 /pallang/notice/ (trailing slash 있음) 와 /pallang/notice (없음) 를 다르게 처리했기 때문입니다. 전자는 "없다", 후자는 실제 페이지입니다. 그래서 세 번째 분기가 들어갔습니다 — trailing slash가 있으면 제거.

2. ACM 인증서는 us-east-1에 발급해야 한다
CloudFront distribution에 커스텀 도메인(Alternate Domain Name, CNAME) 을 붙이면 ACM 인증서가 필요합니다. 함정은 CloudFront는 글로벌 서비스라 인증서를 버지니아 북부(us-east-1)에서 발급한 것만 받는다는 점입니다. 다른 리전에서 만들면 드롭다운에 뜨지도 않습니다.
익숙해지면 당연한 이야기지만, AWS 첫 입문 때 한 번쯤은 헤매는 포인트입니다.
3. HTTPS 강제와 HTTP/2
ViewerProtocolPolicy는 redirect-to-https, Origin protocol도 HTTPS only + TLS 1.2 이상으로 설정했습니다. 그리고 compress: true 켜 놓으면 Framer 원본 gzip 응답이 그대로 전달됩니다.
한 번 만들고 복제 — 다음 브랜드 도메인은 30분
팔랑 세팅이 끝난 뒤, 다음 브랜드 도메인 pointing.ai 도 같은 패턴으로 분리해달라는 요청이 들어왔습니다.

새로 해야 할 작업은 정말 단순했습니다.
- 새 CloudFront distribution — Origin을
www.cplat.io로 동일하게. - 새 CloudFront Function — 문자열만
'/pallang'→'/pointingai'로 바꾼 사본. - ACM 인증서 (us-east-1) 발급·연결.
- Route 53 / 도메인 레지스트라에서 CloudFront 도메인으로 CNAME.
첫 번째 도메인 셋업에서 이미 trailing slash 같은 함정을 다 지나왔기 때문에, 두 번째부터는 말 그대로 복붙 수준이었습니다. 조직 안에 "브랜드 도메인 분리 패턴" 이 생긴 셈입니다.
동작 확인
구성이 제대로 됐는지는 응답 헤더로 바로 보입니다.
via+x-cache+x-amz-cf-pop→ CloudFront를 통과 중server: Framer→ 실제 컨텐츠 소스는 Framer- POP이 서울 엣지(
ICN57)에서 캐시됨 → 레이턴시도 직접 접근과 사실상 동일
그리고 pallang.io/ 의 ETag와 www.cplat.io/pallang 의 ETag가 같으면 "진짜 같은 콘텐츠를 두 경로로 서빙하고 있다" 는 증거가 됩니다. 실제로도 그렇습니다.

언제 이런 패턴이 맞을까
- 에디터(Framer/Webflow/Notion 등)는 하나로 유지하고 싶은데, 특정 섹션만 별도 브랜드 도메인으로 노출하고 싶을 때.
- 풀 마이그레이션 없이 점진적으로 브랜드 도메인을 늘려가야 할 때.
- 리다이렉트로는 안 되는 케이스. 즉 주소창을 브랜드 도메인으로 유지해야 할 때.
반대로 굳이 쓰면 안 되는 케이스:
- 페이지 내부에서 경로 상호 참조(
/other-section) 가 많을 때. 그런 링크는 Framer 시점에선/pallang기준이 아니라 다른 경로를 가리킬 수 있어서 rewrite로 다 못 덮습니다. - 인증·세션이 복잡하게 얽힌 앱. CloudFront Function은 경량 로직만 허용합니다.
마치며
요구사항 자체는 "한 줄" 같아 보였습니다 — "브랜드 도메인으로도 뜨게 해줘". 하지만 플랫폼 제약(Framer의 1-도메인 원칙), 표시 URL 유지(301 탈락), 실제 프록시의 세부(trailing slash) 까지 내려가면 결국 작은 인프라 설계가 됩니다.
CloudFront Functions는 이런 "경량 URL·헤더 재작성" 에 정말 잘 맞는 도구라, 한 번 손에 익히면 다음 번에 비슷한 요구가 와도 반나절 안에 끝납니다. 그 자체로도 좋은 경험이었습니다.
junsobi
2026년 4월 19일