Skip to main content
RunBook Academy

← All labs in OPNsense

Lab · advanced · ~75 min

Lab: VLAN segmentation and inter-VLAN firewalling

B · Nested virtualisationC · Simulation

Objectives

  • Create three VLANs on a 802.1Q trunk and assign them to OPNsense
  • Configure DHCP per VLAN with non-overlapping pools
  • Write inter-VLAN rules that default-deny between segments
  • Verify the inter-VLAN path with ping and tcpdump
  • Audit the runtime ruleset for shadowed or missing rules

Prerequisites

This lab builds a three-VLAN topology on a single trunk interface and writes the firewall rules that enforce the expected segmentation. The point is not the VLANs — it is the discipline of treating east-west traffic the same way you treat north-south traffic: explicit allow, default deny, evidence.

The compounding error in flat networks is that the firewall is only at the boundary. A flat LAN trusts any host that reaches the LAN segment. Once a workstation on the same subnet is compromised, the attacker has the keys to the production servers, the management interfaces, and the guest Wi-Fi. Segmentation is what stops that propagation.

Objective

By the end of this lab you can:

  • Configure 802.1Q trunks on OPNsense’s parent interface.
  • Build VLAN interfaces with addresses and per-VLAN DHCP.
  • Write inter-VLAN firewall rules that default-deny between segments.
  • Verify the bidirectional block with a packet capture.
  • Audit the ruleset for shadowed rules and missing denies.

Requirements

  • The OPNsense baseline from the previous lab (LAN rules baseline).
  • A managed switch that supports 802.1Q tagging, or a virtualised switch with trunk capability (Proxmox bridges with VLAN awareness, Open vSwitch, or a real switch).
  • Three LAN-side clients (or VMs) that can each be assigned to one VLAN. In a virtualised lab, three sibling VMs work.
  • Network access from the firewall to the trunk for VLAN configuration.

The trunk port on the switch must be configured to tag the three VLAN IDs the lab uses. The wrong untagged VLAN on the trunk is one of the most common reasons a freshly built VLAN trunk passes no traffic.

Tasks

Task 1: Pre-flight — confirm the trunk is healthy

Before touching OPNsense, confirm the upstream switch is sending tagged frames. From the firewall console:

tcpdump -ni em1 -e -c 5

The -e flag prints the Ethernet header including the 802.1Q tag. Frames with a vlan 10, vlan 20, or vlan 30 tag are proof the switch is tagging. Frames without a tag are untagged — the trunk is misconfigured on the upstream side.

Task 2: Create the VLANs on the parent interface

In the GUI: Interfaces → Other Types → VLAN. Add three VLANs:

  • VLAN 10 on parent em1, description mgmt
  • VLAN 20 on parent em1, description staff
  • VLAN 30 on parent em1, description guest

Save each, then on Interfaces → Assignments add each as a new interface. The OPNsense convention is vlan10, vlan20, vlan30 as the interface name; you can rename them to MGMT, STAFF, GUEST for the human view.

Task 3: Assign addresses to the VLAN interfaces

Configure each VLAN interface:

  • vlan10 (mgmt): 192.168.10.1/24
  • vlan20 (staff): 192.168.20.1/24
  • vlan30 (guest): 192.168.30.1/24

The non-overlapping /24s exist for three reasons: the routing table must not have ambiguous destinations, the firewall log must be able to identify the source by subnet, and DHCP scope math must avoid double-allocation. The operator who picks 192.168.10.0/24 and 192.168.10.128/25 because they look related has built a diagnostic nightmare.

Task 4: Configure DHCP per VLAN

For each VLAN, Services → ISC DHCPv4 → [VLAN], enable and configure:

  • vlan10: range 192.168.10.100 - 192.168.10.200, gateway 192.168.10.1
  • vlan20: range 192.168.20.100 - 192.168.20.200, gateway 192.168.20.1
  • vlan30: range 192.168.30.100 - 192.168.30.200, gateway 192.168.30.1

Apply. The DHCP relay must be re-enabled if the previous lab disabled it.

Task 5: Verify a host gets a DHCP lease on each VLAN

From a client on VLAN 10:

sudo dhclient -v vlan10 2>&1 | grep -i 'lease\|bound'
ip -4 addr show vlan10

The client should hold a 192.168.10.x address. Repeat for VLAN 20 and VLAN 30. A misconfigured trunk produces a DHCP offer with no IP, or an IP from the wrong subnet; the diagnosis is the upstream switch’s PVID on the trunk port.

Task 6: Write the inter-VLAN rules

The segmentation policy:

  • mgmt (vlan10) can reach everything. The management network is the operator’s path to the firewall and the servers.
  • staff (vlan20) can reach the Internet but not mgmt or guest. Staff workstations do not need to talk to the management plane.
  • guest (vlan30) can reach the Internet only. Guest Wi-Fi is the least-trusted segment.

In the GUI, Firewall → Rules, add the following on each VLAN interface:

On the MGMT interface:

  • Allow MGMT net to any (for operator access)

On the STAFF interface:

  • Allow STAFF net to MGMT net for specific services (DNS, RDP) if needed — otherwise default deny.
  • Allow STAFF net to WAN net (the Internet egress).
  • Block STAFF net to GUEST net (with logging).
  • Block and log everything else.

On the GUEST interface:

  • Allow GUEST net to WAN net (egress only).
  • Block and log everything else (including MGMT, STAFF, and LAN).

The order matters. The most specific rules first; the default-deny last. The block-and-log rules must be above the default-deny so the operator can see the explicit block.

Task 7: Audit the ruleset order with pfctl

After Apply:

pfctl -sr | grep -E 'vlan|MGMT|STAFF|GUEST'

The rules should appear in interface order: MGMT rules first (vlan10), then STAFF (vlan20), then GUEST (vlan30). A stalled interface (e.g., STAFF rules showing before MGMT) is a sorting bug.

Look for two warning signs:

  • A pass rule on GUEST that names MGMT as a destination — the policy says no.
  • A pass rule with any as source and any as destination on any VLAN — this is the default-allow that the previous lab removed from LAN; it must not reappear on a VLAN.

Task 8: Reproduce a block between VLANs

From a STAFF host, ping the MGMT gateway:

ping -c 3 192.168.10.1

The expected result is Request timed out or Destination host unreachable. Check the firewall log:

configctl filter show log | tail -20

The block should be there, logging the source as the STAFF host, the destination as the MGMT subnet, and the rule name should mention the inter-VLAN block.

Task 9: Confirm the egress path works

From a GUEST host:

curl -sI --connect-timeout 5 https://example.com
dig +short google.com @8.8.8.8

Both should succeed. The GUEST VLAN is correctly routed to the Internet, but cannot reach internal subnets. The operator who sees this work and sees the STAFF→MGMT block is looking at the discipline of east-west firewalling.

Validation

  • Three VLAN interfaces exist with non-overlapping /24 addresses.
  • DHCP is serving leases on each VLAN.
  • pfctl -sr shows rules in the expected order: MGMT → STAFF → GUEST.
  • A STAFF→MGMT ping produces a block log entry.
  • A GUEST→Internet HTTPS request succeeds.
  • A GUEST→MGMT ping is blocked and logged.

Expected Result

You have a three-segment topology with explicit allow rules between each pair and a default-deny that catches everything else. The runtime ruleset is auditable and the inter-VLAN blocks are visible in the log. The ISA surfaces of the firewall — DHCP, DNS, ICMP — work inside the management segment; they are denied on the guest segment.

Troubleshooting

  • A VLAN gets no DHCP offer. The trunk port on the upstream switch is not tagging the VLAN ID, or the PVID/native VLAN on the trunk is wrong. tcpdump -ni em1 -e should show the tagged DHCP discover.
  • All VLANs work but cannot reach each other AND cannot reach the Internet. The WAN-side default route is missing or the outbound NAT is not covering the new VLAN subnets. Check Firewall → NAT → Outbound.
  • Pings between VLANs work but services don’t. ICMP is allowed but the TCP/UDP block rules are missing. Add protocol-specific allows.
  • The rule audit shows shadowed rules. Two rules match the same flow; only the first applies. pfctl -sr shows the order; the GUI does not until you simulate. Use the built-in rule tester in the GUI to see which rule wins for a given source/destination.

Cleanup

Snapshot the configuration before the next lab:

configctl backup download
# Save as opnsense-baseline-vlans.xml

To remove the segmentation:

# In the GUI: Interfaces → Other Types → VLAN → delete each VLAN
# Interfaces → Assignments → remove the VLAN assignments
# Services → ISC DHCPv4 → disable each VLAN
# Firewall → Rules → delete the VLAN rules

The reset is destructive. Restore the snapshot rather than removing by hand if the next lab needs the baseline.

What you learned

  • An 802.1Q trunk moves the addressing from the parent interface to the VLAN interfaces; the parent is a wire, not a subnet.
  • Non-overlapping subnets are not optional. They are the foundation of routing, logging, and DHCP correctness.
  • East-west firewalling is the same discipline as north-south: explicit allow, default deny, log the deny, verify with pfctl.
  • A managed switch that does not tag the VLAN ID is the single most common reason a fresh VLAN trunk “doesn’t work” — the diagnostic is the upstream, not OPNsense.

Deliverables

  • · A working VLAN trunk (VLAN 10 mgmt, 20 staff, 30 guest)
  • · Three DHCP scopes, one per VLAN, non-overlapping
  • · A default-deny rule between any pair of VLANs
  • · Evidence of a blocked inter-VLAN flow in the firewall log
  • · A ruleset snapshot before and after the segment rules

Verification status

Last reviewed
2026-08-14
Executed end to end
not yet run on hardware

The commands and configuration here have been reviewed against the verified software versions, but nobody has run this lab start to finish on a system meeting its prerequisites. Treat the Expected Outcome as the intended result rather than an observed one, and keep the Cleanup section to hand.