Network Segmentation - Implementing Mgmt, Services and Public Zones
Status: Active
Last Updated: 2026-08-26
Category: Networking - Phase 2: Services
Prerequisites: virtual-networks, firewalls-nftables, network-segmentation-principles
Time: 3 hours
Tags: segmentation, zones, nftables, vlans, zero-trust, homelab
Summary
Turn segmentation theory into a working zone layout for fogserv: management, services, public-entry and untrusted zones with an explicit policy matrix, enforced by nftables rules on the router. This article is the networking-side implementation companion to the security-side principles article.
๐ฏ What You'll Learn
By the end of this article, you'll be able to:
- โ Map fleet hosts to zones with concrete subnets
- โ Write the allow-matrix as enforceable nftables forward rules
- โ Place the public entry point so compromise can't traverse zones
- โ Audit that segmentation actually holds
Table of Contents
- Context / Why This Matters
- Implementation / Core Content
- Practical Examples
- Troubleshooting & Common Pitfalls
- Next Steps / Ops Actions
Context / Why This Matters
The concepts โ why zones exist, least privilege, default deny between trust levels โ are covered in Network Segmentation Principles; read that first if the "why" is new to you. This article answers "what exactly do we run": which VLAN, which subnet, which firewall rules, per host. It builds directly on the VLAN/bridge mechanics from virtual-networks.
Implementation / Core Content
The fogserv zone map
| Zone | Subnet | Contains | Internet? |
|---|---|---|---|
| mgmt | 192.168.10.0/24 (VLAN 10) | Hypervisors, admin workstations, switch/router UIs | Yes |
| services | 192.168.20.0/24 (VLAN 20) | App containers/VMs behind reverse proxy | Outbound only |
| public | 192.168.21.0/24 (VLAN 20 tagged) | Only reverse-proxy hosts reachable from WAN via Cloudflare tunnel/port-forward | Inbound 80/443 only |
| iot | 192.168.30.0/24 (VLAN 30) | Cameras, smart devices | Outbound only |
| guest | 192.168.40.0/24 (VLAN 40) | Visitor devices | Internet only |
Key rule of thumb: only one host class accepts inbound from the internet โ the reverse-proxy tier. Everything else is reached through it or through WireGuard (wireguard-setup).
Policy matrix (default deny elsewhere)
| From \ To | mgmt | services | public | iot | guest | internet |
|---|---|---|---|---|---|---|
| mgmt | โ | allow (admin ports) | allow | allow | allow | allow |
| services | deny | allow | deny* | deny | deny | outbound allow |
| public | deny | allow (proxy backends only) | โ | deny | deny | outbound allow |
| iot | deny | specific NVR/DNS only | deny | allow | deny | outbound allow |
| guest | deny | deny | deny | deny | isolated | internet only |
* exception: proxy โ its declared upstream ports.
Enforcing it with nftables on the router
#!/usr/sbin/nft -f
# /etc/nftables.d/zones.nft
table inet zones {
set mgmt = { 192.168.10.0/24 }
set svcs = { 192.168.20.0/24 }
set iot = { 192.168.30.0/24 }
set guest = { 192.168.40.0/24 }
chain forward {
type filter hook forward priority 0; policy drop;
# Stateful baseline
ct state established,related accept
# mgmt -> everything (admin)
ip saddr @mgmt accept
# services/public -> internet only (no east-west into mgmt/iot/guest)
ip saddr @svcs oifname "wan0" accept
ip saddr @iot oifname "wan0" accept
# iot may reach NVR + DNS on services only
ip saddr @iot ip daddr 192.168.20.50 tcp dport 554 accept # RTSP to NVR
ip saddr @iot ip daddr 192.168.20.2 udp dport 53 accept # dnsmasq
ip saddr @iot ip daddr 192.168.20.2 tcp dport 53 accept
# guest: internet only; block all RFC1918 destinations
ip saddr @guest ip daddr { 192.168.0.0/16, 10.0.0.0/8, 172.16.0.0/12 } drop
ip saddr @guest oifname "wan0" accept
# explicit logging of denied inter-zone traffic (rate-limited)
limit rate 5/second log prefix "zones-drop: " flags all counter
}
}
sudo nft -c -f /etc/nftables.d/zones.nft && sudo systemctl reload nftables
Host-level defense in depth
Segmentation at the router is necessary but not sufficient โ each host also runs ufw (ufw-firewall) or nftables (firewalls-nftables) allowing only expected sources. Example: node_exporter on every services host allows 192.168.10.0/24 (Prometheus) plus nothing else.
Public entry design
Two supported shapes:
- Cloudflare tunnel (cloudflared) on the proxy host: no inbound port-forward at all; origin connects out.
- Port-forward 80/443 on the router to the proxy host only, ideally restricted to Cloudflare IP ranges.
Both are documented in cloudflare-dns; TLS details in tls-configuration.
Practical Examples
Audit: what can services-zone hosts actually reach?
ssh 192.168.20.30
curl -m3 http://192.168.10.2 # expect timeout (denied)
curl -m3 https://example.com -o /dev/null -w '%{http_code}\n' # expect 200
Verify a guest client cannot see the LAN
From the guest SSID: nmap -sn 192.168.20.0/24 should return zero live hosts.
Trace a dropped packet
Watch the log line while reproducing:
sudo journalctl -k -f | grep zones-drop
# zones-drop: ... SRC=192.168.30.44 DST=192.168.20.15 PROTO=TCP DPT=445 ...
Troubleshooting & Common Pitfalls
| Problem | Cause | Fix |
|---|---|---|
| Legit service broke after zoning | Undocumented flow not in matrix | Add an explicit narrow allow, update the matrix doc |
| Everything works but nothing is logged | Log statement after broad accept | Order rules: drops/log before blanket accepts |
| IoT cameras offline | DNS/NVR exceptions missing | Add targeted udp/tcp 53 + NVR-port rules |
| VPN clients can't reach services | Tunnel subnet absent from matrix | Allow wg transit range into services explicitly |
| Proxy host compromised pivot fear | Flat trust between public & services | Keep public tier separate; proxy reaches only declared upstream ports |
| Rules lost after reboot | File not included/enabled | Verify include in nftables.conf and unit enabled |
Next Steps / Ops Actions
- Read the security rationale: network-segmentation principles.
- Apply host firewalls fleet-wide: ufw-firewall.
- Monitor cross-zone drops as a signal: monitoring-networks.
Sources & Related
External references consulted:
- https://wiki.nftables.org/wiki-nftables/index.php/Configuring_chains
- https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/
Related knowledge-base articles:
Change Log
2026-08-26
- Initial creation by KB build session.