English {#english}
Cloudflare Orchestration and GTape Data Protection Plan
Purpose: Define Cloudflare edge-based dynamic routing and security and a GTape-inspired data protection approach for current Prego (Hetzner, Pulumi, Ansible, Frappe), avoiding K8s operational complexity while achieving similar performance and security.
No code generation — plan, strategy, and application only.
References: saas-unified-architecture-hetzner-cloudflare-zuplo-plan; tenant-subdomain-dns-design (canonical tenant-{short_id}.pregoi.com, approach C); redis-separation-pulumi-ansible-plan §8.4 (health check, visibility).
1. Design principles
KISS & DRY (Workers, Tunnel, R2 instead of K8s; backup in R2). Economical & Efficient. GTape: “recovery reliability” — untested backup is not backup.
2–4. Dynamic routing, Tunnel, backup, application
- §2.1 Workers routing: Hostname → KV lookup → proxy to origin. KV key = tenant canonical (or host), value = server IP or Tunnel URL. Inject X-Frappe-Site-Name. Provisioning/callback writes KV; HA by updating KV on server change.
- §2.2 Tunnel (Gatekeeper): No 80/443 on server; cloudflared outbound-only; traffic only via Cloudflare (WAF, Zero Trust). Aligns with Pulumi firewall (SSH only); Ansible or provisioning installs cloudflared; route tenant-*.pregoi.com to Tunnel.
- §3 GTape-style backup: (1) Soft delete (deleted_at; purge after 30 days). (2) Daily snapshots + MariaDB binlog (PITR). (3) Offsite to R2 (rclone/script), retention policy. (4) DiRT: periodic restore from R2 to separate container and verify.
- §4 Current system: Already: tenant canonical, R2, firewall, binlog, soft delete/purge. To add: Worker + KV, Tunnel on App (and optionally DB), DB backup to R2, DiRT runbook. Architect recommendation: Workers for routing, Tunnel for security, R2 for backup.
5. Deliverables and locations
Worker (tenant-router), KV put script, cloudflared Ansible role, mariadb-backup-to-r2 script + prego-db-backups bucket, dirt-restore-verify script and runbook.
Full tables (§1, §2.1–§2.2, §3.1–§3.4, §4.1–§4.3, §5) and exact wording are in the Korean section below.
한국어 {#korean}
Cloudflare 기반 오케스트레이션 및 GTape 원칙 데이터 보호 기획서
목적: K8s 운영 복잡성을 피하면서 그에 준하는 성능·보안을 확보하기 위해 Cloudflare 에지 기반 동적 라우팅·보안과 구글 SRE GTape 원칙을 계승한 데이터 보호 체계를 정의하고, **현재 Prego 시스템(Hetzner·Pulumi·Ansible·Frappe)**에 적용하는 방법을 정리한다.
코드 생성 없음 — 기획·전략·적용 방안만 정리.
참조:
- saas-unified-architecture-hetzner-cloudflare-zuplo-plan.md (통합 아키텍처, 프로비저닝·Zuplo)
- tenant-subdomain-dns-design.md (canonical
tenant-{short_id}.pregoi.com, 방식 C) - redis-separation-pulumi-ansible-plan.md (§8.4 Health Check·가시성)
1. 설계 원칙
| 원칙 | 내용 |
|---|---|
| KISS & DRY | 복잡한 K8s/Service Mesh 대신 Cloudflare Workers·Tunnel·R2로 인프라를 코드화(IaC)하고, 백업 거점을 R2로 통일. |
| Economical & Efficient | 현재 단계에서 가장 경제적·효율적인 글로벌 아키텍처로, 비즈니스 가치 증명에 집중. |
| GTape 계승 | ”백업의 유무가 아니라 복구의 신뢰성” — 테스트되지 않은 백업은 백업이 아니다. |
2. Cloudflare를 활용한 동적 라우팅 및 보안 강화
2.1 Cloudflare Workers 기반 동적 테넌트 라우팅
Nginx 설정 파일을 매번 수정하는 대신, Cloudflare Workers에서 코드로 라우팅 로직을 처리한다.
동작 원리
- 사용자가
tenant-a1b2c3d4.pregoi.com또는 사용자 서브도메인acme.pregoi.com으로 접속하면, 에지 노드에서 요청을 가로채 테넌트 정보를 식별한다. - Hostname (또는 canonical로 정규화된 호스트)을 추출한다.
- Cloudflare KV(Key-Value) 저장소에서 해당 테넌트가 위치한 물리적 서버 IP(또는 Tunnel 호스트명)를 조회한다.
fetch()API로 해당 오리진으로 요청을 **프록시(전달)**한다.- 에지에서 오리진으로 전달 시 요청 헤더에 사이트 식별자(예:
X-Frappe-Site-Name= hostname 또는 canonical)를 주입한다. 앱 컨테이너가 하나이더라도 이 헤더만 보고 어떤 사이트(테넌트)인지 즉시 식별·DB 전환할 수 있어, 멀티테넌시 동적 라우팅의 정점이 된다. Worker 구현 시 KV 조회 후backendRequest.headers.set("X-Frappe-Site-Name", url.hostname)등으로 주입.
현재 시스템과의 정합성
| 현행 Prego | 적용 방안 |
|---|---|
| 테넌트 식별 | tenant-{short_id}.pregoi.com (canonical). tenant-subdomain-dns-design 방식 C. |
| 테넌트→서버 매핑 | 현재: DNS A/CNAME가 서버 IP 또는 Tunnel을 가리킴. Workers 도입 시: KV 키 = tenant-{short_id}.pregoi.com (또는 host), 값 = https://<tunnel-origin> 또는 http://<app_server_ip>:port. |
| 매핑 갱신 시점 | 프로비저닝 완료 시(Ansible·workflow 콜백) Control Plane 또는 워크플로에서 KV에 tenant_id(canonical) → server_ip 또는 Tunnel URL 쓰기. 서버 이전·장애 시 KV만 수정하면 전 세계 트래픽이 즉시 다른 서버로 리다이렉션되어 고가용성(HA) 확보. |
| D1과의 관계 | 테넌트·서버 매핑은 이미 D1 tenants_master, nodes(또는 서버 레지스트리)에 존재할 수 있음. Workers에서 KV를 사용하면 에지에서 저지연 조회 가능; KV 동기화는 프로비저닝·서버 변경 시 D1→KV 반영으로 일원화. |
장점
- 서버 한 대 장애 시 KV 설정값만 변경하면 전 세계 트래틾이 즉시 다른 서버(또는 대기 노드)로 라우팅.
- Nginx/HAProxy 설정 파일 배포 없이 **인프라를 코드(IaC)**로 관리.
2.2 Cloudflare Tunnel을 통한 보안 강화 (Gatekeeper 패턴)
시스템의 **공격 표면(Attack Surface)**을 최소화하기 위해 Gatekeeper 패턴을 적용한다.
구현 방법
- Docker(또는 Frappe) 서버에서 외부 포트 80·443을 열지 않는다.
- 서버 내부에서
cloudflared커넥터를 실행하여 Cloudflare와 아웃바운드 전용 터널을 맺는다. - 사용자 트래픽은 Cloudflare 에지 → Tunnel → 서버로만 유입된다.
보안 효과
| 항목 | 내용 |
|---|---|
| 공인 IP 노출 제거 | 직접 포트 스캔·DDoS 타깃이 되지 않음. |
| 통로 일원화 | 모든 트래픽이 Cloudflare WAF·봇 차단·DDoS 방어를 거쳐 인증된 통로로만 유입. |
| Zero Trust | 로컬 Docker 서버에 Zero Trust 환경을 즉시 적용 가능. |
현재 시스템과의 정합성
| 현행 Prego | 적용 방안 |
|---|---|
| Pulumi 방화벽 | 현재: SSH(22)만 허용, 80/443은 서버에 열지 않음(Cloudflare Tunnel 사용 권장) — pulumi-ansible-step1-step2-plan·통합 아키텍처와 일치. |
| cloudflared 설치 | Ansible 또는 프로비저닝 단계에서 App 서버(및 필요 시 DB/Redis 관리용)에 cloudflared 설치·설정. Tunnel 토큰 또는 config 파일은 시크릿으로 관리. |
| Tunnel 라우팅 | Cloudflare Zero Trust 대시보드(또는 API)에서 tenant-*.pregoi.com 등을 해당 Tunnel의 Private Network 또는 localhost 서비스로 라우팅. Workers와 병행 시: Worker가 KV로 서버(Tunnel)를 찾고, 실제 요청은 해당 Tunnel 오리진으로 전달. |
3. Docker 환경의 안정적 데이터 백업 및 복구 (GTape 원칙 기반)
구글 GTape 사례(2011년 Gmail 복구 등)의 핵심: “복구의 신뢰성”. Docker·MariaDB 환경에 맞게 4단계로 구체화한다.
3.1 1단계: Soft Deletion (실수 방어)
테넌트·사용자가 데이터를 삭제해도 물리적으로 즉시 삭제하지 않고 일정 기간 보관한다.
| 항목 | 내용 |
|---|---|
| 구현 | 데이터베이스에 deleted_at(또는 동등) 필드를 두고, 삭제 시 해당 필드만 설정. 쿼리에서는 deleted_at IS NULL 등으로 제외. |
| 영구 삭제 | 정기 배치(예: 30일 경과) 후 deleted_at이 오래된 레코드를 영구 삭제. |
| 현재 시스템 | Frappe/ERPNext의 휴지통·DocStatus 등과 정책 정합성 유지. Control Plane·D1의 Pending_Deletion·Purge 정책(예: 30일 후 Hard Purge)과 동일 원칙. |
3.2 2단계: 스냅샷 및 증분 백업 (데이터 보존)
Docker 볼륨에 연결된 MariaDB 데이터를 주기적으로 백업한다.
| 항목 | 내용 |
|---|---|
| Daily Snapshots | 매일 자정(또는 정해진 시간) 전체 DB 덤프(mysqldump 또는 mariadb-dump) 생성. |
| Binary Logs | MariaDB Binlog 활성화 — Point-in-Time Recovery(PITR) 가능. 현행 Ansible mariadb_server role은 이미 --log-bin, --binlog-format=ROW 설정(Phase 2 Replica 대비). |
| 실행 주체 | DB 서버에서 Cron 또는 Ansible 스케줄; 덤프 파일은 로컬 임시 경로에 저장 후 3단계로 전송. |
3.3 3단계: Offsite 백업 (재해 복구)
백업 파일이 운영 서버와 같은 물리 공간에만 있으면 재해 시 동시 손실 위험이 있으므로, 오프사이트로 이관한다.
| 항목 | 내용 |
|---|---|
| 대상 저장소 | Cloudflare R2(S3 호환). Prego는 이미 R2 사용 중(prego-static-assets, prego-usage-raw 등). 백업 전용 버킷(예: prego-db-backups) 또는 prefix 분리. |
| 전송 도구 | Rclone(S3 호환 엔드포인트) 또는 전용 스크립트로 덤프 파일을 R2로 업로드. 업로드 후 로컬 덤프 파일은 디스크 절약을 위해 삭제 또는 단기 보관 정책 적용. |
| 보관 정책 | 일별·주별·월별 보존 기간, R2 라이프사이클(선택)로 오래된 백업 자동 삭제. |
3.4 4단계: 지속적 복구 테스트 (Trust but Verify — DiRT)
“테스트되지 않은 백업은 백업이 아니다”라는 원칙에 따라 복구 파이프라인을 정기 검증한다.
| 항목 | 내용 |
|---|---|
| DiRT (Disaster Recovery Training) | 매월 1회(또는 분기 1회), R2에서 백업 파일을 내려받아 별도 Docker 컨테이너에서 MariaDB 복원 후 데이터 무결성 검증(Checksum·핵심 테이블 건수 등) 수행. |
| 자동화 | 스테이징 또는 전용 복구 검증 환경에서 스크립트로 실행; 실패 시 알림. |
| 산출물 | 복구 성공/실패·소요 시간·검증 요약을 Runbook 또는 모니터링에 기록. |
4. 현재 시스템 적용 요약
4.1 이미 갖춰진 요소
| 항목 | 현황 |
|---|---|
| 테넌트·canonical | tenant-subdomain-dns-design 방식 C: tenant-{short_id}.pregoi.com, D1·프로비저닝 연동. |
| Cloudflare·R2 | Pulumi에서 R2 버킷 생성·CORS; prego-static-assets, prego-usage-raw 등 사용 중. |
| 방화벽 | Pulumi Hetzner 방화벽으로 SSH만 허용, 80/443 미개방(Tunnel 전제). |
| MariaDB Binlog | Ansible mariadb_server role에서 binlog 활성화됨. |
| Soft Delete·Purge | Control Plane 30일 Pending_Deletion 후 Hard Purge 등 정책 존재. |
4.2 도입·보강이 필요한 요소
| 영역 | 도입·보강 내용 |
|---|---|
| 동적 라우팅 | Cloudflare Workers 배포: Hostname → KV 조회 → 오리진 프록시. KV 키는 canonical(또는 host), 값은 서버 IP 또는 Tunnel URL. 프로비저닝·서버 변경 시 KV 쓰기 연동. |
| Tunnel | App(및 필요 시 DB 관리) 서버에 cloudflared 설치·등록. Cloudflare 대시보드에서 tenant-*.pregoi.com 등을 해당 Tunnel로 라우팅. |
| 백업 | DB 서버에서 일별 mysqldump + Rclone(또는 스크립트)으로 R2 전송. 백업 전용 버킷/prefix, 보관 기간 정책. |
| 복구 검증 | 월 1회 DiRT: R2 → 다운로드 → 별도 컨테이너 복원 → 무결성 검증 자동화·Runbook화. |
4.3 아키텍트 최종 제안 (KISS & DRY)
- 복잡한 K8s 관리 인력 대신 Cloudflare Workers로 라우팅을 코드화(IaC), Cloudflare Tunnel로 보안·Zero Trust 확보, R2를 백업 거점으로 통일.
- 현재 단계에서 가장 경제적(Economical)·**효율적(Efficient)**인 글로벌 아키텍처로, 비즈니스 가치 증명에 집중.
5. 산출물·구현 위치
| 순서 | 산출물 | 구현 위치 |
|---|---|---|
| 1 | Cloudflare Worker | workers/tenant-router/ — Hostname → KV 조회 → fetch(오리진). |
| 2 | KV 연동 | workers/tenant-router/scripts/kv-put-tenant-origin.sh — 프로비저닝 완료·서버 변경 시 KV 쓰기. |
| 3 | cloudflared | prego-ansible/roles/cloudflared_tunnel/ — cloudflared 설치·Tunnel 토큰으로 service install. |
| 4 | MariaDB → R2 백업 | scripts/backup/mariadb-backup-to-r2.sh, mariadb-backup-r2.md. Pulumi R2 버킷 prego-db-backups. |
| 5 | DiRT | scripts/backup/dirt-restore-verify.sh, dirt-restore-verify.md. |