Tailscale Zero Trust Architecture
Tailscale is the sole remote access mechanism. No management interfaces or internal services are directly exposed to the internet.
All Tailscale nodes live in the DMZ (VLAN 176).
Nodes
| Host | CT ID | IP | Role |
|---|---|---|---|
ts-gateway |
CT123 (pve0-core) | 10.37.176.22 |
Subnet router. Primary path into the homelab. Tagged tag:subnet-router. |
services-proxy-01 |
CT124 (pve0-core) | 10.37.176.32 |
Caddy reverse proxy. HTTPS entry point for internal services. Tagged tag:reverse-proxy. |
bastion |
CT109 (pve0-core) | 10.37.176.23 |
SSH bastion. Fallback management access. Tagged tag:bastion. |
Access Paths
Management (subnet router)
ts-gateway advertises homelab subnets to the Tailnet. Authenticated Tailscale clients can reach management interfaces (Proxmox, OPNsense, etc.) as if they were on the local network.
Fallback — Tailscale down: if ts-gateway is unreachable, bastion provides shell access with direct connectivity to management interfaces. Since bastion is a separate LXC, it can be up even if the subnet router is having issues.
Fallback — Tailscale completely down: a firewall rule permits SSH (port 22) to bastion from VLAN 192 (Home, 10.37.192.0/24). This allows access from a trusted device on the local network without relying on Tailscale at all. Bastion accepts SSH keys only — password authentication is disabled.
Services (reverse proxy)
services-proxy-01 (Caddy) is a Tailscale node. Internal services are accessed over HTTPS through it. This keeps services off the public internet while still being reachable from anywhere via Tailscale.
Public services
Handled separately by cloudflared (Cloudflare Tunnel) — not through Tailscale.
Users & Groups
| Group | Members | Purpose |
|---|---|---|
group:homelab-admins |
admin | Full admin access. |
group:family |
admin, partner | Access to services and media. |
group:secours |
partner | Emergency-only access to bastion (girlfriend). |
Device Tags
| Tag | Owner | Devices |
|---|---|---|
tag:subnet-router |
homelab-admins | ts-gateway |
tag:bastion |
homelab-admins | bastion |
tag:reverse-proxy |
homelab-admins | services-proxy-01 |
tag:media-player |
homelab-admins | Apple TV, etc. |
Security Postures
posture:secure-admin = node:tsStateEncrypted AND node:tsReleaseTrack == 'stable'
Required for admin access to Proxmox and network infrastructure. Ensures the connecting device has encrypted Tailscale state and runs a stable release.
IP Sets
| IP Set | Members | Notes |
|---|---|---|
ipset:dns-servers |
10.37.64.53, 10.37.64.54 (+ IPv6) |
AdGuard + BIND |
ipset:proxmox-cluster |
10.37.16.2, 10.37.16.3 (+ IPv6) |
Both nodes |
ipset:network-infra |
10.37.0.1, 10.37.8.2, 10.37.0.15, 10.37.0.17 (+ IPv6) |
OPNsense, Omada, switch01, switch02 |
ipset:reverse-proxy |
10.37.176.32 (+ IPv6) |
Caddy |
ipset:wazuh |
10.37.64.64 |
Wazuh SIEM |
ipset:hdhomerun |
10.37.192.64 (+ IPv6) |
HDHomerun OTA tuner |
ipset:ups |
10.37.0.2 |
UPS management |
ipset:docker-hosts |
10.37.64.41 |
docker-prod-01 |
Access Control Rules
Family & Media Players
| Source | Destination | Ports | Notes |
|---|---|---|---|
| family, media-player | dns-servers | 53 | DNS resolution |
| family, media-player | reverse-proxy | 80, 443 | Services via Caddy |
| family, media-player | hdhomerun | * | Live TV (direct tuner access for non-Jellyfin apps) |
| family, media-player | autogroup:internet | * | Exit node for privacy/travel |
Admins (homelab-admins)
| Destination | Ports | Posture Required |
|---|---|---|
| proxmox-cluster | 8006, 22 | posture:secure-admin |
| network-infra | 80, 443, 8043, 22 | posture:secure-admin |
| dns-servers | 53, 80, 12321, 22 | No |
| docker-hosts | 9443 | No |
| ups | 80, 443 | No |
| wazuh | 443 | No |
| tag:bastion | 22 | No |
Emergency Access (group:secours)
| Destination | Ports | Notes |
|---|---|---|
| tag:bastion | 22 | Bastion only. Tailscale SSH as secours user. |
Infrastructure
| Source | Destination | Ports | Notes |
|---|---|---|---|
| tag:subnet-router | dns-servers | 53 | DNS only — cannot reach other services (defense in depth) |
| family, subnet-router, bastion, reverse-proxy | wazuh | 1514, 1515, 55000 | Wazuh agent reporting |
SSH Policy
| Source | Destination | Auth Method | User | Notes |
|---|---|---|---|---|
| group:homelab-admins | tag:bastion | Traditional SSH (Secure Enclave key) | nonroot | Not using Tailscale SSH for admin — defense in depth |
| group:secours | tag:bastion | Tailscale SSH | secours |
Emergency access only |
Tailscale Lock
Tailscale Lock is enabled. All new nodes must be signed by a trusted signing node before they can join the tailnet.
Signing Nodes
| Device | Role |
|---|---|
| Personal iPhone | Primary signing node |
| MacBook Pro | Primary signing node |
bastion |
Emergency signing node — used if all personal devices are lost |
The tailnet disablement secret is stored in Bitwarden (see secrets.md) in case the lock needs to be disabled.
Design Principles
- No open inbound ports on WAN — all remote access goes through the Tailscale overlay.
- DMZ placement — all Tailscale nodes sit in VLAN 176 with controlled access to other segments.
- Posture enforcement — Proxmox and network gear require encrypted state + stable client before granting access.
- Subnet router is not privileged —
ts-gatewaycan only reach DNS. Traffic from Tailscale clients hits destination IPs directly, not via the router. Defense in depth. - Redundant management — subnet router (ts-gateway) + bastion cover failure of either path.
- Emergency path — partner has Tailscale SSH access to bastion only, with a dedicated
secoursaccount. - randomizeClientPort: true — reduces Tailscale fingerprinting on the WAN.