Virtual Networks - VLANs, Bridges and Overlays for the Homelab
Status: Active
Last Updated: 2026-08-26
Category: Networking - Phase 2: Services
Prerequisites: ip-addressing-subnets, network-topologies, docker-networking
Time: 3 hours
Tags: vlan, bridge, netplan, proxmox, segmentation, overlay-networks
Summary
Segment the fogserv LAN with VLANs on a Linux bridge, tag traffic into Proxmox VMs and containers, and understand when an overlay network (WireGuard/VXLAN) beats physical VLANs. Concrete netplan + Proxmox examples using our 192.168.0.0/16 allocation.
๐ฏ What You'll Learn
By the end of this article, you'll be able to:
- โ Build a VLAN-aware Linux bridge under netplan
- โ Tag VMs/containers onto specific VLANs in Proxmox
- โ Route between VLANs deliberately (firewall-on-a-stick)
- โ Decide between VLANs and overlay networks
Table of Contents
- Context / Why This Matters
- Implementation / Core Content
- Practical Examples
- Troubleshooting & Common Pitfalls
- Next Steps / Ops Actions
Context / Why This Matters
One flat LAN is how homelabs rot: your IP camera ends up routable from the media PC, and every compromised container sees everything. Virtual networks let one physical switch and a handful of NICs behave like many isolated segments โ management, services, IoT, guests โ with routing controlled at one point. The zone policy is covered in network-segmentation; this article is the L2/L3 mechanics.
Implementation / Core Content
Our VLAN plan
| VLAN | Name | Subnet | Purpose |
|---|---|---|---|
| 10 | mgmt | 192.168.10.0/24 | Host admin, SSH, IPMI, hypervisors |
| 20 | services | 192.168.20.0/24 | Containers/VMs behind reverse proxy |
| 30 | iot | 192.168.30.0/24 | Cameras, smart devices |
| 40 | guest | 192.168.40.0/24 | Untrusted clients |
VLAN-aware bridge on a Ubuntu host (netplan)
/etc/netplan/01-bridges.yaml:
network:
version: 2
ethernets:
enp3s0:
dhcp4: no
bridges:
br0:
interfaces: [enp3s0]
addresses: [192.168.10.2/24]
routes:
- to: default
via: 192.168.10.1
nameservers:
addresses: [192.168.20.2]
# Trunk: accept tagged frames for all VLANs
The switch port facing this host must be a trunk carrying VLANs 10/20/30/40 (untagged/native = 10 for host access). Then attach workloads to tagged subinterfaces or let the hypervisor tag:
# A second host NIC dedicated to services traffic
vlans:
enp3s0.20:
id: 20
link: enp3s0
addresses: [192.168.20.2/24]
sudo netplan try # rolls back automatically if you lose connectivity
Proxmox example
/etc/network/interfaces:
auto vmbr0
iface vmbr0 inet static
address 192.168.10.5/24
gateway 192.168.10.1
bridge-ports enp3s0
bridge-stp off
bridge-fd 0
bridge-vlan-aware yes
bridge-vids 10 20 30 40
Per-VM NIC: set VLAN Tag: 20 in the hardware dialog (or net0: virtio=XX:XX...,bridge=vmbr0,tag=20). Untagged (tag absent) lands in the native VLAN.
Docker + VLANs
Two options; pick per workload:
# Option A: macvlan โ container gets its own LAN IP on the tagged VLAN
docker network create -d macvlan \
--subnet=192.168.20.0/24 --gateway=192.168.20.1 \
-o parent=enp3s0.20 services_net
Option B: keep containers on a normal docker bridge and expose via the host's VLAN interface / reverse proxy โ usually simpler, see docker-networking.
Routing between VLANs ("router on a stick")
Inter-VLAN routing happens at the router/firewall (or an L3 switch). The essential policy shape:
mgmt(10) -> services(20): allow (admin)
services(20) -> mgmt(10): deny (default)
iot(30) -> anything internal: deny; internet only
guest(40) -> internet only, client-isolated
Implement those rules in nftables (firewalls-nftables) or ufw (ufw-firewall) on the router.
Overlay vs VLAN
| Concern | VLAN | Overlay (WG/VXLAN) |
|---|---|---|
| Scope | One L2 domain, switches must carry tags | Any routed path, even across WAN |
| Setup | Switch + host config | Software only |
| Encryption | None | Yes |
| Best for | Permanent local segmentation | Connecting sites, ephemeral clusters |
For cross-site links use WireGuard tunnels rather than stretching VLANs over the internet โ see wireguard-setup.
Practical Examples
Prove tagging works
# From a host on the trunk:
sudo ip link add link enp3s0 name enp3s0.30 type vlan id 30
sudo ip addr add 192.168.30.9/24 dev enp3s0.30
ping -c2 192.168.30.1 && sudo ip link del enp3s0.30
Check what the switch sees
On the managed switch: verify the port shows tagged members 20,30,40 and untagged 10 for the hypervisor uplink. Mismatch here causes ~90% of "VM has no network" cases.
Isolate an IoT device
Put the camera on VLAN 30, then on the router allow only its NVR destination and drop everything else internal โ done with two nftables rules on the forward chain.
Troubleshooting & Common Pitfalls
| Problem | Cause | Fix |
|---|---|---|
| New VM has no connectivity | Switch port not trunking that VLAN | Add tagged membership on switch port |
| Works until reboot, then gone | Ad-hoc ip link changes not persisted |
Move config into netplan/interfaces file |
Can't reach host after netplan apply over SSH |
Bridge re-created mid-session | Use netplan try, or run from console |
| MTU black holes for big packets | Overlays/VLAN tags eat 4+ bytes | Set MTU 1500 end-to-end minus overhead consistently |
| DHCP offers on two VLANs at once | DHCP relay missing / wrong native VLAN | One DHCP server per subnet; configure relay properly |
| Container can't reach its own published port (macvlan) | Kernel blocks hairpin to parent iface | Access via separate bridge network from the host |
Next Steps / Ops Actions
- Write the actual inter-zone policy matrix: network-segmentation.
- Enforce it with nftables: firewalls-nftables.
- Link sites together without stretching L2: wireguard-setup.
Sources & Related
External references consulted:
- https://netplan.readthedocs.io/en/stable/netplan-yaml/
- https://pve.proxmox.com/wiki/Network_Configuration
Related knowledge-base articles:
Change Log
2026-08-26
- Initial creation by KB build session.