Skip to content

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)**에 적용하는 방법을 정리한다.
코드 생성 없음 — 기획·전략·적용 방안만 정리.

참조:


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 LogsMariaDB 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 이미 갖춰진 요소

항목현황
테넌트·canonicaltenant-subdomain-dns-design 방식 C: tenant-{short_id}.pregoi.com, D1·프로비저닝 연동.
Cloudflare·R2Pulumi에서 R2 버킷 생성·CORS; prego-static-assets, prego-usage-raw 등 사용 중.
방화벽Pulumi Hetzner 방화벽으로 SSH만 허용, 80/443 미개방(Tunnel 전제).
MariaDB BinlogAnsible mariadb_server role에서 binlog 활성화됨.
Soft Delete·PurgeControl Plane 30일 Pending_Deletion 후 Hard Purge 등 정책 존재.

4.2 도입·보강이 필요한 요소

영역도입·보강 내용
동적 라우팅Cloudflare Workers 배포: Hostname → KV 조회 → 오리진 프록시. KV 키는 canonical(또는 host), 값은 서버 IP 또는 Tunnel URL. 프로비저닝·서버 변경 시 KV 쓰기 연동.
TunnelApp(및 필요 시 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. 산출물·구현 위치

순서산출물구현 위치
1Cloudflare Workerworkers/tenant-router/ — Hostname → KV 조회 → fetch(오리진).
2KV 연동workers/tenant-router/scripts/kv-put-tenant-origin.sh — 프로비저닝 완료·서버 변경 시 KV 쓰기.
3cloudflaredprego-ansible/roles/cloudflared_tunnel/ — cloudflared 설치·Tunnel 토큰으로 service install.
4MariaDB → R2 백업scripts/backup/mariadb-backup-to-r2.sh, mariadb-backup-r2.md. Pulumi R2 버킷 prego-db-backups.
5DiRTscripts/backup/dirt-restore-verify.sh, dirt-restore-verify.md.
Help