flowchart TB subgraph PUBLIC["Public access"] direction LR WEB["Browser and API clients"] MEDIA["Direct media clients"] DNS["Cloudflare DNS-only LB
returns healthy edge addresses"] CF["Cloudflare proxied LB
shared pool, equal weights
session affinity"] PROBE["Cloudflare HTTPS monitor
ingress liveness only
source allowlist + monitor token"] WEB --> CF MEDIA -. "DNS lookup" .-> DNS end subgraph EDGES["Dedicated entry layer"] direction LR subgraph EDGEA["edge-a"] direction TB HA["HAProxy HTTPS ingress
validate Host and source
rebuild trusted client headers
normalize paths and apply access rules"] SELECTA["Service backend
prefer local path
peer as backup + routing cookie"] GWA["Private service gateway
overlay listener, trusted edges only
local Anubis AND origin must be healthy"] ANA["Per-service Anubis on loopback
browser challenge or client-compatible policy
application authentication still required"] HA --> SELECTA SELECTA -->|"primary"| GWA GWA --> ANA end subgraph EDGEB["edge-b"] direction TB HB["HAProxy HTTPS ingress
validate Host and source
rebuild trusted client headers
normalize paths and apply access rules"] SELECTB["Service backend
prefer local path
peer as backup + routing cookie"] GWB["Private service gateway
overlay listener, trusted edges only
local Anubis AND origin must be healthy"] ANB["Per-service Anubis on loopback
browser challenge or client-compatible policy
application authentication still required"] HB --> SELECTB SELECTB -->|"primary"| GWB GWB --> ANB end SELECTA -. "per-service backup over encrypted overlay" .-> GWB SELECTB -. "per-service backup over encrypted overlay" .-> GWA end CF -->|"HTTPS to a healthy endpoint"| HA CF -->|"HTTPS to a healthy endpoint"| HB MEDIA -->|"direct HTTPS after DNS selection"| HA MEDIA -->|"direct HTTPS after DNS selection"| HB PROBE -. "GET /_edge/entry-health: edge-ready" .-> HA PROBE -. "GET /_edge/entry-health: edge-ready" .-> HB MESH["Encrypted Tailscale data plane
private routes and least-privilege access
Headscale is the control plane, not an HTTP transit hop"] ANA --> MESH ANB --> MESH subgraph ORIGINS["Shared private origins"] direction LR VPS["Private application hosts
applications bound to private listeners"] ROUTER["Home subnet router
approved route to HTTPS gateway"] FW["Home firewall
allow HTTPS to gateway"] NPM["Nginx Proxy Manager
private HTTPS with valid origin certificate"] APPS["Home applications
native accounts, sessions and tokens"] ROUTER --> FW --> NPM --> APPS end MESH --> VPS MESH --> ROUTER subgraph OPS["Deployment and control"] direction LR GIT["Git repository
service catalogue + generic templates
no credentials in source"] PLAN["Semaphore plan task
local inventory, no deployment secrets
validate catalogue + derived rules"] DEPLOY["Semaphore deployment task
SSH + sudo, serial rollout
validate candidate with selected HAProxy image
check local AND peer paths"] SECRETS["Separate secret values
DNS API / Anubis signing
monitor / metrics"] HS["Headscale control host
validate and back up policy candidate
preserve unrelated rules, then reload"] CERT["Certbot on each edge
DNS-01 certificate issuance and renewal
validate certificate/key and reload HAProxy"] CFAPI["Cloudflare DNS API
certificate challenge + dedicated edge records
application LB publication managed separately"] GIT --> PLAN GIT --> DEPLOY SECRETS -.-> DEPLOY DEPLOY -. "delegated policy management" .-> HS DEPLOY -. "configure local renewal" .-> CERT CERT -. "DNS-01" .-> CFAPI end DEPLOY -. "deploy and verify" .-> HA DEPLOY -. "deploy and verify" .-> HB HS -. "control and access policy" .-> MESH subgraph MONITORING["Monitoring outside the mesh"] direction LR PROM["Prometheus
one DNS-only target per edge
verified TLS + authorized source + metrics token"] GRAF["Grafana
traffic, sessions, service paths
origin probes and backend errors"] ALERT["Optional alert rules and delivery
must be configured separately"] PROM --> GRAF PROM -.-> ALERT end PROM -. "HTTPS /_edge/metrics" .-> HA PROM -. "HTTPS /_edge/metrics" .-> HB subgraph BOUNDARIES["Failure handling and limits - explanatory notes"] direction LR LIMIT_EDGE["Public edge unavailable
Cloudflare selects a healthy edge for new connections"] LIMIT_PATH["One service path unavailable
HAProxy uses the peer when its path is healthy"] LIMIT_ORIGIN["Shared origin unavailable
Both edges lose that application
edge redundancy does not replicate origins"] LIMIT_STREAM["Open video streams and WebSockets
Existing connections do not migrate
clients must reconnect"] LIMIT_EDGE ~~~ LIMIT_PATH ~~~ LIMIT_ORIGIN ~~~ LIMIT_STREAM end %% Invisible positioning only: this is not a data-flow connection. ORIGINS ~~~ BOUNDARIES classDef public fill:#233d58,stroke:#7ab5dc,color:#f2f6ff classDef edge fill:#284c44,stroke:#7bc8a7,color:#f2f6ff classDef origin fill:#514132,stroke:#d6b48c,color:#f2f6ff classDef ops fill:#43395c,stroke:#b4a0de,color:#f2f6ff classDef monitor fill:#34495b,stroke:#9bbdd4,color:#f2f6ff classDef note fill:#4c303a,stroke:#dd9ba7,color:#fff5f6 class WEB,MEDIA,DNS,CF,PROBE public class HA,HB,SELECTA,SELECTB,GWA,GWB,ANA,ANB,MESH edge class VPS,ROUTER,FW,NPM,APPS origin class GIT,PLAN,DEPLOY,SECRETS,HS,CERT,CFAPI ops class PROM,GRAF,ALERT monitor class LIMIT_EDGE,LIMIT_PATH,LIMIT_ORIGIN,LIMIT_STREAM note style BOUNDARIES fill:#291f2a,stroke:#dd9ba7,color:#fff5f6