mirror of
https://github.com/RWejlgaard/pez-infra.git
synced 2026-05-06 04:14:43 +00:00
152 lines
5.4 KiB
Markdown
152 lines
5.4 KiB
Markdown
# Networking
|
|
|
|
## Tailscale Mesh
|
|
|
|
Tailscale is the backbone of the whole setup. It's a WireGuard-based mesh VPN that connects all servers regardless of where they physically are. Every server can reach every other server directly — no port forwarding, no NAT traversal, no exposed SSH ports.
|
|
|
|
All inter-server communication uses Tailscale IPs:
|
|
|
|
| Host | Tailscale IP |
|
|
|------|-------------|
|
|
| helsinki-a | 100.67.6.27 |
|
|
| london-b | 100.84.65.101 |
|
|
| london-a | 100.122.219.41 |
|
|
| nuremberg-a | 100.117.235.28 |
|
|
| copenhagen-a | 100.89.206.60 |
|
|
| copenhagen-c | 100.115.45.53 |
|
|
|
|
### What Tailscale is used for
|
|
|
|
- **Reverse proxying:** Caddy on helsinki-a forwards traffic to backends via Tailscale IPs
|
|
- **Monitoring:** Prometheus on london-a scrapes exporters on all hosts via Tailscale
|
|
- **SSH access:** All SSH is done over Tailscale — no SSH ports exposed to the internet
|
|
- **Ansible deployments:** GitHub Actions runs Ansible over Tailscale SSH connections
|
|
- **Exit nodes:** Servers can act as VPN endpoints — useful for accessing UK content from Copenhagen or vice versa
|
|
|
|
### Mesh Diagram
|
|
|
|
```
|
|
helsinki-a ◄──────────────────────────► london-b
|
|
▲ ▲ ▲ ▲
|
|
│ │ │ │
|
|
│ └──────────► london-a ◄──────────┘ │
|
|
│ ▲ │
|
|
│ │ │
|
|
▼ │ ▼
|
|
nuremberg-a copenhagen-a ◄────► copenhagen-c
|
|
|
|
Every node can reach every other node directly.
|
|
Connections shown are illustrative — the mesh is fully connected.
|
|
```
|
|
|
|
## Physical Networking
|
|
|
|
### London
|
|
|
|
The London setup is in a rack cabinet in the bedroom (great white noise machine, honestly).
|
|
|
|
- **Router:** Ubiquiti Dream Machine Special Edition — overkill for a home setup but gives excellent routing performance vs an ISP router
|
|
- **ISP:** BT, 1 Gbit down / 300 Mbit up, ~£90/month
|
|
- **Cabling:** Cat 5 in the walls, patch panel in the utility closet, connected to a Ubiquiti switch
|
|
- **Servers:** london-a and london-b connected via Ethernet to the switch
|
|
|
|
### Copenhagen
|
|
|
|
A stack of servers at my dad's place — acts as an off-site location.
|
|
|
|
- **Router:** ISP-provided (not my house, can't exactly install a Ubiquiti rack)
|
|
- **ISP:** Symmetrical 500 Mbit — plenty for what's running there
|
|
- **Servers:** copenhagen-a and copenhagen-c connected directly to the ISP router's built-in switch
|
|
|
|
### Helsinki / Nuremberg (Hetzner Cloud)
|
|
|
|
- Standard Hetzner Cloud VPS networking
|
|
- Public IPv4 addresses
|
|
- helsinki-a is the only server that receives traffic from the public internet
|
|
- nuremberg-a receives mail (ports 25, 587, 993)
|
|
|
|
## DNS Flow
|
|
|
|
All DNS is managed by Cloudflare, provisioned via Terraform.
|
|
|
|
### Domain: pez.sh
|
|
|
|
The domain is registered on Hover.com with nameservers pointed to Cloudflare.
|
|
|
|
### How a request reaches a service
|
|
|
|
```
|
|
1. Browser requests radarr.pez.sh
|
|
│
|
|
2. Cloudflare resolves DNS (proxied record → Cloudflare IP)
|
|
│
|
|
3. Cloudflare terminates external TLS, forwards to helsinki-a
|
|
│
|
|
4. Caddy on helsinki-a receives the request
|
|
│
|
|
5. Caddy checks: does this subdomain require auth?
|
|
│
|
|
├── YES: forward_auth to Authelia (localhost:9091)
|
|
│ │
|
|
│ ├── Authenticated → proceed to step 6
|
|
│ └── Not authenticated → redirect to auth.pez.sh
|
|
│
|
|
└── NO: proceed to step 6
|
|
│
|
|
6. Caddy reverse-proxies to the backend over Tailscale
|
|
(e.g., london-b:7878 for Radarr)
|
|
│
|
|
7. Response flows back: backend → Caddy → Cloudflare → browser
|
|
```
|
|
|
|
### Public Subdomains
|
|
|
|
All subdomains are Cloudflare-proxied and terminate at helsinki-a:
|
|
|
|
| Subdomain | Backend | Auth |
|
|
|---|---|---|
|
|
| auth.pez.sh | helsinki-a:9091 | — |
|
|
| bitwarden.pez.sh | helsinki-a:8443 | — |
|
|
| status.pez.sh | helsinki-a:/srv/status | — |
|
|
| apps.pez.sh | helsinki-a:/srv/apps | Authelia |
|
|
| grafana.pez.sh | london-a:3000 | Authelia |
|
|
| prometheus.pez.sh | london-a:9090 | Authelia |
|
|
| jellyfin.pez.sh | london-b:8096 | — |
|
|
| plex.pez.sh | london-b:32400 | — |
|
|
| request.pez.sh | london-b:5055 | — |
|
|
| cloud.pez.sh | london-b:11000 | — |
|
|
| music.pez.sh | london-b:4533 | — |
|
|
| radarr.pez.sh | london-b:7878 | Authelia |
|
|
| sonarr.pez.sh | london-b:8989 | Authelia |
|
|
| lidarr.pez.sh | london-b:8686 | Authelia |
|
|
| readarr.pez.sh | london-b:8787 | Authelia |
|
|
| prowlarr.pez.sh | london-b:9696 | Authelia |
|
|
| soulseek.pez.sh | london-b:5030 | Authelia |
|
|
| download.pez.sh | london-b:9091 | Authelia |
|
|
|
|
### Mail DNS
|
|
|
|
nuremberg-a handles mail for pez.sh. DNS records managed via Cloudflare:
|
|
|
|
- **MX** record pointing to nuremberg-a
|
|
- **SPF** record for sender verification
|
|
- **DKIM** record for message signing
|
|
- **DMARC** record for policy enforcement
|
|
|
|
### Caddy TLS
|
|
|
|
Caddy handles TLS termination for the Cloudflare-to-origin connection. Certificates are obtained and renewed automatically via ACME (Let's Encrypt). No manual cert management, no cron jobs, no renewals to think about.
|
|
|
|
Example Caddyfile block for a protected service:
|
|
|
|
```
|
|
radarr.pez.sh {
|
|
forward_auth helsinki-a:9091 {
|
|
uri /api/verify?rd=https://auth.pez.sh
|
|
copy_headers Remote-User Remote-Groups Remote-Name Remote-Email
|
|
}
|
|
reverse_proxy london-b:7878
|
|
}
|
|
```
|
|
|
|
Compare that to the equivalent Nginx config — about 4 lines vs 20. This is why I use Caddy.
|