Architecture: Hetzner Edge VPS

arch-edge-vps Architecture

architecture infrastructure hetzner
## Deployment: Hetzner Edge VPS Hetzner CAX11 (cpx11) VPS at 178.156.129.142 serving as the internet-facing edge proxy and mail relay for the pal-e platform. ### Diagram ```mermaid graph TB subgraph Internet DNS[DNS A Records] Client[External Clients] end subgraph Hetzner["Hetzner Edge VPS (178.156.129.142)"] Caddy[Caddy :80/:443] Stalwart[Stalwart :25/:587/:993/:8080] TS_Edge[Tailscale Agent] end subgraph Home["Home k3s Cluster"] TS_K3s[Tailscale Agent] Apps[Application Pods] end DNS --> Client Client -->|HTTPS| Caddy Client -->|SMTP| Stalwart Caddy -->|reverse proxy| TS_Edge TS_Edge -->|mesh VPN| TS_K3s TS_K3s --> Apps Stalwart -->|submission| Apps ``` ### Components | Component | Purpose | Notes | |-----------|---------|-------| | Caddy | Reverse proxy + TLS termination | Ports 80, 443; auto-HTTPS via ACME | | Stalwart | SMTP relay, submission, IMAP, admin UI | Ports 25, 587, 993, 8080 | | Tailscale | Mesh VPN to k3s cluster | Connects edge to home network | | Hetzner Firewall | Cloud-level packet filtering | Ports 22, 80, 443, 25, 587, 993 | ### Key Decisions - **Edge VPS instead of k3s for mail**: Home ISPs block port 25 outbound; Hetzner allows it after unblock request - **PTR/rDNS on Hetzner IP**: Required for mail deliverability; only available on static IPs with hosting provider control - **Public IP stability**: Hetzner provides a fixed IPv4 that DNS A records point to — no DDNS needed - **SaltStack for config management**: Declarative state for Caddy + Stalwart; pillar-driven config - **OpenTofu for provisioning**: Server, firewall, SSH key managed as IaC ### Related - `arch-dns` — DNS records pointing to this VPS - `arch-stalwart` — Stalwart mail server running on this VPS - Project: `stalwart-email` ## Management - **Provisioning**: OpenTofu (`terraform/modules/hetzner-edge/main.tf`) - **Configuration**: SaltStack (`salt/states/top.sls` → `edge-proxy` minion) - **Firewall**: Hetzner cloud firewall (ports 22, 80, 443) + port 25/587/993 for mail - **Connectivity**: Tailscale for internal cluster access ## Key Files - `terraform/modules/hetzner-edge/main.tf` — server, firewall, SSH key - `salt/states/caddy/` — Caddy state + Caddyfile.j2 template - `salt/states/top.sls` — assigns states to `edge-proxy` minion - `salt/pillar/caddy.sls` — site definitions (domain + proxy_target)