LUNAROPS · OPERATIONAL UPLINK 100% UPTIME 1,247d POSTS 893 JEFF.MOON@LUNAROPS.DEV UTC --:--:--

Network Segmentation with VLANs: Isolating Traffic on Your Homelab and Beyond

vlansnetworkingsecurityhomelabpfsenseopnsenseswitchessegmentation

A flat network — where every device can talk to every other device — is fine when you have three things plugged in. Once you add smart TVs, IoT sensors, work laptops, servers, a NAS, and guest devices, a flat network becomes a liability. If any device is compromised, an attacker has unrestricted access to everything else. VLANs are the solution: a way to logically divide one physical network into multiple isolated segments without buying extra switches.

This guide covers VLANs from first principles through practical configuration on managed switches, pfSense/OPNsense, and Linux.


What a VLAN Is (and What It Isn’t)

A VLAN (Virtual Local Area Network) is a layer-2 broadcast domain that’s logically separated from other VLANs. Devices in VLAN 10 can’t talk to devices in VLAN 20 unless traffic passes through a layer-3 device (a router or firewall) that explicitly permits it.

The mechanism is simple: Ethernet frames are tagged with a 4-byte 802.1Q header that includes a 12-bit VLAN ID (1–4094). Switches read these tags and either:

  • Forward the frame to ports that belong to the same VLAN
  • Drop the frame if the destination port doesn’t belong to that VLAN
Normal Ethernet Frame:
┌──────────┬──────────┬────────┬─────────┐
│ Dst MAC  │ Src MAC  │ EtherType │ Payload │
└──────────┴──────────┴────────┴─────────┘

802.1Q Tagged Frame:
┌──────────┬──────────┬──────────┬────────┬─────────┐
│ Dst MAC  │ Src MAC  │ 802.1Q   │ EtherType │ Payload │
│          │          │ Tag (4B) │        │         │
└──────────┴──────────┴──────────┴────────┴─────────┘
                          │
                     ┌────┴────┐
                     │ VLAN ID │  (12 bits = VIDs 1–4094)
                     │ PCP     │  (3 bits = priority)
                     │ DEI     │  (1 bit = drop eligible)
                     └─────────┘

VLANs vs Physical Separation

VLANs are not as secure as physical separation. A misconfigured switch, a VLAN hopping attack (double-tagging), or a vulnerability in the switch firmware can theoretically bridge VLANs. For the most sensitive isolation (payment systems, industrial control networks) use physical separation. For homelab, SMB, and typical enterprise security, VLANs provide excellent segmentation when properly configured.


Port Types: Access vs Trunk

Understanding these two port modes is fundamental.

Access Port

An access port belongs to exactly one VLAN. Frames entering an access port are untagged (the device plugged in doesn’t know about VLANs). The switch assigns the configured VLAN ID internally, and strips the tag before forwarding to the destination access port.

PC ──────── [Access Port, VLAN 10] ──── Switch ──── [Access Port, VLAN 10] ──── Server
           (untagged traffic)                       (untagged traffic)

Use access ports for: end devices — computers, servers, phones, printers, IoT devices, APs (when each AP serves only one SSID/VLAN).

Trunk Port

A trunk port carries traffic from multiple VLANs simultaneously, distinguished by 802.1Q tags. The devices connected to trunk ports must understand VLAN tags.

Switch A ──── [Trunk Port] ──── Switch B
              (tagged: VLAN 10, 20, 30)

Use trunk ports for: uplinks between switches, connections to routers/firewalls, connections to hypervisors (ESXi, Proxmox), connections to APs serving multiple SSIDs, connections to servers hosting multiple VMs.

Native VLAN

On a trunk port, one VLAN is designated the “native VLAN” (default is VLAN 1). Traffic on the native VLAN is sent untagged on the trunk. This is a common misconfiguration source — if your native VLAN is VLAN 1 and you haven’t disabled it, untagged traffic leaks into it.

Best practice: Set the native VLAN to an unused VLAN ID (e.g., VLAN 999) and put nothing on it. Tag everything explicitly.


Planning Your VLAN Layout

Before touching a switch, map out what you need. A typical homelab segmentation:

VLAN ID Name Subnet Purpose
10 TRUSTED 192.168.10.0/24 Trusted devices: personal PCs, laptops
20 SERVERS 192.168.20.0/24 Home servers, NAS, media server
30 IOT 192.168.30.0/24 Smart TVs, bulbs, thermostats, cameras
40 GUEST 192.168.40.0/24 Guest Wi-Fi — internet only
50 MANAGEMENT 192.168.50.0/24 Switch management, AP management
60 DMZ 192.168.60.0/24 Internet-facing services
99 NATIVE (unused) Trunk native VLAN — no hosts

Traffic Rules Between VLANs

Draw out the allowed flows before configuring your firewall:

TRUSTED  → SERVERS  ✓  (access NAS, Plex, etc.)
TRUSTED  → IOT      ✗  (block — one-way only needed)
IOT      → TRUSTED  ✗  (block — IoT shouldn't initiate to trusted)
SERVERS  → IOT      ✓  (Home Assistant, monitoring)
GUEST    → *        ✗  (internet only, no LAN)
DMZ      → SERVERS  ✗  (DMZ can't reach internal servers)
SERVERS  → DMZ      ✓  (pull configs, push deployments)
* → MANAGEMENT      limited (admin stations only)

Planning this before touching hardware saves enormous reconfiguration time.


Managed Switch Configuration

You need a managed switch to use VLANs. Unmanaged switches forward all traffic to all ports — they have no concept of VLANs. Budget managed switches start around $30-50 (TP-Link TL-SG108E, Netgear GS308E); enterprise options (Cisco, HP/Aruba, Juniper) offer more features and reliability.

One of the most popular budget managed switches for homelabs. Configured via web UI.

802.1Q VLAN Setup:

  1. Log into the switch web UI (default: 192.168.0.1)
  2. Navigate to VLAN → 802.1Q VLAN
  3. Enable 802.1Q VLAN mode

For each VLAN, define which ports are Tagged (trunk) or Untagged (access):

VLAN Port 1 (pfSense) Port 2 (PC) Port 3 (Server) Port 4 (IoT) Port 5 (AP)
VLAN 10 Tagged Untagged Tagged
VLAN 20 Tagged Untagged Tagged
VLAN 30 Tagged Untagged Tagged
VLAN 99 Tagged Tagged

Then set the PVID (Port VLAN ID) for each port — this is the VLAN assigned to untagged ingress traffic:

Port PVID
Port 1 (pfSense) 99 (native, trunk)
Port 2 (PC) 10
Port 3 (Server) 20
Port 4 (IoT) 30
Port 5 (AP) 99 (trunk)

Cisco IOS (Enterprise/Lab Switches)

# Enter global config
Switch# configure terminal

# Create VLANs
Switch(config)# vlan 10
Switch(config-vlan)# name TRUSTED
Switch(config-vlan)# vlan 20
Switch(config-vlan)# name SERVERS
Switch(config-vlan)# vlan 30
Switch(config-vlan)# name IOT
Switch(config-vlan)# vlan 40
Switch(config-vlan)# name GUEST
Switch(config-vlan)# vlan 99
Switch(config-vlan)# name NATIVE
Switch(config-vlan)# exit

# Configure access port (port for a PC on VLAN 10)
Switch(config)# interface GigabitEthernet0/2
Switch(config-if)# switchport mode access
Switch(config-if)# switchport access vlan 10
Switch(config-if)# spanning-tree portfast
Switch(config-if)# exit

# Configure trunk port (uplink to pfSense or another switch)
Switch(config)# interface GigabitEthernet0/1
Switch(config-if)# switchport mode trunk
Switch(config-if)# switchport trunk encapsulation dot1q
Switch(config-if)# switchport trunk native vlan 99
Switch(config-if)# switchport trunk allowed vlan 10,20,30,40,99
Switch(config-if)# exit

# Disable unused ports (security best practice)
Switch(config)# interface range GigabitEthernet0/6-8
Switch(config-if-range)# shutdown
Switch(config-if-range)# switchport mode access
Switch(config-if-range)# switchport access vlan 999
Switch(config-if-range)# exit

# Save config
Switch# write memory

Juniper EX Series

# Set VLAN definitions
set vlans TRUSTED vlan-id 10 l3-interface irb.10
set vlans SERVERS vlan-id 20 l3-interface irb.20
set vlans IOT vlan-id 30
set vlans NATIVE vlan-id 99

# Access port
set interfaces ge-0/0/2 unit 0 family ethernet-switching
set interfaces ge-0/0/2 unit 0 family ethernet-switching interface-mode access
set interfaces ge-0/0/2 unit 0 family ethernet-switching vlan members TRUSTED

# Trunk port
set interfaces ge-0/0/1 unit 0 family ethernet-switching
set interfaces ge-0/0/1 unit 0 family ethernet-switching interface-mode trunk
set interfaces ge-0/0/1 unit 0 family ethernet-switching vlan members [TRUSTED SERVERS IOT NATIVE]
set interfaces ge-0/0/1 unit 0 family ethernet-switching native-vlan-id 99

commit

HP/Aruba ProCurve (Web UI / CLI)

# Create VLANs
switch(config)# vlan 10
switch(vlan-10)# name "TRUSTED"
switch(vlan-10)# exit

# Assign ports to VLANs
switch(config)# vlan 10
switch(vlan-10)# untagged 2         # Access port - port 2
switch(vlan-10)# tagged 1           # Trunk port - port 1
switch(vlan-10)# exit

# Set native VLAN on trunk
switch(config)# vlan 99
switch(vlan-99)# untagged 1         # Native (untagged) on trunk port 1

switch# write memory

pfSense VLAN Configuration

pfSense is the open-source firewall/router that sits between your VLANs and controls inter-VLAN traffic. The setup flow: create VLANs → create interfaces → assign IPs → configure DHCP → configure firewall rules.

1. Create VLANs on the LAN Interface

Interfaces → Assignments → VLANs → + Add

Parent Interface VLAN Tag Description
em1 (LAN) 10 TRUSTED
em1 (LAN) 20 SERVERS
em1 (LAN) 30 IOT
em1 (LAN) 40 GUEST
em1 (LAN) 50 MANAGEMENT

2. Assign VLAN Interfaces

Interfaces → Assignments → + Add for each VLAN:

  • Available network port: select em1.10 → Add → rename to OPT1 → rename in interface settings to TRUSTED
  • Repeat for each VLAN

3. Configure Each Interface

Interfaces → TRUSTED:

  • Enable: checked
  • IPv4 Configuration Type: Static IPv4
  • IPv4 Address: 192.168.10.1 /24

Repeat for each VLAN with its respective gateway IP.

4. Configure DHCP for Each VLAN

Services → DHCP Server → TRUSTED:

  • Enable: checked
  • Range: 192.168.10.100 to 192.168.10.200
  • DNS Server: 192.168.10.1 (or your preferred DNS)

Repeat for each VLAN.

5. Configure Firewall Rules

This is where the security model lives. Navigate to Firewall → Rules.

IOT VLAN — Internet access only, no LAN:

# Allow IoT to reach DNS on pfSense
Action: Pass
Interface: IOT
Protocol: UDP
Source: IOT net
Destination: IOT address (192.168.30.1)
Dest Port: 53

# Allow IoT internet access
Action: Pass
Interface: IOT
Protocol: TCP/UDP
Source: IOT net
Destination: !RFC1918 (not private addresses)
Dest Port: any

# Block IoT from everything else (private addresses)
Action: Block
Interface: IOT
Protocol: any
Source: IOT net
Destination: RFC1918

GUEST VLAN — Internet only:

Action: Pass
Interface: GUEST
Protocol: any
Source: GUEST net
Destination: !RFC1918

Action: Block
Interface: GUEST
Protocol: any
Source: GUEST net
Destination: any

TRUSTED → SERVERS (allow all):

Action: Pass
Interface: TRUSTED
Protocol: any
Source: TRUSTED net
Destination: SERVERS net

Block SERVERS → TRUSTED (servers don’t initiate to workstations):

Action: Block
Interface: SERVERS
Protocol: any
Source: SERVERS net
Destination: TRUSTED net

Floating rule — anti-spoofing:

Action: Block
Interface: any (floating)
Direction: in
Protocol: any
Source: !VLAN own subnet  (traffic from VLAN with wrong source IP)

6. Inter-VLAN DNS

Run Unbound DNS on pfSense for each VLAN, or configure per-VLAN DNS servers. For internal hostnames:

Services → DNS Resolver:

  • Enable: checked
  • Network Interfaces: add each VLAN interface
  • Outgoing Network Interfaces: WAN

Add host overrides for internal services:

  • nas.home192.168.20.10
  • homeassistant.home192.168.20.20

OPNsense VLAN Configuration

OPNsense is the more actively developed fork of pfSense with a modern UI. The flow is nearly identical.

1. Create VLANs

Interfaces → Other Types → VLANs → + Add

  • Device: em1
  • VLAN tag: 10
  • Description: TRUSTED

2. Assign Interfaces

Interfaces → Assignments → + Add for each VLAN device.

3. Configure Interfaces

Interfaces → [TRUSTED]:

  • Enable interface: checked
  • IPv4 Configuration Type: Static IPv4
  • IPv4 address: 192.168.10.1 / 24

4. DHCP

Services → DHCPv4 → [TRUSTED]:

  • Enable: checked
  • Range: .100 to .200

5. Firewall Rules

OPNsense rules work identically to pfSense. Navigate to Firewall → Rules → [interface].

A useful OPNsense-specific feature: Aliases for grouping subnets:

# Create an alias for all RFC1918 space
Firewall → Aliases → + Add
Name: RFC1918
Type: Network
Networks:
  10.0.0.0/8
  172.16.0.0/12
  192.168.0.0/16

Then use RFC1918 in rules instead of repeating all three networks.


Linux VLAN Configuration

Linux can participate in VLAN-tagged networks without any additional hardware.

Using ip (iproute2) — Temporary

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
# Load the 8021q kernel module
modprobe 8021q

# Create a VLAN interface on top of a physical interface
ip link add link eth0 name eth0.10 type vlan id 10
ip link add link eth0 name eth0.20 type vlan id 20
ip link add link eth0 name eth0.30 type vlan id 30

# Bring up the VLAN interfaces
ip link set eth0 up
ip link set eth0.10 up
ip link set eth0.20 up

# Assign IP addresses
ip addr add 192.168.10.5/24 dev eth0.10
ip addr add 192.168.20.5/24 dev eth0.20

# Add routes
ip route add default via 192.168.10.1 dev eth0.10

# Verify
ip -d link show eth0.10

Using systemd-networkd — Persistent

1
2
3
4
5
6
7
8
# /etc/systemd/network/10-eth0.network
[Match]
Name=eth0

[Network]
VLAN=eth0.10
VLAN=eth0.20
VLAN=eth0.30
1
2
3
4
5
6
7
# /etc/systemd/network/20-eth0.10.netdev
[NetDev]
Name=eth0.10
Kind=vlan

[VLAN]
Id=10
1
2
3
4
5
6
7
8
# /etc/systemd/network/30-eth0.10.network
[Match]
Name=eth0.10

[Network]
Address=192.168.10.5/24
Gateway=192.168.10.1
DNS=192.168.10.1
1
2
systemctl restart systemd-networkd
networkctl status

Using NetworkManager — Desktop/Server

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
# Create VLAN connection
nmcli connection add \
  type vlan \
  con-name "VLAN10-TRUSTED" \
  dev eth0 \
  id 10 \
  ip4 192.168.10.5/24 \
  gw4 192.168.10.1

nmcli connection up "VLAN10-TRUSTED"

# Verify
nmcli connection show
ip -d link show eth0.10

Using netplan (Ubuntu)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# /etc/netplan/01-vlans.yaml
network:
  version: 2
  ethernets:
    eth0:
      dhcp4: false

  vlans:
    eth0.10:
      id: 10
      link: eth0
      addresses:
        - 192.168.10.5/24
      routes:
        - to: default
          via: 192.168.10.1
      nameservers:
        addresses: [192.168.10.1]

    eth0.20:
      id: 20
      link: eth0
      addresses:
        - 192.168.20.5/24
1
2
netplan apply
ip -d link show eth0.10

Wi-Fi and VLANs: Multiple SSIDs

A wireless access point can present multiple SSIDs, each mapped to a different VLAN — so your guests connect to “Guest-WiFi” and land on VLAN 40, while your phone connects to “Home” and lands on VLAN 10.

The AP connects to the switch via a trunk port carrying all the VLANs. The AP maps each SSID to a VLAN tag.

Ubiquiti UniFi

UniFi is the most common managed AP system for homelabs. Configuration is done in the UniFi Controller (or UniFi Network Application):

  1. Create Networks: Settings → Networks → Create New Network

    • Name: IoT, VLAN: 30, DHCP: enabled or handled by pfSense
    • Repeat for each VLAN
  2. Create Wi-Fi SSIDs: Settings → WiFi → Create New WiFi

    • Name: Home-IoT
    • Network: select IoT (VLAN 30)
    • Security: WPA2/WPA3
  3. Trunk the AP port on the switch:

    • The switch port connected to the UniFi AP must be configured as a trunk carrying all VLANs used by SSIDs on that AP

OpenWRT (DIY/flexible APs)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
# Install VLAN support
opkg install kmod-8021q

# Configure in /etc/config/network
config interface 'TRUSTED'
  option type 'bridge'
  option proto 'dhcp'

config device
  option type '8021q'
  option ifname 'eth0'
  option vid '10'
  option name 'eth0.10'

# Configure SSIDs in /etc/config/wireless
config wifi-iface
  option device 'radio0'
  option mode 'ap'
  option ssid 'Home-IoT'
  option network 'IOT'
  option encryption 'psk2'
  option key 'your-passphrase'

Practical IoT Isolation Example

This is the most immediately valuable use of VLANs for most homelabs. IoT devices are notorious for:

  • Shipping with poor/no security updates
  • Phoning home to manufacturer servers
  • Being recruited into botnets
  • Having default credentials that are rarely changed

Putting them on an isolated VLAN with no LAN access and monitored outbound traffic eliminates most of this risk.

The IoT VLAN Design

IoT VLAN (192.168.30.0/24)
  │
  ├── Smart bulbs (192.168.30.10-19)
  ├── Thermostat (192.168.30.20)
  ├── IP cameras (192.168.30.30-39)
  ├── Smart TV (192.168.30.40)
  └── Robot vacuum (192.168.30.50)
  │
  └──→ pfSense/OPNsense firewall rules:
       ├── ALLOW: 192.168.30.0/24 → internet (port 80, 443, NTP)
       ├── ALLOW: 192.168.30.0/24 → DNS (192.168.30.1:53)
       ├── BLOCK: 192.168.30.0/24 → 192.168.0.0/8 (all private)
       └── ALLOW: 192.168.20.5 (Home Assistant) → 192.168.30.0/24

Home Assistant (on the SERVERS VLAN) can reach IoT devices to control them, but IoT devices can’t initiate connections to the trusted network.

Blocking Specific IoT Telemetry (Optional)

Use pfBlockerNG (pfSense) or AdGuard Home on a separate VLAN to block known telemetry domains:

# pfBlockerNG DNSBL categories to enable for IoT traffic:
# - Tracking and Telemetry
# - Advertising
# Per-VLAN DNS override in pfSense pointing IoT VLAN to a filtered DNS

Troubleshooting VLANs

“I configured VLANs but nothing works”

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
# 1. Verify the VLAN interface exists and is up on Linux
ip -d link show eth0.10
# Should show: eth0.10@eth0: ... vlan protocol 802.1Q id 10 ...

# 2. Check if frames are tagged correctly with tcpdump
tcpdump -i eth0 -e -n vlan
# -e shows layer-2 headers including VLAN tags

# 3. Verify switch port PVID/mode matches what you expect
# Access port for VLAN 10: PVID should be 10, membership untagged
# Trunk port: PVID should be native VLAN (99), membership tagged

# 4. Test connectivity within VLAN first (before testing inter-VLAN)
ping 192.168.10.1    # Gateway (pfSense VLAN interface)

# 5. Test DHCP is handing out correct addresses
dhclient -v eth0.10

“Inter-VLAN routing doesn’t work”

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
# 1. Verify pfSense/OPNsense has the interface enabled and configured
# Diagnostics → Ping (from pfSense) → test each VLAN interface

# 2. Check firewall rules aren't blocking (pfSense logs everything)
# Status → System Logs → Firewall → filter by source VLAN subnet

# 3. Verify default routes on clients point to VLAN gateway
ip route show
# default via 192.168.10.1 dev eth0.10

# 4. Check gateway ARP
arp -n 192.168.10.1
# Should resolve to pfSense's MAC address

“VLAN hopping / unexpected traffic between VLANs”

1
2
3
4
5
6
7
8
9
# Verify native VLAN is not VLAN 1 and is unused
# Double-tagging attacks work by sending frames tagged with the native VLAN
# wrapping an inner tag for the target VLAN

# On Cisco: verify
show interfaces trunk | grep "native"

# On pfSense: look for unexpected traffic in firewall logs
# Status → System Logs → Firewall → block rules

Useful Diagnostic Commands

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
# Show all VLAN interfaces on Linux
ip -d link show type vlan

# Capture tagged traffic on a trunk interface
tcpdump -i eth0 -nn -e 'vlan 30'

# Show VLAN membership on a Cisco switch
show vlan brief

# Verify trunk configuration
show interfaces trunk

# Show MAC address table per VLAN
show mac address-table vlan 10

# Test DHCP from specific VLAN
nmap --script broadcast-dhcp-discover -e eth0.10

Security Hardening Checklist

Switch Security:
  □ Change default switch management password and username
  □ Disable unused ports (put them in an unused VLAN and shut down)
  □ Disable CDP/LLDP on user-facing ports (hides network topology)
  □ Enable BPDU Guard on access ports (prevents STP attacks)
  □ Disable VLAN 1 as native VLAN — use an unused VLAN (e.g., 999)
  □ Restrict management VLAN access to admin IPs only
  □ Enable port security (MAC address limiting) on access ports
  □ Use a dedicated management VLAN for switch/AP access

Firewall Rules:
  □ Default deny on all inter-VLAN traffic, explicit allow only
  □ Block RFC1918 on IoT and Guest VLANs
  □ Enable anti-spoofing rules
  □ Log blocked traffic for analysis
  □ Rate-limit new connections from untrusted VLANs

Wi-Fi:
  □ Separate SSIDs for each security zone
  □ WPA3 or WPA2-AES (not TKIP) on all SSIDs
  □ Client isolation on Guest and IoT SSIDs
  □ 802.11r (fast roaming) only if needed — disable if not
  □ Management Wi-Fi on separate SSID (or wired only)

Quick Reference: VLAN Concepts

802.1Q             IEEE standard for VLAN tagging
VLAN ID (VID)      12-bit identifier, range 1–4094
Native VLAN        Untagged traffic on a trunk port (use unused VID)
Access Port        Connects end devices — one VLAN, untagged
Trunk Port         Carries multiple VLANs — tagged frames
PVID               Port VLAN ID — VLAN assigned to untagged ingress
Inter-VLAN routing Routing between VLANs — requires L3 (router/firewall)
VLAN hopping       Attack exploiting misconfigured native VLANs

ip link add link eth0 name eth0.10 type vlan id 10   # Linux VLAN
switchport mode access / trunk                        # Cisco port mode
switchport access vlan 10                             # Cisco access VLAN
switchport trunk allowed vlan 10,20,30                # Cisco trunk VLANs
switchport trunk native vlan 99                       # Cisco native VLAN

A well-segmented network built on VLANs doesn’t just improve security — it makes your network easier to reason about. When a compromised device can only reach the internet and your DNS server, the blast radius of that compromise is contained. When your smart TV can’t talk to your NAS, you don’t lose sleep about its firmware update cadence. The hour spent planning and configuring VLANs pays dividends every day afterward.

Comments