Docs menu Architecture

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.

Updated Source in the repo: Architecture/Access-Paths.md Platforms/Nginx Proxy Manager/ Platforms/Netbird/ Guides/NetBird.md Guides/Nginx-Proxy-Manager.md Infrastructure/Compute/Galaxy/Configuration/Datacenter-Firewall.md

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.

PathWho uses itEntry pointNames
Internal HTTPSLAN clientsNginx Proxy Manager on CT 107 docker-network, Access-A (VLAN 85)*.alphasecunited.com, LAN only
Remote access, WireGuardMe, off the LANUniFi Management Access WireGuard server on the gatewayAddresses, not names
Remote access, meshMe, off the LANSelf-hosted NetBird, routed through docker-networkAddresses, not names
Remote controlMe, at a device’s consoleMeshCentral and RustDesk on CT 108 docker-blue, Personal-A (VLAN 40)mesh.alphasecunited.com
Node managementMy admin devicesProxmox 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 guestNames
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.

Nginx Proxy Manager diagram: the certificate path from the DNS provider API and Let's Encrypt, the local DNS records on the gateway, the proxy on docker-network, and the proxied backends grouped by guest with the firewall allows between them

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.

ElementState
NetworkAlphaSec-Galaxy, built on NetBird’s Networks model
Routing peerdocker-network, with masquerade, the only router on the network
Resources defined13: subnets for nine VLANs plus four Proxmox node hosts
Resources grantedOne: Access-A (VLAN 85), through the policy Peers → Access-A (VLAN 85)
Peer DNSNone 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.com names, which only the UniFi gateway answers on the LAN. So https://jellyfin.alphasecunited.com fails off the LAN even though the route works. The fix is a NetBird nameserver group for alphasecunited.com that 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.

NetBird diagram: remote clients reaching the self-hosted control plane on docker-network through Nginx Proxy Manager, and the routed path from the mesh into Access-A

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.

ToolVersionStatus
MeshCentral1.2.6Pilot, deployed 2026-09-12
RustDesk (hbbs and hbbr)1.1.16Incumbent

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:

  1. 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-dev has its own explicit policy.
  2. 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:

SourceGrant
Jedi PC, MacBook Air, Pixel, Parrot OS-Mac, ubuntu-devSSH, web GUI, SPICE console
ansible-01SSH, web GUI
monitor-01 and one dashboard on docker-mainWeb GUI and API only
WireGuard VPN rangeMGMT-A
The other nodesSSH 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-main to 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-Ports group and the pve_admins rule.
  • 2026-08-13: Moving development to ubuntu-dev needed its address in pve_admins and 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_admins and its MAC on the UniFi Device Access --> Proxmox policy.

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.

Records

Written from the public Homelab repository on GitHub, which records the lab's changes, incidents and current state.