UniFi site¶
The UniFi site is declared in terraform/unifi/network: networks, WAN, Wi-Fi,
adopted devices, DHCP reservations, firewall policies, port forwards, the
WireGuard server and dynamic DNS. The console is for reading; changes go through
Terraform. The user-defined local.bigd.no records are a separate stack, see
dns.md.
Networks and Wi-Fi¶
| Network | VLAN | Subnet | Firewall zone | SSID |
|---|---|---|---|---|
| Trusted | untagged | 10.3.10.0/24 |
Internal | Eden-Trusted (2.4 and 5 GHz) |
| IoT | 20 | 10.3.20.0/24 |
Unsecure Zone | Eden-IoT (2.4 GHz only) |
| Guest | 1000 | 192.168.100.0/24 |
Hotspot | Eden-Guest (guest, L2 isolation) |
Every network hands out Home Assistant (10.3.10.15, AdGuard add-on) as its DNS
server, and so does the primary WAN. DHCP pools run from .6 to .254. The
three SSIDs are WPA2 with WPA3 transition and optional PMF.
Internet 1 is the active WAN (DHCP, weighted, priority 1). Internet 2 is
declared but disabled, failover-only.
Devices¶
| Device | Address | Notes |
|---|---|---|
| Cloud Gateway Fiber | 10.3.10.1 |
router, firewall, resolver for local.bigd.no |
| USW-Lite-8-PoE | 10.3.10.3 |
port 6 is "LG TV" with IoT as native network |
| U6+ | 10.3.10.2 |
LED off; 2.4 GHz on channel 13 to stay clear of Zigbee channel 20, 5 GHz on 108 |
The cluster, NAS and PBS uplink through the switch.
Reservations¶
clients.tf holds the fixed IPs: NAS .10, PBS .11, hyper1-3 .12-.14,
Home Assistant .15, Hue Bridge Pro .16, Talos control plane .31-.33 and
workers .34-.36, all on Trusted, plus the Bluetooth proxy on IoT
(10.3.20.39). Each Trusted reservation also sets local_dns_record, which is
where the console's generated <name>.local.bigd.no records come from.
Firewall¶
IoT is isolated from Trusted by the controller's predefined Block All policies,
which are not managed here. Every policy in firewall.tf is a hole through that
block:
| Policy | From | To |
|---|---|---|
| Allow Internal to Unsecure Zone | Trusted | IoT, any |
| IoT -> Home Assistant | IoT | 10.3.10.15 tcp/udp 53, 8123 |
| LG TV -> Plex | LG TV MAC | 10.3.10.103 tcp 32400 |
Home Assistant dials out to ESPHome, Hue and Sonos, so Trusted reaches IoT freely and IoT only answers. IoT reaches Home Assistant for DNS and for TTS audio on 8123.
A new IoT device that needs something on Trusted gets its own policy, scoped to
that device (CLIENT plus MAC) and destination port. Never a network-to-network
allow: that reopens the whole Trusted side. A device moved from Wi-Fi to cable
gets a new MAC, so its policy has to follow, and its switch port needs the IoT
native network in devices.tf.
Port forwards and remote access¶
| Forward | WAN port | Target |
|---|---|---|
| trefik-http | 80 tcp/udp | 10.3.10.101 (public Traefik gateway) |
| trefik-https | 443 tcp/udp (UDP for HTTP/3) | 10.3.10.101 |
| plex | 32400 tcp/udp | 10.3.10.103 (Plex VIP) |
remote-access.tf holds the break-glass WireGuard server (UDP 51820, clients in
192.168.3.0/24) and the gateway's Cloudflare dynamic DNS clients, which keep
ddns.bigd.no and ddns.nordbye.it on the current WAN address. Day-to-day
remote access is Tailscale, see remote-access.md.
Secrets in tfvars¶
The Wi-Fi passphrases and DDNS tokens in terraform.tfvars must be the values
the controller already has. The provider writes them on every update of their
resource, so a wrong passphrase disconnects that SSID and a wrong DDNS token
stops the WAN address updates. A new value here is how a secret is rotated.
The WireGuard private key is not declared. The console never shows it, and declaring it would put the key every peer trusts into tfvars and state.
Provider traps¶
- The provider fills unset arguments with its own defaults rather than the
controller's, so arguments that look redundant (
setting_preference,lte_lan,group_rekey,bss_transition,ap_group_ids,wlan_band) are pinned to the console's values. Removing one shows up as a change inplan. bandsteering_modemust stay declared on every WLAN. Unset, it plans as unknown on every run and re-pushes the SSID, dropping every client.- Devices have
prevent_destroy: destroying aunifi_deviceforgets (unadopts) it.config_networkis pinned on the switch and AP so an update can never send an empty management address. unifi_devicemanages only the ports declared inport_override. Other ports keep their console settings, and dropping a block does not reset its port.- Zones are data sources by name, and the Default user group and "All APs" group are hardcoded IDs (no data source exists). Renaming "Unsecure Zone", "Internal" or "Hotspot" in the console breaks the plan until the name follows.
indexon firewall policies is read-only; a new policy lands at the end of its zone pair. With allow-only policies the order is moot.- Terraform sees only what it manages. Things created in the console stay
invisible to
plan.
Rebuilding state¶
Everything here was created in the console first and adopted with import blocks.
If the state is ever lost, write a temporary imports.tf from the controller's
_ids (/proxy/network/api/s/default/rest/* and
/proxy/network/v2/api/site/default/firewall-policies); clients import by MAC.
Apply only when the plan reports imports and no adds or destroys, then delete the
file.
Not managed here¶
Site settings (country, NTP, IGMP, DPI, IPS, speedtest; unifi_setting imports
empty, see docs/backlog/README.md), the mDNS reflector, Teleport, the
predefined zones and their default policies, admin accounts and backups.