A network bridge is a Layer 2 virtual switch that allows virtual machines and containers to share a physical network interface and appear as first-class devices on the local network. On RHEL 9, NetworkManager is the authoritative tool for creating and managing bridges, replacing the deprecated brctl-only workflows of older distributions. Bridges are essential for KVM/QEMU virtual machines that need external network access, and are also used by LXC containers, Open vSwitch integrations, and some Docker configurations. This tutorial walks through creating a production-ready bridge (br0) on RHEL 9 using nmcli.

Prerequisites

  • RHEL 9 system with at least one physical (or bonded) Ethernet interface (e.g., ens3)
  • Root or sudo access
  • NetworkManager running (systemctl status NetworkManager)
  • bridge-utils installed for verification (dnf install -y bridge-utils)
  • Console or out-of-band access recommended — adding a physical NIC to a bridge will briefly drop connectivity

Step 1 — Create the Bridge Interface

Use nmcli to create a new connection of type bridge. This creates a logical bridge device named br0 without yet connecting it to any physical interface.

# Create the bridge connection
sudo nmcli con add type bridge con-name br0 ifname br0

# Disable Spanning Tree Protocol (STP) for simple single-bridge setups
sudo nmcli con mod br0 bridge.stp no

# Verify the connection profile was created
nmcli con show br0

Step 2 — Assign a Static IP Address to the Bridge

Configure the bridge with a static IP so that the host remains reachable after the physical interface is enslaved to the bridge and loses its own IP.

# Set static IP, gateway, and DNS
sudo nmcli con mod br0 
    ipv4.method manual 
    ipv4.addresses "192.168.1.50/24" 
    ipv4.gateway "192.168.1.1" 
    ipv4.dns "8.8.8.8,8.8.4.4" 
    ipv6.method ignore

# Confirm the settings
nmcli -f ipv4.addresses,ipv4.gateway,ipv4.dns con show br0

Step 3 — Add a Physical Interface as a Bridge Slave

Attach the physical Ethernet interface (ens3) to the bridge as a slave port. The physical interface will no longer hold an IP address — the bridge will own it.

# First, bring down and delete any existing connection on ens3
sudo nmcli con down ens3
sudo nmcli con del ens3

# Create the slave (port) connection
sudo nmcli con add 
    type ethernet 
    slave-type bridge 
    con-name br0-slave 
    ifname ens3 
    master br0

# List all connections to confirm both br0 and br0-slave exist
nmcli con show

Step 4 — Bring Up the Bridge

Activate the bridge connection. NetworkManager will automatically bring up the slave connection as well.

# Bring up the bridge (this may momentarily drop SSH if connected over ens3)
sudo nmcli con up br0

# Confirm the bridge is up and has the expected IP
ip addr show br0

# Example expected output:
# br0: 
#     inet 192.168.1.50/24 brd 192.168.1.255 scope global br0

Step 5 — Verify the Bridge Configuration

Use ip link and brctl to confirm bridge membership and forwarding state.

# Show all interfaces and their states
ip link show

# Show bridge details and connected ports
brctl show

# Example brctl output:
# bridge name  bridge id         STP  interfaces
# br0          8000.52540012ab34  no   ens3

# Show the bridge forwarding table (MAC address table)
brctl showmacs br0

# Test connectivity from the host
ping -c 4 192.168.1.1

Step 6 — Connect a KVM Virtual Machine to the Bridge

When creating a KVM VM with virt-install, specify the bridge as the network source so the VM receives an IP on the same subnet as physical hosts.

# Install libvirt and KVM tools if not already present
sudo dnf install -y qemu-kvm libvirt virt-install

sudo systemctl enable --now libvirtd

# Create a VM attached to br0
sudo virt-install 
    --name testvm 
    --ram 2048 
    --vcpus 2 
    --disk size=20 
    --os-variant rhel9.0 
    --network bridge=br0 
    --cdrom /path/to/rhel9.iso

# For Docker, note that Docker creates its own docker0 bridge by default.
# To connect Docker containers to br0 instead, use a macvlan network:
# docker network create -d macvlan 
#     --subnet=192.168.1.0/24 
#     --gateway=192.168.1.1 
#     -o parent=br0 macvlan_br0

Conclusion

You have created a fully functional NetworkManager-managed bridge (br0) on RHEL 9, assigned it a static IP, enslaved a physical interface, verified the configuration with brctl and ip link, and connected a KVM virtual machine to it. Bridges created with nmcli are persistent across reboots and fully managed by NetworkManager, making them more reliable than manually editing ifcfg files or calling brctl directly. For Docker workloads that need direct Layer 2 access to the physical network, macvlan networks over br0 are the recommended approach.

Next steps: How to Set Up a DHCP Server with ISC DHCP on RHEL 9, How to Configure Bond and Team Interfaces on RHEL 9, and How to Configure DRBD for High-Availability Storage on RHEL 9.