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:


Table of Contents

  1. Context / Why This Matters
  2. Implementation / Core Content
  3. Practical Examples
  4. Troubleshooting & Common Pitfalls
  5. 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:

  1. Cloudflare tunnel (cloudflared) on the proxy host: no inbound port-forward at all; origin connects out.
  2. 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

Sources & Related

External references consulted:

Related knowledge-base articles:

Change Log

2026-08-26

Choose Theme

Your selection is saved locally.

Neural Cacophony
Aperture v2
Flux v1
Mosaic Chaos
Nexus v1
Nexus Zest
Prism v2
Synapse