Access paths
How I reach the lab from the LAN and from away. Internal HTTPS through Nginx Proxy Manager with one DNS-01 wildcard certificate, WireGuard and NetBird for remote access, MeshCentral and RustDesk for remote control, and the rule that a path to a Proxmox node needs two firewalls to say yes.
Every way into the lab has one owner and one entry point. This page covers the internal ones: how a client on the LAN reaches a web app, how I get in from outside, and how I take over a machine’s console. The lab also runs public services, which have their own separate path that this page does not cover.
| Path | Who uses it | Entry point | Names |
|---|---|---|---|
| Internal HTTPS | LAN clients | Nginx Proxy Manager on CT 107 docker-network, Access-A (VLAN 85) | *.alphasecunited.com, LAN only |
| Remote access, WireGuard | Me, off the LAN | UniFi Management Access WireGuard server on the gateway | Addresses, not names |
| Remote access, mesh | Me, off the LAN | Self-hosted NetBird, routed through docker-network | Addresses, not names |
| Remote control | Me, at a device’s console | MeshCentral and RustDesk on CT 108 docker-blue, Personal-A (VLAN 40) | mesh.alphasecunited.com |
| Node management | My admin devices | Proxmox web GUI and SSH on MGMT-A (VLAN 70) | grey.alphasecunited.com and the other node names |
Internal HTTPS
The flow for every internal web app is the same:
LAN client -> UniFi local DNS -> Nginx Proxy Manager (HTTPS) -> backend web port
Nginx Proxy Manager 2.15.1 runs on CT 107 docker-network as my internal HTTPS front door. It has no public DNS and no WAN ingress. On 2026-10-05 it held 25 live proxy hosts: NetBird plus 24 applications.
One certificate. A single Let’s Encrypt certificate covers *.alphasecunited.com and the apex. It renews through a Cloudflare DNS-01 challenge, which proves control of the domain with a TXT record, so no inbound port is needed and none of the internal names has to exist in public DNS. Every live host uses that certificate with Force SSL, HTTP/2, Block Common Exploits and WebSocket support. HSTS is off. The certificate issued on 2026-07-11 has since renewed in place and runs to 2026-12-08.
One DNS record per host. The UniFi gateway holds a local A record for each proxy host, all pointing at the proxy. Adding an app has meant three changes: the proxy host, its DNS record, and its web port on the UniFi policy that lets the proxy reach that backend.
A shared Docker network. NPM and the NetBird containers on the same host share an external Docker network called proxy, so NPM reaches them by container name without publishing their HTTP ports to the LAN. NetBird trusts only NPM’s fixed address on that network as its HTTP proxy.
Most of the names, grouped by the guest behind them:
| Backend guest | Names |
|---|---|
media-01 (CT 842) | jellyfin, seerr, sonarr, radarr, prowlarr, qbittorrent |
docker-main (CT 110) | immich, booklore (now serving BookOrbit), dashboard (Homarr), sure, forgejo, dockhand, openwebui, appportal |
monitor-01 (CT 104) | peanut, grafana, prometheus |
security-01 (VM 200) | wazuh |
splunk-siem (VM 109) | splunk |
ansible-01 (CT 100) | semaphore |
alpha-prod-01 (VM 401) | ts3-manager |
docker-blue (CT 108) | mesh |
docker-network (CT 107) | netbird |
NPM connects to three backends over HTTPS because they already serve it: Wazuh, Splunk Web and MeshCentral. The rest are plain HTTP behind the proxy. A few hosts carry their own settings: Immich has request buffering off, a 50,000 MiB body limit and 600-second timeouts, and MeshCentral and Dockhand use WebSockets with one-hour proxy timeouts.
Outside the proxy, the gateway also answers five Proxmox node names on MGMT-A for each node’s web GUI, and one name for Windows Admin Center on the identity network. The NPM admin interface itself has no domain name and stays on the LAN.
Firewall side. On 2026-09-24, 13 UniFi policies named NPM. Ten let the proxy reach exactly one backend each, on that backend’s listed web ports and nothing else. Three let specific clients outside the Internal zone reach the proxy on HTTPS: the container-management agents on alpha-prod-01 and security-01, and the domain test workstation HQ-WS001. Internal and VPN clients reach the proxy through the zone-level allows into AlphaSec-Access. The proxy’s own outbound traffic is limited to web and NTP, then blocked.
Warning: Everything behind the proxy depends on one container. On 2026-09-25 a scheduled container update stopped NPM and could not restart it, and every internal HTTPS name was down from 3:00 AM to 6:12 AM. I pinned the image to 2.15.1 and excluded it from automatic updates; a 2.16.0 upgrade is a planned manual step.
Internal HTTPS for 24 names: one wildcard certificate, one DNS record per name, and the backends the proxy is allowed to reach. Click to enlarge.
Remote access: WireGuard
Management Access is a WireGuard server on the UniFi gateway itself and the only one of the remote-user VPN servers that is enabled. FamilyVPN, Game-Access and Temp are disabled. Clients land in the Vpn firewall zone, and UniFi policies admit them to:
- the management zone (
AlphaSec-Mgmt), SERVERS-A, Access-A and the observability zone; - the whole Internal zone and the DMZ (Management Access only);
- RDP on the four identity hosts;
- the PeaNUT UPS dashboard.
On the Proxmox side, the Datacenter firewall admits the WireGuard client range to MGMT-A and SERVERS-A. When I locked down MGMT-A on 2026-07-27 I kept this path broad on purpose, because it is my approved remote-management path. Both enforced rule layers were verified at the time, but no VPN client was connected for a live traffic probe.
Remote access: NetBird
NetBird is a self-hosted WireGuard mesh. Its control plane runs on CT 107 docker-network, beside Nginx Proxy Manager, as two containers: the combined netbird-server (management 0.79.0) and the dashboard (v2.93.0). There is no separate signal or relay container. The dashboard is published internally at netbird.alphasecunited.com through NPM proxy host 1.
| Element | State |
|---|---|
| Network | AlphaSec-Galaxy, built on NetBird’s Networks model |
| Routing peer | docker-network, with masquerade, the only router on the network |
| Resources defined | 13: subnets for nine VLANs plus four Proxmox node hosts |
| Resources granted | One: Access-A (VLAN 85), through the policy Peers → Access-A (VLAN 85) |
| Peer DNS | None distributed; overlay domain netbird.selfhosted only |
I chose Networks over legacy network routes because a Network resource is unreachable until a policy grants it, which matches the default-deny zone firewall. Legacy routes grant access as soon as they are published.
What a peer can actually reach is narrower than the resource list suggests. Twelve of the 13 resources are enabled, but no policy names them or their groups, so they are unreachable; the routing peer installs only the Access-A route. One policy, Admin Users --> Security Machines, looks like it covers VLAN 72, but its destination is the peer group Security-A rather than the resource group security-a, whose names differ only in case, so it grants nothing. A few resources are also stale: one points at the deleted DMZ-A VLAN 90, another group still carries the old AD-SERVERS name for what is now IDENTITY-A, and MONITOR-A has no resource at all. None of that changes reach, because only Access-A is granted.
Access-A is enough in practice. Nginx Proxy Manager sits inside that one subnet and fronts every internal application, so the single granted resource covers every published app. With masquerade on, peer traffic leaves the routing peer as docker-network itself, so the gateway sees it inside AlphaSec-Access and applies that zone’s rules. No extra gateway policy was needed.
Note: NetBird gives peers no DNS. A remote peer reaches the proxy by address but cannot resolve the
alphasecunited.comnames, which only the UniFi gateway answers on the LAN. Sohttps://jellyfin.alphasecunited.comfails off the LAN even though the route works. The fix is a NetBird nameserver group foralphasecunited.comthat points at the UniFi resolver.
I validated the path on 2026-07-12: a peer installed the route on its wt0 interface, reached Access-A through the overlay with the right SNI name, and got HTTPS 200. The MGMT-A lockdown deliberately added no NetBird management path, so NetBird does not reach the Proxmox nodes. Both images track latest. The moves to 0.79.0 and v2.93.0 have no change record; the server container last started at 3:00 AM on 2026-09-19, the time the daily container update runs.
The NetBird control plane on docker-network and the routed path into Access-A. Click to enlarge.
Remote control: MeshCentral and RustDesk
Both run on CT 108 docker-blue on Personal-A.
| Tool | Version | Status |
|---|---|---|
| MeshCentral | 1.2.6 | Pilot, deployed 2026-09-12 |
RustDesk (hbbs and hbbr) | 1.1.16 | Incumbent |
MeshCentral’s browser interface and its agents share one HTTPS listener, published through NPM proxy host 29 at mesh.alphasecunited.com since 2026-09-13. Putting it behind the proxy meant agent installs no longer needed a patched script. Six devices were enrolled as of 2026-09-18, including the management server HQ-MGT01, Jedi PC, ubuntu-dev and ObiPC. ObiPC’s agent connected within eight seconds of enrolling, which proved the path from Secure Client that I had until then only reasoned from zone membership.
On the identity network, Allow Identity to MeshCentral admits only HQ-MGT01 and HQ-WS001. The domain controllers are left out on purpose.
RustDesk stays until MeshCentral passes four console tests: access while logged out, Ctrl+Alt+Delete, UAC elevation, and reconnect after a reboot. I also still have to decide on MeshCentral’s local session recording, which is on and is the one part that grows without bound.
Node management and the two-yes rule
A path to a Proxmox node needs two firewalls to say yes:
- The UniFi zone firewall decides whether traffic reaches MGMT-A at all. The broad Internal-to-management allow has been disabled since 2026-07-27. Admin devices are admitted by MAC to the Proxmox admin port group, and
ubuntu-devhas its own explicit policy. - The Proxmox Datacenter firewall on every node admits named IPSets to SSH, the web GUI and the SPICE proxy, then drops everything else aimed at SSH or the GUI.
Who gets in at the Proxmox layer:
| Source | Grant |
|---|---|
Jedi PC, MacBook Air, Pixel, Parrot OS-Mac, ubuntu-dev | SSH, web GUI, SPICE console |
ansible-01 | SSH, web GUI |
monitor-01 and one dashboard on docker-main | Web GUI and API only |
| WireGuard VPN range | MGMT-A |
| The other nodes | SSH and the GUI proxy |
Neither layer is enough on its own, and I have the records to prove it:
- 2026-07-14: UniFi already allowed a web terminal on
docker-mainto reach the nodes, but the Proxmox SSH drop rule blocked it until I added an IPSet. (I removed that exception on 2026-07-27.) - 2026-07-26: UniFi allowed the NUT exporter, then on
security-01, to read the UPS data on Grey and Red, and the port stayed blocked until the Datacenter firewall got matching accepts. - 2026-08-07: The SPICE console needed its port in both the UniFi
Proxmox-Admin-Portsgroup and thepve_adminsrule. - 2026-08-13: Moving development to
ubuntu-devneeded its address inpve_adminsand an explicit UniFi policy, because a client-MAC entry never produced a working UniFi rule for the new guest. - 2026-09-27: Adding Parrot OS-Mac meant one line in
pve_adminsand its MAC on the UniFiDevice Access --> Proxmoxpolicy.
So every change to node access is two changes, and I test from the source host afterwards. A rule that exists on one side and not the other fails silently: the connection just times out.
Open items
- Give NetBird peers DNS for
alphasecunited.com. - Finish the MeshCentral pilot tests, then retire RustDesk.
- Plan the manual Nginx Proxy Manager 2.16.0 upgrade.