Network bridges and VLANs are foundational building blocks for self-hosted infrastructure. Whether you are setting up virtual machine networking with KVM, container networking with Docker, or network segmentation for multi-tenant services, you need reliable tools to create and manage Linux bridges and VLAN interfaces.

This guide compares the three primary approaches to Linux bridge and VLAN management: bridge-utils (the legacy brctl toolkit), iproute2 (the modern ip/bridge replacement), and netplan (the declarative configuration framework used by Ubuntu and increasingly other distributions). We cover configuration patterns, persistence mechanisms, and which tool fits your self-hosted environment.

Understanding Linux Bridges and VLANs

A Linux bridge operates like a virtual network switch, connecting multiple network interfaces (physical or virtual) into a single broadcast domain. Bridges are essential for:

  • KVM/libvirt virtual machine networking
  • Docker and container network overlays
  • Bonding interfaces for high availability
  • Software-defined networking (SDN)

A VLAN (Virtual LAN) tags Ethernet frames with an 802.1Q identifier, allowing a single physical interface to carry traffic for multiple isolated networks. VLANs are used for:

  • Network segmentation between services
  • Tenant isolation in multi-tenant environments
  • Separating management, storage, and data traffic
  • Microsegmentation in containerized environments

Managing bridges and VLANs involves two distinct operations: runtime configuration (creating interfaces that exist until reboot) and persistent configuration (ensuring interfaces survive reboots through configuration files).

bridge-utils (brctl)

bridge-utils is the original Linux bridge management toolkit, providing the brctl command. It has been the standard since the early 2000s and remains available on most distributions.

Bridge Management with brctl

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
# Create a bridge
sudo brctl addbr br0

# Add physical interfaces to the bridge
sudo brctl addif br0 eth1
sudo brctl addif br0 eth2

# Set the bridge up
sudo ip link set br0 up

# Show bridge configuration
brctl show
brctl showmacs br0

# Remove an interface from the bridge
sudo brctl delif br0 eth1

# Delete the bridge
sudo ip link set br0 down
sudo brctl delbr br0

VLAN Configuration with bridge-utils

bridge-utils does not directly manage VLANs. For VLAN interfaces, you use the vconfig command (from the vlan package) or the ip link command:

1
2
3
4
5
6
7
8
9
# Create VLAN interface using ip link (preferred over vconfig)
sudo ip link add link eth0 name eth0.100 type vlan id 100
sudo ip link set eth0.100 up

# Assign IP to VLAN
sudo ip addr add 192.168.100.1/24 dev eth0.100

# Delete VLAN
sudo ip link delete eth0.100

Persistence

bridge-utils itself does not provide persistence. On Debian/Ubuntu, bridge configuration is persisted through /etc/network/interfaces:

1
2
3
4
5
6
auto br0
iface br0 inet static
    address 192.168.1.1/24
    bridge_ports eth1 eth2
    bridge_stp on
    bridge_fd 0

On RHEL systems, persistence uses network scripts in /etc/sysconfig/network-scripts/ifcfg-br0.

iproute2 (ip command)

iproute2 is the modern replacement for the legacy net-tools suite. The ip command handles bridge and VLAN management natively, without requiring separate tools.

Bridge Management with iproute2

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# Create a bridge
sudo ip link add name br0 type bridge

# Enable STP (Spanning Tree Protocol)
sudo ip link set br0 type bridge stp_state 1

# Set bridge forward delay
sudo ip link set br0 type bridge forward_delay 0

# Add interfaces to the bridge
sudo ip link set eth1 master br0
sudo ip link set eth2 master br0

# Bring up the bridge and ports
sudo ip link set br0 up
sudo ip link set eth1 up
sudo ip link set eth2 up

# Show bridge configuration
bridge link show
bridge vlan show

# Remove interface from bridge
sudo ip link set eth1 nomaster

# Delete bridge
sudo ip link set br0 down
sudo ip link delete br0 type bridge

VLAN Management with iproute2

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
# Create VLAN with specific ID
sudo ip link add link eth0 name eth0.200 type vlan id 200

# Set VLAN protocol (802.1Q or 802.1ad)
sudo ip link add link eth0 name eth0.300 type vlan proto 802.1ad id 300

# Configure VLAN filtering on a bridge
sudo ip link set br0 type bridge vlan_filtering 1

# Add VLAN to a bridge port
sudo bridge vlan add dev eth1 vid 100 master br0
sudo bridge vlan add dev eth2 vid 200 master br0

# Show VLAN configuration
bridge vlan show

Persistence

iproute2 commands are runtime-only. Persistence depends on the network management framework:

  • systemd-networkd: .network files in /etc/systemd/network/
  • NetworkManager: nmcli commands or /etc/NetworkManager/system-connections/
  • Debian ifupdown: /etc/network/interfaces

netplan

netplan is a declarative network configuration framework introduced by Canonical for Ubuntu 17.10+. Instead of imperative commands, you write YAML configuration files that netplan translates into backend configurations for systemd-networkd or NetworkManager.

Bridge Configuration with netplan

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
# /etc/netplan/01-bridge.yaml
network:
  version: 2
  renderer: networkd
  ethernets:
    eth1:
      dhcp4: no
    eth2:
      dhcp4: no
  bridges:
    br0:
      interfaces: [eth1, eth2]
      addresses: [192.168.1.1/24]
      parameters:
        stp: true
        forward-delay: 0
      dhcp4: no

Apply the configuration:

1
2
3
4
5
6
7
8
# Validate configuration
sudo netplan generate

# Apply configuration
sudo netplan apply

# Debug and see what's being generated
sudo netplan --debug apply

VLAN Configuration with netplan

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
# /etc/netplan/02-vlans.yaml
network:
  version: 2
  renderer: networkd
  ethernets:
    eth0:
      dhcp4: no
  vlans:
    eth0.100:
      id: 100
      link: eth0
      addresses: [10.0.100.1/24]
      routes:
        - to: default
          via: 10.0.100.254
    eth0.200:
      id: 200
      link: eth0
      addresses: [10.0.200.1/24]

Bridge with VLANs Combined

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
# /etc/netplan/03-bridge-vlan.yaml
network:
  version: 2
  renderer: networkd
  bridges:
    br-vlan100:
      interfaces: [eth0.100]
      addresses: [192.168.100.1/24]
      parameters:
        stp: true
  vlans:
    eth0.100:
      id: 100
      link: eth0
    eth0.200:
      id: 200
      link: eth0

Comparison: bridge-utils vs iproute2 vs netplan

Featurebridge-utils (brctl)iproute2 (ip/bridge)netplan
Interface TypeImperative commandsImperative commandsDeclarative YAML
Bridge Createbrctl addbrip link add type bridgeYAML bridges: section
VLAN Createip link / vconfigip link add type vlanYAML vlans: section
Bridge VLAN FilteringNot supportedbridge vlan addSupported via YAML
PersistenceVia ifupdown/NM scriptsVia backend (networkd/NM)Built-in (YAML = persistent)
BackendKernel bridge moduleKernel bridge modulesystemd-networkd or NetworkManager
Default OnLegacy systemsAll modern LinuxUbuntu 17.10+, expanding
Deprecation StatusDeprecated (brctl removed from iproute2)Current standardRecommended for Ubuntu
Learning CurveLow (simple commands)Medium (many subcommands)Low (declarative YAML)
GitHubN/A (in kernel tree)N/A (in kernel tree)github.com/canonical/netplan (500+ stars)

Why Self-Host Bridge and VLAN Management?

For self-hosted infrastructure, network bridges and VLANs are essential for isolation, security, and multi-tenant operations. Whether you are running virtual machines, containers, or a multi-service homelab, proper network segmentation prevents services from interfering with each other.

Network segmentation for security. By placing services on separate VLANs — database servers, application servers, and management interfaces on distinct virtual networks — you limit the blast radius of a security incident. A compromised web server on VLAN 100 cannot directly reach your database server on VLAN 200. For deeper network segmentation strategies, see our microsegmentation guide.

Virtual machine and container networking. KVM virtual machines connect to the host through bridges. Docker and container runtimes create their own bridges for container networking. Understanding bridge management is essential for troubleshooting connectivity issues in virtualized environments. For related container networking topics, see our container CNI plugins guide.

Cost-effective multi-tenant infrastructure. With proper bridge and VLAN configuration, a single physical server can safely host multiple isolated environments — each with its own network space, IP range, and gateway. This eliminates the need for separate physical switches or dedicated hardware for each tenant.

No vendor lock-in. Linux bridge and VLAN tools are open-source and built into the kernel. Unlike proprietary virtual switch solutions from VMware or Cisco, the Linux bridge has no licensing cost and runs on any hardware. Our overlay networks guide covers higher-level networking for distributed environments.

Best Practices for Production

  1. Use iproute2 for runtime commands — brctl is deprecated and may not be available on newer distributions. Use ip link and bridge commands for all runtime bridge and VLAN operations.

  2. Use netplan for persistent configuration on Ubuntu — netplan’s declarative YAML is easier to version-control, review, and automate than imperative scripts.

  3. Enable STP for multi-bridge topologies — If your bridge connects to other switches or bridges, enable Spanning Tree Protocol to prevent loops:

    1
    
    sudo ip link set br0 type bridge stp_state 1
    
  4. Test VLAN filtering before deploying — When using bridge VLAN filtering, verify connectivity on each VLAN before removing the untagged default VLAN from trunk ports.

  5. Version-control your netplan files — Store /etc/netplan/*.yaml in a git repository. This provides change history, rollback capability, and peer review for network changes.

FAQ

Is brctl deprecated? Should I stop using it?

Yes, brctl is considered deprecated. The bridge-utils package is still available on most distributions for backward compatibility, but the iproute2 suite’s ip link and bridge commands provide full bridge management functionality. New scripts and automation should use iproute2 commands. On Ubuntu 22.04+ and Fedora 35+, bridge-utils may not be installed by default.

Can I mix bridge-utils and iproute2 commands on the same bridge?

Yes. Both tools operate on the same kernel bridge interface. You can create a bridge with brctl addbr and inspect it with bridge link show. However, for consistency and future compatibility, use iproute2 exclusively.

Does netplan work on non-Ubuntu distributions?

netplan is available on Debian, Fedora, and Arch Linux through their respective package repositories, but it is most actively developed for Ubuntu. On non-Ubuntu systems, you may prefer to use systemd-networkd directly (with .network files) or NetworkManager (with nmcli).

How do I create a bridge that spans multiple VLANs?

Create VLAN sub-interfaces on the physical port, then add each VLAN interface as a separate bridge:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
vlans:
  eth0.100:
    id: 100
    link: eth0
  eth0.200:
    id: 200
    link: eth0
bridges:
  br100:
    interfaces: [eth0.100]
    addresses: [10.0.100.1/24]
  br200:
    interfaces: [eth0.200]
    addresses: [10.0.200.1/24]

What is bridge VLAN filtering and when should I use it?

Bridge VLAN filtering allows a single Linux bridge to handle multiple VLANs natively, without creating separate VLAN sub-interfaces. It is useful when you need to pass tagged traffic through a bridge to virtual machines or containers that understand VLAN tags. Enable it with ip link set br0 type bridge vlan_filtering 1, then assign VLANs to ports with bridge vlan add dev eth1 vid 100 master br0.

How do I troubleshoot a bridge that is not passing traffic?

Check these common issues:

  1. Verify the bridge and ports are UP: ip link show br0
  2. Check that ports are added: bridge link show
  3. Verify STP is not blocking ports: bridge link show | grep BLOCKING
  4. Check firewall rules that may block bridged traffic
  5. Verify IP addresses are assigned: ip addr show br0