Homelab VLANs on Proxmox: Segmentation, fail2ban & SSH Hardening
Set up VLAN segmentation with Linux bridges, protect your homelab from brute-force attacks using fail2ban, and harden SSH on Proxmox for a stable infrastructure.
On this page
VLANs on a homelab are often treated as optional decoration — until you need to run Home Assistant, Jellyfin, Kubernetes, and your database without everything talking to each other at once. Setting up proper network segmentation with Linux bridges, fail2ban protection, SSH hardening, and Proxmox firewall rules turns that jumble into a clean, reliable infrastructure in about an hour.
Key Takeaways
- VLAN isolation prevents containerized services from silently discovering each other and breaking things when you restart them together
- fail2ban on the host catches SSH brute-force attempts before they hit your VMs at all — no agent needed per guest
- Proxmox firewall rules are evaluated in order, so placement matters as much as what you write
- Linux bridges with VLAN tagging give you proper Layer 3 separation without sacrificing a single physical NIC
Why Homelabs Need More Than One VLAN
Most homelab guides show a single vmbr0 bridge and call it done. That works when you have one VM, maybe two LXCs, and nothing talks to each other anyway. But once you start running services that depend on each other — or worse, ones that accidentally collide with the same port numbers — everything becomes brittle.
When I first set up my homelab (see Build a Private Cloud at Home with Proxmox VE for context), I kept every VM and LXC on vmbr0 with no VLAN tags. It was fine until I added Nextcloud, then Plex, then K3s — all of which wanted port 80, or tried to discover each other via mDNS, or had their backup jobs hammering the same storage path at midnight.
The fix wasn't more hardware. It was network segmentation: putting services into their own VLANs so they can only see what they're supposed to see. This is different from using separate physical NICs — you get isolation without needing a switch port for every service. The tradeoff is that your initial setup takes longer and requires a few extra config edits, but the long-term payoff shows up as fewer "why did X stop working when I restarted Y?" moments.
Configuring Linux Bridges with VLAN Tags on Proxmox Nodes
Before writing any firewall rules, you need bridges set up correctly. The Configuring VLANs on Proxmox with Linux Bridges article walks through the basics in detail, but here's the practical part that most people miss: how to tag individual VM interfaces rather than tagging everything at once.
On a typical homelab node, I use this setup for vmbr0:
auto vmbr0
iface vmbr0 inet static
address 192.168.1.2/24
gateway 192.168.1.1
bridge-ports enp3s0
bridge-stp off
bridge-fd 0
# VLAN subinterfaces on the physical port
auto vmbr0.10
iface vmbr0.10 inet manual
vlan-raw-device vmbr0
auto vmbr0.20
iface vmbr0.20 inet manual
vlan-raw-device vmbr0
auto vmbr0.30
iface vmbr0.30 inet manual
vlan-raw-device vmbr0
This gives you three untagged VLANs on top of your primary bridge — one for management traffic (10), one for VM workloads (20), and one for containers (30). Each subinterface is manual so it doesn't try to acquire an IP address; the actual IPs live inside the guest VMs or LXCs.
The gotcha here: if your switch port isn't configured as a trunk, you need to pick one native VLAN and tag only that one in Proxmox. On most managed switches (UniFi, Netgear GS308T, etc.) this is VLAN 1 by default — but I prefer tagging everything explicitly so the setup doesn't break when someone accidentally reconfigures a switch port later.
Setting Up fail2ban for Cluster-Wide Brute-Force Defense
fail2ban runs on your Proxmox host and protects all of your services from one place. If you have 40 VMs, each with its own SSH daemon, you only need one instance scanning /var/log/auth.log. This is a key advantage over CrowdSec on Proxmox: Cluster-Wide Brute-Force Defense — fail2ban uses fewer resources and doesn't require an external agent, though CrowdSec's shared blocklist reputation can be more aggressive against persistent attackers.
Install it with:
apt update && apt install -y fail2ban
Then configure the jail for SSH in /etc/fail2ban/jail.local:
[DEFAULT]
bantime = 1h
findtime = 5m
maxretry = 3
backend = auto
usedns = warn
[sshd]
enabled = true
port = ssh
filter = sshd
logpath = /var/log/auth.log
action = iptables-multiport[name=SSHD, port="ssh", protocol=tcp]
The bantime of one hour is my standard recommendation — long enough to matter for persistent attackers but short enough that legitimate users who get locked out by a misconfigured backup script won't be stuck forever. The maxretry = 3 catches most brute-force attempts before they escalate into password-guessing storms.
Verify it's working:
fail2ban-client status sshd
You should see output like:
Status for the jail: sshd
|- Filter
| |- Currently failed: 0
| |- Total failed: 147
`- Action
|- Currently banned: 3
|- Total banned: 28
`- Banned IP list: 203.0.113.45 198.51.100.12 45.33.32.156
For more advanced setups, you can also protect the Proxmox web UI itself by adding a pve jail that watches /var/log/pveproxy/access.log. This prevents attackers from hammering your admin panel even when they're not trying SSH directly.
Hardening Your SSH Configuration on the Host
fail2ban catches repeated bad attempts, but hardening SSH at the config level reduces what fail2ban needs to deal with in the first place. The key edits go into /etc/ssh/sshd_config on your Proxmox host:
Port 22
PermitRootLogin no
PasswordAuthentication no
PubkeyAuthentication yes
AuthorizedKeysFile .ssh/authorized_keys
X11Forwarding no
AllowTcpForwarding no
MaxAuthTries 3
ClientAliveInterval 300
ClientAliveCountMax 2
Setting PermitRootLogin no is the single most impactful change. If someone guesses your root password, they're in — and with root access to Proxmox, you've lost. With key-based auth only, even a successful brute-force attack against passwords does nothing unless the attacker also has your private key.
I recommend generating an Ed25519 key for each admin user:
ssh-keygen -t ed25519 -C "admin@homelab"
ssh-copy-id root@<proxmox-ip>
Ed25519 keys are faster to authenticate than RSA and produce a 68-character fingerprint that's easy to verify visually. The tradeoff is older OpenSSH versions (<7.0) don't support them natively, but Proxmox VE 8.x ships with OpenSSH 9.x so this isn't an issue in practice.
Adding Firewall Rules Between VLANs on the Host
Proxmox's built-in firewall (not to be confused with container firewalls or iptables rules) works at the node level and is evaluated per-VM/LXC based on their network settings. To use it, enable it cluster-wide:
pvecm set -firewall 1
systemctl restart pve-firewall
Then define your VLAN-based firewall policy in /etc/pve/firewall.fw. Here's a practical example for the three-VLAN setup above:
[DEFAULT]
policy = allow
log_level = warn
[rules]
# Allow all management traffic on vmbr0.10 (VLAN 10)
INCOMING:ALLOW,vmbr0.10,-p tcp -s 192.168.10.0/24 --dport 22
INCOMING:ALLOW,vmbr0.10,-p tcp -s 192.168.10.0/24 --dport 8006
# VM workloads can talk to VLAN 30 (containers) but not directly to the internet
OUTGOING:ALLOW,vmbr0.20,-p tcp -d 192.168.30.0/24 --sport 80-443
INCOMING:DENY,vmbr0.20
# Containers can reach outside but not VMs on VLAN 20
OUTGOING:ALLOW,vmbr0.30,-p tcp -d 192.168.20.0/24 --sport 80-443
INCOMING:DENY,vmbr0.30
# Block all other incoming traffic
INCOMING:DENY
The rules are evaluated in order — the first match wins. This means you can be specific about what gets through and rely on a final DENY to catch everything else. If you need more complex logic (like rate limiting or stateful tracking), fall back to raw iptables or nftables, but for most homelab setups this is sufficient.
VLAN Segmentation Patterns That Actually Work in Homelabs
Different services benefit from different isolation patterns. Here's a comparison of the approaches I've tested across multiple homelab deployments:
| Pattern | Best For | Pros | Cons |
|---|---|---|---|
| Single bridge, tagged VMs (one VLAN per service) | Up to ~15 services, managed switch | Simple routing rules, easy debugging | Each extra VLAN consumes a host IP and adds config complexity |
| Flat network with container-level isolation | Docker/Podman-heavy setups | No tagging needed; LXC devices handle the rest | Services can still discover each other via broadcast/mDNS |
| Dedicated bridge per workload group (VMs vs LXCs) | Mixed VM/LXC workloads, GPU passthrough hosts | Clear separation of concerns; easier hardware assignment | Requires more VLAN IDs and switch port configuration |
| Dual-NIC setup with LACP bonding | High-throughput VMs (NAS, databases) | Near-10 Gbps throughput to the host | Uses two physical ports; single point of failure on one NIC |
For most homelabs running a mix of Kubernetes clusters, media servers, and virtualized services, I recommend starting with pattern #3: separate bridge per workload group. It gives you enough isolation without forcing every service into its own VLAN — which is where things get expensive in terms of config overhead and switch port usage.
Putting It All Together: A Working Example
To see how this works end-to-end, let me walk through a concrete scenario. I have five VMs on vmbr0.20 (VLAN 20): a Home Assistant node at 192.168.20.10, Jellyfin at .20, K3s master at .30, and two backup VMs for Automated Backups with Proxmox Backup Server at .40 and .50.
Home Assistant needs to reach the internet (for updates) and communicate with my K3s cluster, but I don't want it accidentally scanning other VMs. Jellyfin should only be accessible from VLAN 10 management traffic — no direct LAN access for security. The backup servers need full connectivity since they talk to multiple targets.
The configuration is straightforward: set each LXC/VM's network interface with the appropriate bridge and tag, apply firewall rules based on source IP, and let fail2ban handle any brute-force attempts from outside. I've also added a cron job that restarts fail2ban once per week to clear stale bans — this caught me when a misconfigured backup script tried 50 SSH connections in ten minutes and temporarily locked out my own home IP for an hour.
If you're running Cloudflare Tunnel on Proxmox for Zero-Trust Remote Access alongside this setup, the firewall rules help prevent tunnel traffic from accidentally bypassing your VLAN segmentation. Make sure to add a rule that allows Cloudflare's IP ranges through while keeping other external traffic blocked:
INCOMING:ALLOW,-p tcp -s 162.158.0.0/15 --dport 443
INCOMING:ALLOW,-p tcp -s 104.16.0.0/12 --dport 443
Conclusion
Setting up VLAN segmentation, fail2ban protection, and SSH hardening on your Proxmox host takes about an hour but dramatically reduces the number of "surprise" issues that creep into homelabs over time. The key insight is that network isolation isn't just a security concern — it's also about predictability. When you know exactly which services can talk to each other, debugging becomes much simpler and your infrastructure feels more stable even when things change.
The next step depends on where you are: if you're still deciding how many VLANs you need, start with three (management, VM workloads, container workloads) and expand from there. If you already have bridges but haven't added firewall rules or fail2ban yet, do those first — they give the most bang for your effort. And once you've got a working setup, consider Automate Proxmox VE with Ansible Full VM Playbooks to make these configurations reproducible and version-controlled.