Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
95 lines
13 KiB
Markdown
95 lines
13 KiB
Markdown
# 도메인 구매·DNS 관리 자동화 — 공급자 모듈 (v1.5.36, v1.6.32 Route 53 Domains 추가, v1.6.35 사용자 프로세스)
|
||
|
||
AI Webmaker v1.5.36 · 2026-10-16 · 대상: 운영자
|
||
|
||
## 1. 구성
|
||
|
||
| 역할 | 공급자 | 모듈 | 접속 정보(보관소 종류) |
|
||
|---|---|---|---|
|
||
| 도메인 등록 업체(검색·구매·갱신·네임서버) | Openprovider | `lib/registrars/openprovider.js` | `openprovider` (USERNAME 설정 + 비밀번호) |
|
||
| | Porkbun | `lib/registrars/porkbun.js` | `porkbun` (API_KEY 설정 + Secret API Key) |
|
||
| | Amazon Route 53 Domains (v1.6.32) | `lib/registrars/route53.js` (+ `lib/awsv4.js`) | `route53` (DNS 와 같은 키 — IAM 에 `route53domains:*` 권한 추가 필요, 아래 2-1) |
|
||
| DNS 공급자(영역·레코드·MX·ACME TXT·이전 영역) | Openprovider DNS | `lib/dns/openprovider.js` | `openprovider` |
|
||
| | Porkbun DNS | `lib/dns/porkbun.js` | `porkbun` |
|
||
| | Amazon Route 53 | `lib/dns/route53.js` (+ `lib/awsv4.js` 서명) | `route53` (ACCESS_KEY_ID 설정 + Secret Access Key, 선택 SESSION_TOKEN·REGION) |
|
||
| | Google Cloud DNS | `lib/dns/gcloud.js` (+ `lib/google.js` 토큰) | `gcloud-dns` (서비스 계정 키 JSON, roles/dns.admin; PROJECT 설정은 키의 project_id 와 다를 때만) |
|
||
|
||
공통 창구: `lib/registrar.js`(등록 업체), `lib/dnszone.js`(DNS). 기존 코드(`lib/domains.js` 구매·레코드·메일 MX, `lib/ssl.js`·`scripts/acme-dns-hook.js` 와일드카드 인증서 TXT)는 모두 창구를 거친다. API 키 등 접속 정보는 **나중에** 관리자 콘솔 › 설정 › 외부 연동 접속 정보에 넣으면 되고, 넣기 전에는 "준비되지 않음" 으로 보인다.
|
||
|
||
## 2. 설정
|
||
|
||
- 관리자 콘솔 › 설정 › **도메인 서비스**: 플랫폼 도메인 · **DNS 공급자**(수동 / Openprovider / Porkbun / Route 53 / Google Cloud DNS) · **등록 업체**(Openprovider / Porkbun / Amazon Route 53 — v1.6.32). 저장값 `settings.domains.dnsProvider`, `settings.domains.registrar` (1.5.31 까지의 `platformDns` 는 호환용으로 함께 유지).
|
||
- 접속 정보: 설정 › 외부 연동 접속 정보에서 종류를 고르고 저장 → "연결 확인" 이 실제 목록 호출(영역·도메인 목록)로 검사한다.
|
||
- 명령줄: `node scripts/config.js` 는 설정 파일용이며 도메인 설정은 관리자 설정(`data/settings.json`)이다.
|
||
|
||
### 2-1. Amazon Route 53 로 도메인 등록 (v1.6.32)
|
||
|
||
- 접속 정보는 DNS 와 같은 보관소 항목 `route53` 을 쓴다(ACCESS_KEY_ID 설정 + Secret Access Key). 등록 업체로 쓰려면 그 IAM 사용자에 Route 53 **Domains** 권한을 더한다:
|
||
`route53domains:CheckDomainAvailability` · `ListPrices` · `RegisterDomain` · `GetOperationDetail` · `GetDomainDetail` · `ListDomains` · `RenewDomain` · `UpdateDomainNameservers`.
|
||
보관소의 "연결 확인" 이 호스팅 영역 수와 함께 "등록 도메인 N개(Route 53 Domains 사용 가능)" 또는 "도메인 등록은 불가: …(권한 오류)" 를 보여 준다.
|
||
- 관리자 콘솔 › 설정 › 도메인 서비스 › **등록 업체** 에서 "Amazon Route 53" 을 고른다. 가격은 USD(ListPrices) × 요율. 등록자 정보는 사용자가 도메인 탭에 저장한 것을 RegisterDomain 에 그대로 넣는다(AWS 에는 고객 핸들이 없음; WHOIS 개인정보 보호 켬; 전화는 `+82.1012345678` 형식으로 바꿈).
|
||
- **비동기 등록**: AWS 는 등록 요청을 접수(OperationId)하고 뒤에서 처리한다(보통 몇 분, 등록자 이메일 확인이 필요하면 더 오래). 구매는 최대 60초 완료를 기다린 뒤 끝나지 않으면 도메인 상태 **PENDING** 으로 기록하고 차감한다(요청은 AWS 에 접수된 상태). 이후 사용자가 도메인 탭을 열 때(`propagation`)와 관리자 운영 복구 "등록 상태 확인" 이 `finalizeRegistration` 으로 완료를 확인해 만료일을 채우고 DNS 영역(@·www A)·네임서버를 맞춘다. AWS 가 ERROR/FAILED 로 끝내면 상태 FAILED 로 운영 복구에 "관리자 확인 필요" 로 남는다(비용 환불은 회원·청구에서).
|
||
- Route 53 Domains 는 등록 완료 때 같은 이름의 호스팅 영역을 **스스로 만든다**. DNS 공급자도 Route 53 이면 `createZone` 이 같은 이름의 영역을 재사용하므로 영역이 둘 생기지 않는다. DNS 공급자가 다른 업체면 그 영역의 네임서버를 `UpdateDomainNameservers` 로 지정한다(AWS 가 만든 영역은 비어 있는 채 남으며 월 요금이 붙으니 AWS 콘솔에서 지워도 된다).
|
||
- 지원하지 않는 확장자(.kr 등)는 ListPrices 가 비어 "Route 53 는 .kr 도메인을 등록하지 않습니다" 로 안내한다. 프리미엄·예약 이름은 등록 불가로 표시된다.
|
||
- 엔드포인트는 `route53domains.us-east-1.amazonaws.com` 하나(글로벌). 시험용 대체 주소 `ROUTE53DOMAINS_API_BASE`(모의 서버 검증 `test/registrar-route53.test.js`).
|
||
|
||
## 3. 동작
|
||
|
||
| 기능 | 흐름 |
|
||
|---|---|
|
||
| 검색·견적 | 등록 업체 `check/price` → 요율(기본 250%) 적용 원화 견적 |
|
||
| 구매 | 등록 업체 `createDomain` → 캐시 차감 → DNS 공급자에 영역(@·www A 레코드) 생성 → 공급자가 등록 업체와 다르면 등록 업체에 **네임서버 지정**(예: Porkbun 등록 + Route 53 DNS). 도메인 기록에 `registrar`·`dnsProvider`·`nameServers` 저장 |
|
||
| 레코드 | 구입 도메인: 그 도메인의 DNS 공급자 영역에서만, 영역 기준 상대 이름으로만. 서브 도메인: 플랫폼 영역 공급자가 있을 때 자기 이름 아래만 |
|
||
| 메일(MX·SPF·DMARC·Resend) | `setupMail` 이 공급자 창구로 레코드 추가 (수동이면 안내) |
|
||
| 와일드카드 SSL(DNS-01) | `lib/ssl.js` 가 플랫폼 도메인의 공급자 id 를 훅에 넘기고, 훅이 `_acme-challenge` TXT 를 넣고 지운다 |
|
||
| 영역 관리(관리자) | (v1.6.33: 1.5.36~1.6.32 는 API 경로 누락으로 이 화면의 모든 호출이 "not found" 였음 — 수정됨. "이전된 영역 받기" 는 NS 조회로 영역 상태를 먼저 확인해 미등록/위임 없음/네임서버 무응답은 원인과 함께 실패, 레코드가 없으면 "zone 파일 구성을 찾을 수 없습니다" + 빈 영역) 설정 › 도메인 서비스 › **DNS 영역 관리**: 목록·만들기·**이전된 영역 받기**(공용 DNS 에 보이는 A·AAAA·CNAME·MX·TXT 를 읽어 새 영역에 복사, 네임서버 안내)·레코드 보기/추가/삭제·지우기 |
|
||
|
||
## 4. 보안 (여러 도메인·여러 사용자)
|
||
|
||
- 접속 정보는 관리자만 넣고 보관소에 암호화된다. 사용자 API 응답에는 키·영역 id 가 나가지 않는다.
|
||
- 사용자는 `getOwned`(자기 소유 도메인)와 계정 종류(자체 도메인 계정) 검사를 거쳐서만 레코드를 만지고, 레코드 이름은 영역 기준 상대 이름이라 다른 영역·상위 이름을 건드릴 수 없다. 서브 도메인 계정은 DNS 를 직접 만지지 못한다.
|
||
- 도메인 이름은 서비스 전체에서 하나(`byName`)라 다른 사용자가 등록한 이름을 다시 등록하거나 가로챌 수 없다.
|
||
- 관리자 영역 API(`/api/admin/dns/*`)는 관리자 세션만, 회원이 쓰는 도메인의 영역 삭제는 `force=1` 확인이 있어야 한다. 모든 변경은 `data/dns-audit.json`(누가·언제·공급자·영역·레코드)에 남고 화면의 "DNS 감사 기록" 에 보인다.
|
||
|
||
## 5. 관리자 API
|
||
|
||
```
|
||
GET /api/admin/dns 공급자 목록·준비 여부, 감사 기록, 전체 도메인
|
||
GET /api/admin/dns/zones?provider=route53 영역 목록
|
||
POST /api/admin/dns/zones {domain, provider, import?} 영역 만들기 / 이전된 영역 받기
|
||
DELETE /api/admin/dns/zones/<domain>?provider=&force=1
|
||
GET /api/admin/dns/records/<domain>?provider=
|
||
POST /api/admin/dns/records/<domain> {records:[{name,type,value,ttl,prio}]}
|
||
DELETE /api/admin/dns/records/<domain> {records:[…]}
|
||
POST /api/admin/dns/domains/<id> {dnsProvider} 도메인별 DNS 공급자 지정
|
||
```
|
||
|
||
## 6. 검증과 한계
|
||
|
||
- 공급자 클라이언트는 모의 API 서버(Route 53 XML · Cloud DNS JSON · Porkbun JSON)로 영역 생성·레코드 추가/삭제/교체·영역 삭제·네임서버·등록 흐름을 검사했고, SigV4 서명은 AWS 공식 예제 서명값과 일치한다. 실제 계정으로는 접속 정보를 넣은 뒤 "연결 확인" 과 작은 영역으로 먼저 시험한다.
|
||
- Porkbun 의 도메인 등록·갱신 API(`domain/create`·`domain/renew`)는 계정에 API 등록 권한이 켜져 있어야 하며, 응답이 다르면 그 메시지를 그대로 안내한다. 등록자 정보는 Porkbun 계정의 기본 연락처를 쓴다.
|
||
- 시험용 대체 주소: `ROUTE53DOMAINS_API_BASE`(v1.6.32), `ROUTE53_API_BASE`, `GCLOUD_DNS_API_BASE`, `GOOGLE_TOKEN_URL`, `PORKBUN_API_BASE`, `OPENPROVIDER_API_BASE`.
|
||
|
||
## 7. 사용자 도메인 준비 프로세스 (v1.6.35)
|
||
관리자 콘솔은 접속 정보·플랫폼 도메인·서브 도메인 등록 허용 여부·가격 요율만 정한다(설정 › 도메인 서비스). 검색·구매·영역·레코드는 사용자 "도메인" 탭에서 사용자가 한다(`lib/domains.js` "도메인 준비 프로세스" 절).
|
||
|
||
| 단계 | 사용자가 하는 일 | 서버가 하는 일 | API |
|
||
|---|---|---|---|
|
||
| ① 구매 | 검색 → 장바구니에 담기 → 장바구니에서 구매 | 가격(요율 적용)·등록 가능 여부를 담을 때와 열 때 다시 확인, 구매 시 금액 재확인(409) | `POST /api/domains/search`, `GET/POST/DELETE /api/domains/cart`, `POST /api/domains/purchase` |
|
||
| ② 네임서버 이전 | 도메인·쓰는 하위 이름 입력, "이미 구매했습니다" 확인 → 네임서버 변경 → "네임서버 변경했습니다" | NS/SOA 로 생존 확인 → 공용 DNS 레코드를 읽어 공급자에 영역 생성 → 네임서버 안내 → NS 집합 비교로 완료 판정. 완료 전 `pending.kind='transfer'`(레코드 수정 409) | `POST /api/domains/external {mode:'ns'}`, `POST /api/domains/<id>/transfer-check {confirmed}` |
|
||
| ③ 직접 DNS 관리 | 도메인 입력, "이미 구매했습니다" 확인 → 안내된 레코드를 자기 DNS 에 넣음 → "설정 완료 — 확인" | 필요한 레코드(A @·www, 선택 시 MX·SPF·DMARC·DKIM) 계산 → 공용 DNS 조회로 레코드별 확인 → `manual.siteOk/mailOk` 기록 | `GET /api/domains/<id>/required`, `POST /api/domains/<id>/verify` |
|
||
| ④ 자동 설정 | 사이트에 연결 → 발행 → 메일(MX) 자동 설정 → "도메인 상태" | ns 도메인은 영역의 @·www A 를 사이트 IP 로 교체(`setRecords`), 발행 때 vhost·SSL, 상태는 소유→DNS→A→배포 단계→메일 로 판정 | `POST /api/domains/<id>/connect`, `POST /api/domains/<id>/mail`, `GET /api/domains/<id>/status` |
|
||
|
||
- 도메인 기록 type: `subdomain` · `registered`(구매) · `external`(mode `ns` | `manual`). `external/ns` 는 `registered` 와 같은 영역 관리(레코드 추가·삭제·메일 자동)를 받는다.
|
||
- 등록 업체 이전(registrar transfer)은 지원하지 않는다 — 화면에 명시. `quote(operation:'transfer')` 는 가격 조회만 남아 있다.
|
||
- 영역을 먼저 만드는 이유: 공급자(Route 53 등)는 영역을 만든 뒤에야 그 영역의 네임서버를 알려 준다. 네임서버가 바뀌기 전까지 새 영역은 공용 DNS 에 보이지 않으므로, 옮긴 레코드는 전파 뒤 그대로 살아난다.
|
||
- 관리자 "DNS 영역 현황" 은 조회·정리(쓰지 않는 영역 삭제)만 한다. 관리자 API `/api/admin/dns/zones POST`(만들기·import)는 호환을 위해 남아 있지만 화면에서는 쓰지 않는다.
|
||
|
||
## 8. 네임서버 정보 · DNS 레코드 정보 팝업 (v1.6.38, 요구 3)
|
||
|
||
직접 산 도메인(네임서버 이전·직접 DNS 관리)은 사용자가 등록 업체에서 네임서버를 바꾸거나 그 업체의 DNS 레코드를 직접 넣어야 한다. 도메인 탭 "내 도메인" 항목의 안내 줄이 어느 버튼을 누르는지 먼저 말하고, 상세는 팝업으로 보인다.
|
||
|
||
- **네임서버 정보**: 등록 업체에서 "네임서버 설정"(DNS 레코드 관리가 아님)을 열어 사용자 네임서버로 바꾸는 단계, 네임서버 표(값 클릭 전체 선택·복사 버튼·전체 복사), 지금 네임서버, DNS 공급자 이름. 직접 DNS 관리 도메인에는 네임서버 이전으로 바꾸는 순서(해제 → 네임서버 이전 등록)를 안내한다 — Route 53 등은 영역을 만들 때 네임서버가 정해지기 때문.
|
||
- **DNS 레코드 정보**: "DNS 레코드 관리" 를 여는 단계, 사이트용(A @·www) · 메일용 MX(우선순위 안내) · 메일용 TXT(SPF·DMARC) · 보내기 인증(DKIM 등) 표. 이름·값·우선순위를 클릭하면 전체 선택(Ctrl-C), "복사" 버튼, 묶음별·전체 복사(탭 구분). 데이터는 `GET /api/domains/<id>/required?siteId=&mail=1`.
|
||
- 값 복사는 https 에서 클립보드 API 로 동작하고, 막히면 "직접 선택해 Ctrl-C" 로 바뀐다.
|