Skip to content

Gateway (UniFi)

Each site runs a UniFi Dream Machine Pro (UDM Pro) as the network gateway. The UDM Pro handles VLANs, inter-VLAN routing, static routes for Tailscale, and port forwarding for the reverse proxy. Gateway configuration is managed manually through the UniFi controller UI — it is not automated via Ansible.

VLANs

Each environment uses the same VLAN layout with environment-specific IP ranges.

VLAN Name Subnet Purpose
1 Infrastructure 10.2.0.0/24 Proxmox hosts, NAS, physical infrastructure
10 Storage 10.2.10.0/24 Dedicated storage traffic
20 Virtual Machines 10.2.20.0/24 All Ansible-managed VMs
30 Servers Misc 10.2.30.0/24 Miscellaneous server devices
200 Wired Devices 10.2.200.0/24 Wired client devices
230 Wireless Devices 10.2.230.0/24 Wi-Fi client devices
245 IoT Devices 10.2.245.0/24 IoT and smart home devices
VLAN Name Subnet Purpose
1 Infrastructure 10.3.0.0/24 Proxmox hosts, NAS, physical infrastructure
20 Virtual Machines 10.3.20.0/24 All Ansible-managed VMs
30 Servers Misc 10.3.30.0/24 Bare-metal lab devices (PTP time server and clients)

All Ansible-managed infrastructure and application VMs live on VLAN 20 (Virtual Machines). The networking VM at .53, CA at .9, NTP at .123, and monitoring at .30 are all on this VLAN. In LDN, the PTP time server (LattePanda MU) is a physical host on VLAN 30 at 10.3.30.123, managed by the separate ptp-experiments repo.

Static Routes

Static routes on the UDM Pro direct traffic for remote site subnets through the local Tailscale subnet router. Without these routes, traffic destined for other sites would be sent to the default gateway (the ISP) instead of through the Tailscale tunnel.

Why Static Routes Are Needed

The Tailscale subnet router VM advertises remote subnets to the Tailscale mesh, but the UDM Pro doesn't participate in Tailscale. Other VMs and physical devices on the network need a route to reach the remote subnets, so the UDM Pro must be told to forward that traffic to the Tailscale subnet router.

graph LR
    Client["Local Client\n(any VLAN)"] -->|"10.3.x.x"| UDM["UDM Pro"]
    UDM -->|"static route"| TSRouter["Tailscale Subnet Router\n10.2.20.53"]
    TSRouter -->|"WireGuard tunnel"| Remote["Remote Site\n10.3.x.x"]

Configuration

In the UniFi controller: Settings → Routing → Static Routes

UniFi static route configuration

Name Destination Next Hop Purpose
LDN Network 10.3.0.0/16 10.2.20.53 Route to LDN via Tailscale
Tailscale CGNAT 100.64.0.0/10 10.2.20.53 Route to Tailscale mesh IPs
Name Destination Next Hop Purpose
WIL Network 10.2.0.0/16 10.3.20.53 Route to WIL via Tailscale
Tailscale CGNAT 100.64.0.0/10 10.3.20.53 Route to Tailscale mesh IPs

Note

The next hop is always the Tailscale subnet router VM (.53 on VLAN 20). This VM runs Tailscale in subnet_router mode with IP forwarding and NAT masquerade enabled. See VPN (Tailscale) — Deployment Modes.

Adding a New Site Route

When adding a new site to the homelab:

  1. Deploy Tailscale on the new site's networking VM as a subnet router (see Tailscale — Set up a new subnet router)
  2. On each existing site's UDM Pro, add a static route:
    • Destination: the new site's subnet (e.g., 10.4.0.0/16)
    • Next Hop: the local Tailscale subnet router (e.g., 10.2.20.53)
  3. On the new site's UDM Pro, add static routes for each existing site

Port Forwarding

Port forwarding rules on the UDM Pro direct inbound internet traffic to the Caddy reverse proxy. This is required for external access to services like Plex and for Caddy to serve HTTPS on the public IP.

Configuration

In the UniFi controller: Settings → Firewall & Security → Port Forwarding

UniFi port forwarding configuration

Name External Port Internal IP Internal Port Protocol Purpose
HTTP 80 10.2.20.53 80 TCP HTTP → Caddy (redirects to HTTPS)
HTTPS 443 10.2.20.53 443 TCP HTTPS → Caddy (reverse proxy)

Both rules forward to the networking VM (.53) where Caddy listens. Caddy handles TLS termination using wildcard certificates obtained via the Cloudflare DNS-01 challenge and routes requests to the appropriate backend service.

Warning

Only ports 80 and 443 should be forwarded. Individual services should never be directly exposed — all external traffic routes through Caddy. Services that need external access are configured with Cloudflare DDNS records pointing to the public IP.

Traffic Flow

graph LR
    Internet[Internet Client] -->|"plex.5am.video:443"| UDM["UDM Pro\n(port forward)"]
    UDM -->|443| Caddy["Caddy\n10.2.20.53"]
    Caddy -->|"reverse proxy"| Plex["Plex\n10.2.0.5:32400"]
  1. External client resolves plex.5am.video via Cloudflare DNS → public IP
  2. UDM Pro receives traffic on port 443, forwards to 10.2.20.53:443
  3. Caddy terminates TLS, matches the hostname, and proxies to the backend

Network Boot (PXE)

The LDN netboot VM (10.3.20.60) runs netboot.xyz for PXE re-imaging of bare-metal devices — currently the PTP time server on VLAN 30. See the Re-image the Time Server runbook.

In the UniFi controller: Settings → Networks → (VLAN 30 network) → DHCP Service Management → Show Options → Network Boot

Network Server Filename Purpose
LDN VLAN 30 10.3.20.60 netboot.xyz.efi UEFI x86_64 PXE boot → netboot.xyz menu

Scoping the option to VLAN 30 keeps PXE away from every other network. If the controller version lacks a Network Boot toggle, set custom DHCP options 66 (TFTP server) and 67 (boot filename) instead.

DHCP Reservation

The installed OS pins the time server's address statically by its PXE NIC's MAC (see the timeserver_hosts entry in the netboot vars); the installer itself uses DHCP only transiently to fetch the ISO. A fixed-IP reservation is kept purely as a backstop:

Device Fixed IP Notes
LattePanda MU (PTP grandmaster) 10.3.30.123 Reserve against the PXE NIC MAC (54:49:4d:45:00:22), the same key as its timeserver_hosts entry

Firewall Requirements

PXE clients on VLAN 30 must reach the netboot VM on VLAN 20: UDP 69 (TFTP) and TCP 8080 (HTTP boot assets). Inter-VLAN routing is allowed by default; only restrictive custom LAN-to-LAN rules would break this (symptom: iPXE times out fetching the boot file).

Raspberry Pi CM5 clients on the same VLAN ignore the boot filename option (netboot.xyz.efi is x86-only and harmless to them) and pin the TFTP server via TFTP_IP in their EEPROM instead of relying on this DHCP option — no UniFi changes are needed for them. See Provision a CM5.

Inter-VLAN Routing

The UDM Pro routes traffic between VLANs by default. Key inter-VLAN traffic patterns:

Source Destination Purpose
VLAN 200/230 (clients) VLAN 20 (VMs) Access services via Caddy
VLAN 1 (infrastructure) VLAN 20 (VMs) Proxmox managing VMs
VLAN 20 (VMs) VLAN 1 (infrastructure) VMs accessing NAS storage
VLAN 20 (VMs) VLAN 10 (storage) Dedicated storage traffic (NFS/iSCSI)
VLAN 245 (IoT) VLAN 20 (VMs) IoT devices reaching Home Assistant

Tip

Firewall rules on the UDM Pro can restrict inter-VLAN traffic. For example, IoT devices on VLAN 245 might only be allowed to reach specific IPs on VLAN 20 (like Home Assistant) and nothing else.

Troubleshooting

Cross-site traffic not reaching destination — Verify the static route exists in the UniFi controller (Settings → Routing → Static Routes). The next hop must be the Tailscale subnet router VM (.53). Check that the subnet router VM is running and Tailscale is connected.

Port forwarding not working — Verify the rules in Settings → Firewall & Security → Port Forwarding. Ensure ports 80 and 443 forward to the networking VM IP. Check that no firewall rules are blocking inbound traffic.

Inter-VLAN access denied — Check UniFi firewall rules. By default, inter-VLAN routing is allowed, but custom rules may restrict it. Verify the source and destination VLANs in the firewall policy.