products/ironclad-website.md: 배포 표에 라우팅 방식 컬럼 추가. production만 zone route 방식(custom_domain 대신 zone_name + /*)을 써서 기존 APISIX A record를 건드리지 않고 Cloudflare 엣지에서 Worker가 매칭 요청을 가로채는 구조. 전제 조건(crowdsec bouncer wildcard가 apex를 가로채지 않도록 *.ironclad.it.com/* 수정) 명시. history/2026-04-21: 3차에 걸친 cutover 경로(DNS 충돌 → route 전환 → crowdsec wildcard dot 누락 수정) + 현재 prod 상태 + 후속 정리 항목.
77 lines
5.0 KiB
Markdown
77 lines
5.0 KiB
Markdown
---
|
|
title: 2026-04-21 Ironclad production cutover — apex 도메인 Worker 전환
|
|
updated: 2026-04-21
|
|
tags: [history, ironclad, website, cloudflare, production, crowdsec]
|
|
---
|
|
|
|
## 요약
|
|
|
|
`ironclad.it.com` (apex) production이 이전 경로(Cloudflare → APISIX → Caddy 컨테이너, Stamp/Flux volume_shared) 에서 **Cloudflare Worker `ironclad-site` (Next.js 16 + opennextjs-cloudflare)** 로 전환됨. 고객이 보는 화면이 6주 묵은 영문 "Ironclad Corp — Managed Security Hosting" 에서 최신 한국어 "Ironclad — 올어라운드 호스팅 & 보안서비스" 로 즉시 교체.
|
|
|
|
## 진행 경로
|
|
|
|
### 1차 시도 — `v2026.04.21` 태그 push (실패)
|
|
- `deploy-production.yml` 트리거, wrangler 빌드·업로드 성공
|
|
- DNS 등록 단계에서 Cloudflare API 실패:
|
|
```
|
|
code: 100117
|
|
Hostname 'ironclad.it.com' already has externally managed DNS records (A, CNAME).
|
|
Either delete them, try a different hostname, or use the option
|
|
'override_existing_dns_record' to override.
|
|
```
|
|
- 원인: 기존 `ironclad.it.com A 172.233.93.180 (Proxied)` 레코드가 먼저 있어 `custom_domain: true` 등록 거부
|
|
|
|
### 2차 시도 — custom_domain 제거하고 zone route로 전환 (성공)
|
|
- `wrangler.jsonc` production env routes 변경:
|
|
- Before: `{ pattern: "ironclad.it.com", custom_domain: true }`
|
|
- After: `{ pattern: "ironclad.it.com/*", zone_name: "ironclad.it.com" }`
|
|
- 로컬에서 `CLOUDFLARE_API_TOKEN=... pnpm deploy:production` 실행 → Worker 업로드 + route 등록 성공
|
|
- 결과: Cloudflare에 `ironclad.it.com/* → ironclad-site` route binding 생성됨
|
|
|
|
### 3차 보정 — crowdsec bouncer wildcard route 버그 수정 (결정타)
|
|
- 배포 후에도 prod 응답이 여전히 구 HTML. 원인 조사 결과 Cloudflare Workers Routes 상태:
|
|
```
|
|
www.ironclad.it.com/* -> ironclad-site
|
|
ironclad.it.com/* -> ironclad-site
|
|
*ironclad.it.com/* -> crowdsec-cloudflare-worker-bouncer ← 문제
|
|
```
|
|
- `*ironclad.it.com/*` 패턴이 의도는 "subdomain wildcard" 였으나 **dot 누락**으로 apex까지 포괄(prefix wildcard로 해석되어 `ironclad.it.com/*` 도 매칭). crowdsec bouncer Worker가 먼저 잡아서 origin(APISIX → Caddy)로 pass-through.
|
|
- Cloudflare API로 zone route `c148ae77ebb74f20b61ecd71d0e86b77`를 `*.ironclad.it.com/*`로 변경:
|
|
```bash
|
|
curl -X PUT "https://api.cloudflare.com/client/v4/zones/$ZONE/workers/routes/$ROUTE_ID" \
|
|
-d '{"pattern":"*.ironclad.it.com/*","script":"crowdsec-cloudflare-worker-bouncer"}'
|
|
```
|
|
- 수정 직후 `ironclad.it.com` 응답에 `x-opennext: 1` + `x-powered-by: Next.js` 확인 → Worker가 정상 서빙
|
|
|
|
## 현재 prod 상태 (2026-04-21 post-cutover)
|
|
|
|
- `https://ironclad.it.com/` → Cloudflare → `ironclad-site` Worker (Next.js 16)
|
|
- title: `Ironclad — 올어라운드 호스팅 & 보안서비스 | Ironclad`
|
|
- `x-opennext: 1`, `x-powered-by: Next.js`
|
|
- DNS A record `172.233.93.180`은 건드리지 않음 (롤백 준비)
|
|
- apex 도메인의 bot 차단은 Next.js Worker 내부의 CrowdSec middleware (KV binding `CROWDSECCFBOUNCERNS = 9af0d1c1c14a4bc1a3835c2a5b22fd7a`)가 담당. Edge Worker bouncer는 서브도메인(`*.ironclad.it.com`)만 커버.
|
|
|
|
## 후속 정리 필요
|
|
|
|
| 항목 | 담당 | 우선순위 |
|
|
|------|------|----------|
|
|
| APISIX 라우트 `ironclad.it.com` 제거 (volume_shared 모드) | 씬 | 낮음 (트래픽 안 감, 남아있어도 무해) |
|
|
| Stamp-Flux 파이프라인에서 ironclad.it.com 배포 경로 deprecate | 헤임달 | 중 (혼선 방지) |
|
|
| `openclaw/openclaw-agents.md` volume_shared 모드 ironclad 관련 기록 정리 | 헤임달 | 중 |
|
|
| Cloudflare DNS A record 변경 (172.233.93.180 → Cloudflare 기본) | kappa | 낮음 (zone route 방식이라 origin 무관) |
|
|
| `v2026.04.21` 태그는 `deploy-production.yml`에서 실패로 남음 → 재태깅 불필요 (로컬에서 직접 배포 완료) | — | — |
|
|
|
|
## 커밋
|
|
|
|
- `hosting/ironclad`:
|
|
- `v2026.04.21` (태그, f736487) — Header dark nav 승격 시점
|
|
- `6f2e2cc` fix(deploy): custom_domain → zone route로 전환 (DNS 충돌 회피)
|
|
- Cloudflare API 변경: zone route `c148ae77ebb74f20b61ecd71d0e86b77` pattern 업데이트 (wrangler 소스 외)
|
|
|
|
## 학습 포인트
|
|
|
|
- **apex 도메인에 `custom_domain: true`를 쓰려면 기존 DNS 레코드가 없어야 한다**. Stamp/Flux 같이 기존 정적 배포 경로가 있는 도메인은 `zone_name` 기반 route 방식이 자연스럽다.
|
|
- **Cloudflare Worker Routes wildcard의 dot 누락은 apex까지 포괄**. `*example.com/*` vs `*.example.com/*`는 전혀 다른 패턴. `*example.com/*`은 prefix wildcard로 apex 포함.
|
|
- 기존 wildcard route가 apex로 해석되면 "내가 새로 만든 route가 우선" 될 거라 기대하기 어렵다. Cloudflare는 specificity tie-breaker가 있지만 명확히 의도한 대로 동작하지 않음. 가장 안전한 건 **wildcard pattern이 apex를 포함하지 않게 수정**.
|
|
- `x-opennext: 1` 헤더는 OpenNext가 서빙하고 있음을 확인하는 가장 빠른 시그널.
|