Skip to content

KVM bridge networking

A Linux bridge connects KVM instances to your provider’s network. Create the bridge on each hypervisor first, then enter its name in the VirtConsole subnet. This guide covers an ordinary Ethernet network with a gateway on the same subnet, including an untagged switch port or a provider VLAN.

VirtConsole attaches instance interfaces to an existing host bridge. Adding a Bridged subnet in the panel does not configure the host’s physical interface, IP address or default route.

Check that bridged networking fits your provider

Section titled “Check that bridged networking fits your provider”
What your provider supplies Use
Addresses on the same Ethernet network as an upstream gateway, with guest MAC addresses allowed A Linux bridge, as described here.
A tagged VLAN carrying that network A VLAN interface connected to a bridge. See Tagged VLANs.
Additional IPs tied to provider-issued virtual MAC addresses The provider’s MAC for each guest IP. See Hetzner or OVH.
A subnet routed to the host’s main IP, with no direct guest access to the upstream gateway A routed configuration. See Networking modes and the provider’s routing instructions.

A bridge exposes guest MAC addresses to the upstream switch. A provider that permits only the host MAC must explicitly support additional virtual MACs, or you need a routed design. Giving the bridge the host’s MAC does not make guest traffic use that MAC.

The examples below are for KVM hosts running the VirtConsole agent. Manage a Proxmox node’s bridges through Proxmox networking, not these agent-host instructions.

Provider switch and gateway
|
eno1 Physical uplink; no host IP after conversion
|
br0 Linux bridge; carries the host IP and default route
/ \
guest NIC guest NIC Each instance has its own IP and MAC

For a shared management and guest uplink, move the host’s addresses, routes and DNS configuration from the physical interface to the bridge. The physical interface becomes a bridge port. Do not leave the same address or default route configured on both.

If guests use a separate uplink or VLAN, leave management networking in place. The guest bridge can have no host IP address and no default route; guests still use the provider’s gateway. Do not move management onto a guest-only bridge.

Run configuration commands as root on the hypervisor. Start by recording the current setup:

Terminal window
ip -br link
ip -br address
ip -4 route show
ip -6 route show
bridge link show
cat /etc/resolv.conf

Record the uplink name, host IPv4 and IPv6 addresses with prefixes, gateways, DNS resolvers, MAC address and MTU. With several default routes, identify the actual management uplink rather than taking the first line. Check the provider’s network allocation as well as the running configuration.

Use the network manager already controlling the interface:

Existing configuration Section
Debian with /etc/network/interfaces and ifupdown Debian
Ubuntu with /etc/netplan/*.yaml Ubuntu
RHEL, Rocky or AlmaLinux with NetworkManager profiles RHEL

An OS name alone does not identify the network manager. If the host uses native systemd-networkd, a bond, policy routing or another custom setup, adapt that existing configuration instead of enabling a second manager. If cloud-init or your provider rewrites networking at boot, update its authoritative configuration or follow its documented procedure to take over network management.

All IP addresses below are documentation examples. Replace them with your allocation before applying anything.

Setting Example
Physical uplink eno1
New bridge br0
Host IPv4 203.0.113.10/24
Upstream IPv4 gateway 203.0.113.1
Host MAC 02:00:00:00:00:10
DNS 1.1.1.1, 9.9.9.9, or your existing resolvers
Optional host IPv6 2001:db8:100::10/64
Optional upstream IPv6 gateway 2001:db8:100::1

Keep your real prefix length; do not change it to /24 just to match the example. Gateways outside the assigned prefix, /32 host addresses and provider-specific IPv6 routing need explicit routes; use the relevant provider guide. Do not invent a gateway.

Choose an unused bridge name. virbr0 is commonly used by libvirt’s default NAT network; that network is not your provider-facing bridge. An existing working bridge can be reused after checking its uplink and addressing.

This example uses the bridge extensions provided by bridge-utils. It does not replace an existing ifupdown2 or systemd-networkd setup.

Back up the configuration and make sure the bridge support is installed:

Terminal window
cp -a /etc/network /root/network-before-br0
apt-get install bridge-utils

Edit the existing uplink configuration in /etc/network/interfaces or its included file. Remove the old uplink’s static or DHCP stanza and replace it with the bridge configuration below. The bridge scripts bring up eno1; do not retain a separate address-bearing stanza for that port. Preserve the loopback definition, includes and unrelated interfaces, checking that an included file does not still configure the old uplink.

/etc/network/interfaces (relevant configuration)
auto lo
iface lo inet loopback
auto br0
iface br0 inet static
address 203.0.113.10/24
gateway 203.0.113.1
bridge_ports eno1
bridge_hw eno1
bridge_stp off
bridge_fd 0
dns-nameservers 1.1.1.1 9.9.9.9

bridge_hw eno1 keeps the host-facing bridge MAC equal to the uplink MAC. STP is disabled for this single-uplink topology. Do not add a second physical uplink unless you have designed the bonding or loop-prevention arrangement.

The dns-nameservers option requires resolver integration such as resolvconf. Preserve the host’s existing resolver configuration if it is managed separately; verify name resolution after the change.

For an existing static IPv6 allocation, add this stanza and remove the corresponding address and gateway from the physical port’s old configuration:

iface br0 inet6 static
address 2001:db8:100::10/64
gateway 2001:db8:100::1

Review the saved file with ifquery br0. Apply the change from the console during the maintenance window by rebooting the host, then perform the verification checks. A planned reboot avoids leaving addresses from the old live configuration on the physical port. Do not use a reboot as a substitute for checking the saved configuration first.

Rollback: from the console, restore the original interface files from /root/network-before-br0, remove only the new bridge stanza or file you added, and reboot into the original configuration. Do not delete unrelated interface files.

Back up the directory before editing:

Terminal window
cp -a /etc/netplan /root/netplan-before-br0

Edit the YAML file that already defines the uplink. Netplan merges its configuration files, so adding a new file does not automatically remove an address or DHCP setting from an older one. Preserve unrelated interfaces and routes.

The following example uses systemd-networkd and static IPv4. It disables automatic host IPv6 configuration; if the host uses static IPv6, DHCPv6 or router advertisements, carry that configuration over to br0 before applying it.

Existing /etc/netplan/*.yaml uplink configuration
network:
version: 2
renderer: networkd
ethernets:
eno1:
dhcp4: false
dhcp6: false
accept-ra: false
bridges:
br0:
interfaces: [eno1]
macaddress: 02:00:00:00:00:10
dhcp4: false
dhcp6: false
accept-ra: false
addresses:
- 203.0.113.10/24
routes:
- to: default
via: 203.0.113.1
nameservers:
addresses: [1.1.1.1, 9.9.9.9]
parameters:
stp: false
forward-delay: 0

Replace macaddress with the actual uplink MAC from ip link show eno1. For static IPv6, add 2001:db8:100::10/64 to the bridge’s addresses list and a second default route with via: 2001:db8:100::1. Use your actual IPv6 gateway; a link-local gateway is scoped to br0. If the provider supplies the host address through DHCP or SLAAC, configure those methods on the bridge instead of copying this static example. Preserve any DHCP client-ID requirements.

Validate and try the configuration:

Terminal window
netplan generate
netplan try --timeout 120

During the trial, verify host connectivity and open a second SSH connection. Confirm the trial only when those checks pass. A confirmed trial applies the configuration; it is already saved for boot.

Rollback: use the console to restore the original YAML files from /root/netplan-before-br0 and remove only new files introduced for this change. Run netplan generate, then netplan apply. Recheck addressing and routes. If an unused bridge remains, verify that the original management network is restored and the saved configuration is correct before rebooting.

RHEL, Rocky and AlmaLinux with NetworkManager

Section titled “RHEL, Rocky and AlmaLinux with NetworkManager”

Use NetworkManager profiles for RHEL 9 and 10. Do not add legacy network-scripts files alongside them. Record the connection profile name, which can differ from the device name:

Terminal window
nmcli -f NAME,UUID,TYPE,DEVICE connection show --active
nmcli connection show "CURRENT_UPLINK_PROFILE"
cp -a /etc/NetworkManager/system-connections /root/nm-connections-before-br0

Replace CURRENT_UPLINK_PROFILE below with that exact profile name. Keep the original profile as a rollback option. Create the bridge and port without activating them:

Terminal window
nmcli connection add type bridge con-name br0 ifname br0 connection.autoconnect no
nmcli connection modify br0 \
ipv4.method manual ipv4.addresses 203.0.113.10/24 \
ipv4.gateway 203.0.113.1 ipv4.dns "1.1.1.1 9.9.9.9" \
ipv6.method disabled \
bridge.mac-address 02:00:00:00:00:10 bridge.stp no
nmcli connection add type ethernet con-name br0-port ifname eno1 \
port-type bridge controller br0 connection.autoconnect no
nmcli connection modify br0 connection.autoconnect-ports 1

The port-type, controller and connection.autoconnect-ports names require RHEL 9.4 or later. On older RHEL 9 installations, use slave-type, master and connection.autoconnect-slaves, respectively.

This example disables host IPv6 on the bridge. If the host currently has static IPv6, configure it before activation:

Terminal window
nmcli connection modify br0 \
ipv6.method manual ipv6.addresses "2001:db8:100::10/64" \
ipv6.gateway "2001:db8:100::1"

For DHCPv6 or SLAAC, retain the existing host’s IPv6 method and DNS settings on the bridge instead. Carry over additional routes, MTU and any interface-based firewall-zone assignment deliberately; a newly created profile does not inherit them.

From the console, disable automatic activation of the original profile and activate the bridge port. Activating the port also activates its bridge:

Terminal window
nmcli connection modify "CURRENT_UPLINK_PROFILE" connection.autoconnect no
nmcli connection up br0-port

This replaces the old active uplink profile and can interrupt SSH. After the verification checks pass, enable the new profiles at boot:

Terminal window
nmcli connection modify br0 connection.autoconnect yes
nmcli connection modify br0-port connection.autoconnect yes

Rollback: from the console, bring down br0-port and br0, disable their autoconnect, restore autoconnect on CURRENT_UPLINK_PROFILE, and activate the original profile. Keep the backup until a planned reboot has verified persistence.

An untagged access port needs no VLAN interface on the host. If the provider explicitly delivers a tagged VLAN, put its VLAN interface into the bridge, not the raw uplink. For VLAN 100:

Provider trunk -- eno1 -- eno1.100 -- br100 -- instance interfaces

For example, add this to an existing Netplan configuration for a guest-only VLAN. Keep all existing management settings under eno1 unchanged. The bridge has no host address and creates no additional default route:

network:
version: 2
renderer: networkd
# Retain the existing ethernets: eno1: management configuration here.
vlans:
eno1.100:
id: 100
link: eno1
dhcp4: false
dhcp6: false
accept-ra: false
bridges:
br100:
interfaces: [eno1.100]
dhcp4: false
dhcp6: false
accept-ra: false
parameters:
stp: false
forward-delay: 0

This is a fragment to merge into the existing configuration, not a replacement file: eno1 must already be defined. Use the same validation and console-backed trial as above. With ifupdown or NetworkManager, create the equivalent persistent VLAN device and make it the bridge port. Do not enslave the raw trunk to this guest-only bridge or tag traffic twice. Check the VLAN ID and permitted MTU with the provider.

Instances attached to br100 see an ordinary untagged network; the host VLAN interface adds and removes the tag. Enter br100 as the subnet’s bridge in VirtConsole. If management also uses this VLAN, move that VLAN’s host addressing onto the bridge using the shared-uplink pattern instead.

After the host bridge works, go to Networking > Subnets > Add subnet. See Subnets and IP addresses for the full form.

Field For the untagged example
Networking Mode Bridged
Bridge br0, exactly as it exists on the host
Protocol IPv4; add IPv6 as a separate subnet if supplied
Netmask The guest allocation’s mask, for example 255.255.255.0
Gateway The provider’s gateway for that guest allocation, for example 203.0.113.1
DNS Resolver 1 / 2 Resolvers reachable from the instances
Hypervisors Only hosts where this bridge exists and reaches this allocation

Use the provider’s guest allocation, which may differ from the management subnet. Do not use the host IP as the guest gateway unless you are deliberately configuring a routed network.

Generate only addresses assigned to you. Exclude the host address, gateway and any reserved addresses; exclude network and broadcast addresses for an ordinary IPv4 subnet. If the provider requires a virtual MAC, enter it on each corresponding IP. Do not assign every guest the physical host MAC.

On multiple hypervisors, the same bridge name is not enough: each bridge must reach the correct upstream network or VLAN. Prepare it on every selected host before enabling placement there.

Check the host before deploying a guest:

Terminal window
ip -br address
ip -4 route show
ip -6 route show
ip link show master br0
bridge link show
ping -c 3 203.0.113.1
getent hosts docs.virtconsole.com

Substitute the real bridge and gateway. Confirm that:

  • The host address and intended default route use br0, with no duplicate address or default route left on eno1.
  • eno1 is a port of br0 and has carrier. For a tagged VLAN, the port is the VLAN interface.
  • DNS works, a new SSH connection works, and the management server can still reach the agent on port 2443.
  • The host’s IPv6 address and default route are present if IPv6 was configured. An ICMP-blocking gateway may not answer ping, so also test actual permitted traffic.

Deploy one test instance from the new subnet. Confirm its assigned IP, prefix, gateway and MAC inside the guest; test its gateway, DNS and outbound connectivity, then inbound connectivity from another machine. Inbound tests must match the instance’s security-group rules.

For an instance already running, virsh domiflist INSTANCE_DOMAIN shows the host bridge used by its NIC. virsh net-list lists libvirt-managed networks, not every Linux bridge, so an empty network list does not mean br0 is missing.

At the end of the maintenance window, verify the saved configuration survives a planned host reboot before putting production instances on it.

Symptom Check
Host becomes unreachable Console first: wrong prefix/gateway, duplicate configuration, changed host MAC, wrong uplink, or missing management VLAN. Restore the saved configuration if necessary.
Host works but guests cannot reach the gateway Provider MAC restrictions, guest IP/MAC pairing, upstream VLAN, bridge port membership and guest prefix/gateway.
Bridge exists but an instance cannot start Exact bridge name in the VirtConsole subnet, selected hypervisor, link state and the agent’s error message.
IPv4 works but IPv6 fails IPv6 address and route moved to the bridge, correct gateway scope, provider routing/MAC requirements, and neighbour-discovery filtering. IPv4 success does not validate IPv6.
Small packets work but larger transfers stall MTU across guest, bridge, VLAN/bond and upstream path; check firewall handling of path-MTU discovery.
Configuration breaks after reboot Duplicate network-manager definitions, cloud-init regeneration, old NetworkManager autoconnect profiles, or a bridge-helper service recreating the same bridge.

Do not flush the host firewall or disable instance security groups to make a bridge work. Inspect the applicable forwarding and filtering rules. See CSF firewall and Security groups.

Older versions of this guide used hypervisor:bridge with a vbridge-*.service unit. Do not run that helper or its stop action against a bridge now managed by the OS network configuration. The stop action tears the bridge down.

When converting an existing helper installation, schedule a console-backed maintenance window, record the service and live network state, and prepare the persistent OS configuration first. Disable the old unit for the next boot without stopping the live bridge, then activate the new configuration during that window. Keep a console rollback plan. One bridge should have one configuration owner.