Skip to content

Network

Last Updated: 2026-04-16 Purpose: Network topology, VLANs, DNS, and external access setup.


Physical Setup

All networking runs on UniFi equipment managed by the UCG Ultra. The switch topology is a chain from the bedroom wardrobe outward:

UCG Ultra (Bedroom wardrobe)
├── Port 2 → Bedroom AP (U7LT)
└── Port 3 → Bedroom Switch (USW Mini 5)
               ├── Port 5 → Living Room Switch (US8P60)
               │              ├── Port 2 → Office Switch (USW Mini 5)
               │              │              └── Port 3 → Office AP (U7LT)
               │              └── Port 6 → Living Room AP (U7PG2)
               └── (other ports → local bedroom devices)

For full hardware specs (models, MACs, firmware) see Hardware Inventory — Network Equipment.


WAN / Internet

WAN1 — Primary (Vodafone ADSL)

Provider Vodafone ADSL
Modem Bedroom wardrobe, connected to phone socket behind curtain
Modem gateway 192.168.99.254
UCG Ultra port 2.5GE WAN (port 5)
UPS backed Yes (bedroom UPS)

WAN2 — Backup (Three LTE)

Provider Three UK — LTE
Router Zyxel LTE3302-M432 at 192.168.2.254
Signal -56 dBm RSSI (excellent)
UCG Ultra port GE port 4 (configured as WAN2)
Mode Failover only — activates automatically when WAN1 fails
NAT Double NAT (Zyxel router mode + UCG Ultra) — harmless with Tailscale; no port forwarding used
UPS backed Yes (bedroom UPS)

Failover Configuration

WAN failover is handled automatically by the UCG Ultra: - Health check: Pings 8.8.8.8 and 1.1.1.1 every 5 seconds - Trigger: 80% packet loss to both targets over 30 seconds - Failback: Automatic when WAN1 recovers


VLANs

VLAN Name Subnet Purpose DNS
MainLAN 192.168.1.0/24 Primary devices and servers 192.168.1.11, 192.168.1.111
20 IoT 192.168.20.0/24 IoT devices with internet access 1.1.1.1, 4.4.4.4 (Cloudflare, direct)
30 NoT 192.168.30.0/24 IoT devices without internet access 192.168.1.11, 192.168.1.111
66 Guest 192.168.40.0/27 Guest WiFi (isolated) Router
VPN 192.168.3.0/24 L2TP VPN server pool

All of MainLAN, IoT and NoT sit inside the same UniFi Internal firewall zone, so traffic between them is permitted by default. NoT's isolation comes from internet_access_enabled: false on the network plus a Drop all other NoT catch-all policy, with narrow allow rules above it (Home Assistant, Mosquitto, DNS, NTP).

Cross-VLAN allow rules

IoT and NoT are each isolated by a catch-all BLOCK at the bottom of the Internal → Internal policy list, with every exception stacked above it:

Index Policy
10000–10026 the Allow … exceptions (Home Assistant, Mosquitto, DNS, NTP, Plex, Sonos, LMS, …)
10027 Allow Kindle to CWA192.168.20.244192.168.1.80:8083/tcp
40000 BLOCK Drop IoT from local network — IoT → All local IP Addresses
40001 BLOCK Drop all other NoT

Allow rules here only ever need one direction. Allow Established and Related (index 10009, Internal → Internal) already permits the reply path for every session an allow rule opens. Adding a matching return rule is redundant — the only reason Allow IoT to DNS Servers has a (Return) twin is that it is a predefined UniFi pair, not a pattern to copy.

To add an exception: create the policy, then drag it above the relevant 40000-series BLOCK. Anything left below it is silently dead.

Read the live list with:

unifi-q.py "v2/api/site/default/firewall-policies"

The claude code UniFi admin is read-only — it can list policies but gets 403 on any write, so rule changes must be made in the UI.

Time (NTP)

NoT has no internet, so devices there must use a local time source. Lotus (192.168.1.80) and Cooper (192.168.1.60) both serve NTP; the UCG does not.

⚠️ The Allow all Local to NTP policy originally specified a source port of 123 as well as a destination port of 123. Only a classic ntpd binds local port 123 as a client — SNTP clients like Tasmota use an ephemeral port, so the rule never matched them and every NoT device sat at 1970-01-01 indefinitely. Fixed 2026-07-28 by setting the source port to Any on the Internal → Internal instance of the rule. See Lessons Learned.


Key IP Addresses

Device Hostname IP
Gateway / Router UCG Ultra 192.168.1.1
Bedroom Switch 192.168.1.2
Living Room Switch 192.168.1.3
Office Switch 192.168.1.4
Proxmox NUC Pacific 192.168.1.10
Home Assistant VM HomeAssistant 192.168.1.12
Desktop PC Brabham 192.168.1.40
Backup NAS Cooper 192.168.1.60
Primary NAS Lotus 192.168.1.80
Local docs (nginx on Lotus) docs.home 192.168.1.81
Gabriela dashboard (on Lotus) gabriela.home 192.168.1.82
Bedroom AP 192.168.1.171 (DHCP)
Living Room AP 192.168.1.123 (DHCP)
Office AP 192.168.1.101 (DHCP)
Primary DNS 192.168.1.11
Secondary DNS 192.168.1.111

Switches

Name IP Location Uplink
Bedroom Switch 192.168.1.2 Bedroom wardrobe UCG Ultra Port 3
Living Room Switch 192.168.1.3 Living room Bedroom Switch Port 5
Office Switch 192.168.1.4 Office outbuilding Living Room Switch Port 2

Full specs (model, ports, firmware) in Hardware Inventory.


Access Points & WiFi

Name IP Location Uplink
Bedroom AP 192.168.1.171 (DHCP) Bedroom UCG Ultra Port 2
Living Room AP 192.168.1.123 (DHCP) Living room Living Room Switch Port 6
Office AP 192.168.1.101 (DHCP) Office outbuilding Office Switch Port 3

All three APs broadcast four SSIDs on both 2.4 GHz and 5 GHz:

SSID VLAN Purpose
2SVT-Main MainLAN Primary network — trusted devices
IoT IoT (20) IoT devices with internet access
NoT NoT (30) IoT devices without internet access
Guest Guest (66) Isolated guest access

Full specs (model, firmware) in Hardware Inventory.

2.4 GHz channel plan

Channels are pinned manually and auto-optimisation/RRM is left off — an RRM run can drop an AP onto a jammed channel. 2.4 GHz stays at 20 MHz width.

AP 2.4 GHz channel Notes
Bedroom AP 1
Living Room AP 6 Restored 2026-07-29 after the channel-6 jamming incident was resolved
Office AP 1 Shares ch1 with Bedroom; both are lightly loaded (cu_total 25 and 29) at opposite ends of the property

2.4 GHz is shared with two Zigbee meshes — Sonoff/Zigbee2MQTT on channel 26 and Hue on channel 25, both at the top of the band. WiFi 1/6/11 are the only non-overlapping channels and they leave three gaps:

Band MHz Occupant
WiFi ch 1 2401–2423 Bedroom AP, Office AP
gap 2423–2426 Zigbee 15 (2425) — free
WiFi ch 6 2426–2448 Living Room AP
gap 2448–2451 Zigbee 20 (2450) — free
WiFi ch 11 2451–2473 free
top 2473–2483 Zigbee 25 (Hue), Zigbee 26 (Sonoff)

Why the Office AP is still on ch1 rather than ch11: WiFi ch11's upper edge leaves only ~2 MHz to Zigbee 25 and ~7 MHz to Zigbee 26. Measured evidence (the Living Room AP sat on ch11 from 07-27 to 07-29, in the same room as both coordinators) showed no distance-correlated degradation of the Sonoff ch26 mesh — so ch11 is probably safe, especially for an AP in the outbuilding. But Hue on ch25 exposes no link metrics and remains unmeasured. The clean path is to move Hue 25 → 15 first, removing the only tight adjacency, then take the Office AP to 11 for a full 1/6/11 split.

Do not move the Sonoff coordinator off channel 26 — 75 devices, and battery TRVs/sensors often won't follow a channel change (hand re-pairing). Note ch26 runs at reduced TX power on CC2652 coordinators (band-edge limits), so suspect it first for any range or dropout issue.

Zigbee link quality is measurable via the sensor.*_linkquality entities — these are created disabled by default by Zigbee2MQTT and were all enabled on 2026-07-29. Baseline: min 18, max 142, average 69. Newly paired devices arrive with their LQI entity disabled and need enabling individually.

Diagnosing a jammed channel: cu_total ≥ 95 with cu_self_rx/cu_self_tx ≈ 0 and tx_packets ≈ 0 means external interference, not a busy AP. Read via unifi-login-api api/s/default/stat/deviceradio_table_stats[]. stat/spectrumscan is not exposed on this UniFi version, so putting an AP on a channel is the only way to observe it.


External Access

Services are accessed externally via Tailscale + SWAG:

  1. Cloudflare DNS*.djchome.uk wildcard A record resolves to Lotus's Tailscale IP (100.106.140.33)
  2. SWAG (reverse proxy on Lotus) — handles SSL termination and routes to the correct container
  3. Tailscale — only devices on the Tailnet can reach the Tailscale IP, so services are private by default

No ports are directly forwarded from the internet. Access requires being on the Tailnet.

A Tailscale exit node runs on Pacific (LXC 103), allowing Tailnet devices to route all traffic through the home network.

Exception: docs.djchome.uk is hosted on Cloudflare Pages and protected by Google authentication. It is accessible from anywhere without Tailscale.

SWAG Hot Spare

A standby SWAG instance runs on Cooper (Tailscale IP: 100.126.183.94). A failover script on Cooper monitors Lotus SWAG every 5 minutes and automatically updates the *.djchome.uk Cloudflare wildcard record to point to Cooper if Lotus is unreachable for two consecutive checks (~10 minutes). It fails back automatically when Lotus recovers.

See Cooper server doc for full details.


Domain

Domain djchome.uk
Wildcard *.djchome.uk
DNS provider Cloudflare
Docs site docs.djchome.uk (Cloudflare Pages + Google Auth)
Cloudflare Pages project homelab-docs
GitHub repo danieljclark/homelab-docs

DNS

Server IP Notes
Primary 192.168.1.11
Secondary 192.168.1.111

AdGuard Home is installed on Pacific (LXC 101) but is not currently active as the primary DNS resolver.

The IoT VLAN (20) uses Cloudflare DNS (1.1.1.1 / 4.4.4.4) directly, bypassing local DNS filtering.

Notable IoT VLAN devices:

Device IP Notes
Sonoff Zigbee Bridge (Tasmota) 192.168.20.10 Zigbee coordinator — living room, UPS backed, connects to HA via WiFi

Security Posture

  • No direct port forwarding from internet to internal services
  • External access requires Tailscale (mesh VPN)
  • IoT devices isolated on VLAN 20 (internet access) or VLAN 30 (no internet)
  • Guest WiFi isolated on VLAN 66 — small pool, no access to internal devices
  • Admin interfaces (Unraid, Proxmox, SWAG) not exposed externally
  • L2TP VPN server available for legacy VPN clients

Documentation Access

URL Hosted on Availability
Cloud docs https://docs.djchome.uk Cloudflare Pages Anywhere (requires Google login)
Local docs http://docs.home (192.168.1.81) nginx:alpine on Lotus (br0) Home network only — syncs from GitHub every 30 min