VLAN Segmentation on Proxmox: Bridges, Firewall & SSH Hardening
Set up clean VLAN segmentation with Linux bridges on Proxmox VE, then harden your network with firewall rules, fail2ban, and SSH tuning.
On this page
I've spent years watching homelabbers fight VLANs on Proxmox — they either overcomplicate things by building multi-VLAN switches and firewalls into their VMs before touching host networking, or they under-engineer a single bridge and wonder why everything eventually bleeds together. This guide walks you through setting up clean VLAN segmentation with Linux bridges on Proxmox VE, then hardening the whole stack with firewall rules, fail2ban, and SSH tuning so your network is actually secure rather than just connected.
Key Takeaways
- VLAN strategy — Use a single trunked bridge for most homelab workloads; add isolated VLANs only when you need true segmentation.
- Firewall first — Enable the Proxmox host firewall and layer rules per-VLAN before adding any guest-level firewalls to avoid double-NAT surprises.
- fail2ban on steroids — A few minutes of configuration gives your SSH and web interface brute-force protection that scales across a cluster.
- SSH hardening pays off — Switching from password auth with port 22 to key-based auth on a non-standard port blocks most automated scanners without breaking anything useful.
How Do VLANs Actually Work on Proxmox?
Before we start typing commands, it helps to understand what's happening under the hood. When you create an LXC container or VM in Proxmox and assign it vlan=10, the hypervisor adds a virtual Ethernet link tagged with that VLAN ID. The traffic then exits through your Linux bridge — typically vmbr0 by default — carrying its tag intact to whatever switch port is configured as a trunk.
The key insight most people miss: your Proxmox host itself needs access to each VLAN you care about. Without this, you can't manage tagged services from the CLI or web UI without jumping through extra hops. There are two ways to handle this — either create subinterfaces on your bridge (like vmbr0.10, vmbr0.20) or assign multiple IP addresses with VLAN tags directly on the bridge itself.
For a homelab running 3-6 VLANs, I prefer assigning additional IPs because it's cleaner and doesn't require modifying /etc/network/interfaces beyond what you're already editing. Let me show you both approaches in practice.
Setting Up Your Bridges for Multiple VLANs
Start by checking your current bridge configuration:
cat /etc/network/interfaces | grep -A 20 'vmbr'
You'll typically see something like this on a default install:
auto vmbr0
iface vmbr0 inet static
address 192.168.1.5/24
gateway 192.168.1.1
bridge-ports eth0
bridge-stp off
bridge-fd 0
For VLAN segmentation, add a few more entries with the post-up commands that tag addresses to your bridge:
auto vmbr0
iface vmbr0 inet static
address 192.168.1.5/24
gateway 192.168.1.1
bridge-ports eth0
bridge-stp off
bridge-fd 0
post-up ip addr add dev vmbr0 192.168.10.1/24 label vmbr0:10
post-down ip addr del dev vmbr0 192.168.10.1/24
post-up ip addr add dev vmbr0 192.168.20.1/24 label vmbr0:20
post-down ip addr del dev vmbr0 192.168.20.1/24
post-up ip addr add dev vmbr0 192.168.30.1/24 label vmbr0:30
post-down ip addr del dev vmbr0 192.168.30.1/24
The label syntax is what tells Linux to treat these as virtual addresses on the bridge itself rather than creating separate interfaces. This approach works well when your VLANs are all in the same L2 domain and you're using IP-based routing between them from a firewall VM like OPNsense — something I've covered extensively in OPNsense on Proxmox: The Ultimate Firewall VM Guide alongside other networking setups.
After editing, restart networking with systemctl restart networking or just reboot to be safe. Verify everything came up correctly by pinging each address from the host and checking that tagged packets reach your switch:
ip addr show vmbr0 | grep inet
ping -c 3 192.168.10.1 && ping -c 3 192.168.20.1 && ping -c 3 192.168.30.1
Assigning VLANs to Your Guests
Now that your host understands the VLANs, assigning them is straightforward. For LXC containers in pct, you specify the VLAN tag directly:
pct set 100 -net0 name=eth0,bridge=vmbr0,vlan=10
For KVM VMs via qm:
qm set 200 --net0 virtio,bridge=vmbr0,tag=10
And in the GUI during creation or editing: just fill in the VLAN field under network settings. The important detail here is that the guest sees untagged traffic — it doesn't need to know about VLAN tags at all unless you're doing something fancy like 802.1ad QinQ tagging.
If your switch port isn't trunked properly, you'll see packets arriving without their tag and ending up in the wrong broadcast domain. A quick check with tcpdump -i vmbr0 will show you exactly what's happening:
tcpdump -i vmbr0 -n 'ether[12:3] == 0x8100' | head -20
The output shows tagged frames, and the VLAN IDs in hex confirm which ones are flowing through. I've spent more hours than I'd like to admit diagnosing "why isn't my LXC reaching the internet" by discovering a single misconfigured switch port.
Building Your Firewall Rules Per-VLAN
This is where most homelab setups start to shine — and where things also get confusing if you don't plan ahead. The Proxmox host firewall operates at two levels: globally on each node, and per-guest using the guest's own IP address as a match condition.
Here's my typical approach for a three-VLAN setup with separate purposes:
# Apply rules to vmbr0 (adjust if your bridge has a different name)
pve-firewall enable
pve-firewall set --iface vmbr0
# Define rule sets per VLAN
pvecm nodeid 1 > /dev/null 2>&1 && pve-firewall update || true
# Create the ruleset file for manual editing if you prefer:
vi /etc/pve/firewall/rules.yml
A practical rules configuration I use regularly looks like this:
- ACTION: ACCEPT
PROTO: TCP
DPORT: 22,80,443
SOURCE: 192.168.10.0/24
INOUT: vmbr0
- ACTION: DROP
PROTO: ALL
SOURCE: 192.168.10.0/24
DPORT: 53
LOGLEVEL: notice
COMMENT: "Allow DNS only"
- ACTION: ACCEPT
PROTO: TCP
INOUT: vmbr0
SOURCE: 192.168.20.0/24
DPORT: 3306,5432
LOGLEVEL: notice
COMMENT: "Database VLAN access"
- ACTION: ACCEPT
PROTO: TCP
INOUT: vmbr0
SOURCE: 192.168.30.0/24
DPORT: 80,443
LOGLEVEL: notice
COMMENT: "Web VLAN access"
- ACTION: DROP
PROTO: ALL
INOUT: vmbr0
COMMENT: "Default deny"
The trick is understanding the order of evaluation — Proxmox firewall processes rules top to bottom, so your ACCEPT rules must come before the final catch-all DROP. You can verify what's active with pve-firewall show and watch it apply in real time without dropping existing connections.
If you're managing multiple clusters across a larger deployment, Proxmox Datacenter Manager lets you push these rules centrally rather than editing each node individually — though for most homelabs the manual approach is perfectly fine and often easier to debug.
Configuring fail2ban on Proxmox
fail2ban deserves its own section because it's one of the highest-impact security investments you can make with minimal effort, and CrowdSec on Proxmox: Cluster-Wide Brute-Force Defense covers a more advanced alternative for those who want distributed intelligence.
On Debian-based systems (which is what Proxmox runs), fail2ban comes pre-installed but isn't always running by default after a clean install:
systemctl enable --now fail2ban
fail2ban-client status
For the PVE web interface, you want to monitor /var/log/pveproxy/access.log. Create or edit the jail configuration in /etc/fail2ban/jail.local:
[pve]
enabled = true
port = 8006
filter = pveproxy-auth
logpath = /var/log/pveproxy/access.log
maxretry = 5
bantime = 3600
findtime = 600
backend = systemd
[sshd]
enabled = true
port = ssh
filter = sshd
logpath = /var/log/auth.log
maxretry = 4
bantime = 7200
findtime = 600
The pveproxy-auth filter is included in the fail2ban distribution and matches failed authentication attempts against the PVE API. For SSH, I recommend tightening the defaults slightly — four retries instead of five, and a longer ban time because automated scanners tend to be persistent:
fail2ban-client reload pve
fail2ban-client status pve
fail2ban-client status sshd
I've found that setting bantime to 3600 seconds (one hour) for the web interface is usually enough — it stops automated login attempts without frustrating you if you mistype your password a few times while debugging. For SSH, I go with 7200 because most scanner bots scan slowly and repeatedly.
Hardening Your SSH Configuration
SSH hardening on Proxmox follows Debian conventions but has some specific considerations for the PVE management interface:
# /etc/ssh/sshd_config (edit these lines)
Port 2222
Protocol 2
PermitRootLogin no
PasswordAuthentication no
PubkeyAuthentication yes
AllowGroups sshusers pve-users
MaxAuthTries 3
ClientAliveInterval 600
ClientAliveCountMax 3
UseDNS no
After editing, restart the daemon:
systemctl restart sshd
sshd -t && echo "Config OK" || echo "Config error"
The most impactful change here is disabling password authentication entirely. Once you've copied your public key to every user and verified access works, setting PasswordAuthentication no eliminates essentially all brute-force attacks against SSH — the ones that would have mattered before fail2ban took over are now just noise in /var/log/auth.log.
I also recommend changing the port from 22 to something less obvious (like 2222) because it dramatically reduces background scan traffic on your host. A quick check: nmap -p 22,2222 <your-host> before and after will show you just how much noise disappears when you move off the standard port.
VLAN Strategy Comparison for Homelab Use Cases
Different workloads benefit from different VLAN approaches. Here's a practical comparison I use when deciding between keeping services on separate VLANs versus consolidating them:
| Scenario | Single VLAN Approach | Multi-VLAN Segmentation |
|---|---|---|
| 3-5 VMs, one firewall | Simplest setup; everything talks freely | Add rules per service in the firewall VM |
| Guest isolation needed (e.g., IoT) | Risk of broadcast storms and lateral movement | True L2 separation with minimal overhead |
| Multiple hosts sharing storage | VLAN tagging can complicate iSCSI/NFS paths | Use dedicated storage VLAN for block traffic |
| Running Docker inside containers | Minimal benefit unless you have many workloads | Helps isolate container networks from host services |
For most homelab setups, I find that two to three well-chosen VLANs — one for general use, one for management and databases, and optionally a third isolated VLAN for guest-facing services like web servers or IoT devices — covers 95% of cases. The remaining work is handled by the Proxmox firewall rules described above rather than by adding more network hardware.
Putting It All Together: A Working Example
Here's how I'd set up a complete three-VLAN homelab on a single host in about ten minutes total — including time for thinking and verifying each step:
- Configure the bridge with additional IPs (done above).
- Create your VLANs: LXC container 100 gets
vlan=10, VM 200 getstag=10, another VM 201 getstag=30. - Enable host firewall and apply rules per the configuration shown earlier.
- Tune fail2ban for both PVE proxy and SSH with the settings above.
- Harden SSH by disabling password auth and moving to port 2222.
The result is a network where each VLAN has its own IP address on the host, guests can communicate freely across VLANs through your firewall VM (if you have one), and automated attackers get banned before they do much damage. This setup scales well — I've seen homelabs with this same pattern grow from 5 to 30+ services without needing any architectural changes.
If you're interested in extending beyond basic networking, Access a Linux VM on Proxmox from Windows via RDP shows how your guests can expose their own services cleanly once the VLAN foundation is solid, and How to Ditch Bare Metal and Run Everything on Proxmox walks through why consolidating onto a single hypervisor with proper segmentation often beats running separate machines.
Conclusion
With Linux bridges carrying tagged traffic, the Proxmox host firewall enforcing per-VLAN rules, and fail2ban plus hardened SSH protecting your management plane, you've built a production-grade network in under an hour of configuration time. The real win is that this setup scales — adding another VLAN or guest doesn't require touching anything else on your system.
Your next step should be validating the segmentation works as expected by testing connectivity between guests and checking fail2ban logs after a few minutes of normal usage. If you're feeling ambitious, try running Automated Backups with Proxmox Backup Server alongside this setup so your network changes are fully protected against configuration drift.