Network bonding combines two or more physical interfaces into one logical interface, bond0. Depending on the mode, the bond gives you failover when a cable, NIC or switch port dies, extra aggregate bandwidth, or both. In this tutorial you will configure a bond on Ubuntu 24.04 with Netplan, first in active-backup mode and then in LACP (802.3ad) mode, check its state, and test failover. A short section covers the equivalent NetworkManager commands for Rocky Linux 9.

Prerequisites

To follow this tutorial you need:

  • A server running Ubuntu 24.04 LTS with at least two physical network interfaces connected to the same network, such as a CubePath dedicated server. Virtual machines usually have a single virtual NIC, where bonding brings no benefit.
  • A non-root user with sudo privileges.
  • Access to an out-of-band console (IPMI, iDRAC, iLO or KVM). You are about to reconfigure the interface that carries your SSH session, and a typo can cut you off.
  • For LACP only: switch ports configured as an LACP port-channel (LAG). If you do not control the switch, use active-backup.

Throughout the guide the interfaces are called eno1 and eno2, and the example addressing is 203.0.113.10/24 with gateway 203.0.113.1. Replace them with your own values.

Choosing a bonding mode

The Linux bonding driver supports seven modes. These are the ones worth knowing:

ModeNetplan nameWhat it doesSwitch configuration
1active-backupOne interface carries traffic, the others wait and take over on failureNone
4802.3adLACP aggregation, flows are spread over all linksLACP port-channel
6balance-albLoad balancing in software, including receive traffic via ARPNone
0balance-rrRound-robin per packet, causes reordering in TCPStatic port-channel

Active-backup is the safest choice and works on any switch. LACP is the standard for more bandwidth, but remember that a single TCP flow never exceeds the speed of one link: aggregation helps with many concurrent flows.

Step 1 - Identifying interfaces and backing up the configuration

List the physical interfaces and their link state:

ip -br link
lo               UNKNOWN        00:00:00:00:00:00 <LOOPBACK,UP,LOWER_UP>
eno1             UP             3c:ec:ef:12:34:56 <BROADCAST,MULTICAST,UP,LOWER_UP>
eno2             UP             3c:ec:ef:12:34:57 <BROADCAST,MULTICAST,UP,LOWER_UP>

Both interfaces should show LOWER_UP, which means there is carrier on the cable. Note the current address, gateway and DNS servers, because the bond will take them over:

ip -br addr show eno1
ip route show default
resolvectl dns

Then look at the existing Netplan files and copy them to a backup directory outside /etc/netplan:

ls /etc/netplan/
sudo mkdir -p /root/netplan-backup
sudo cp /etc/netplan/*.yaml /root/netplan-backup/

Step 2 - Configuring an active-backup bond

Netplan merges every YAML file in /etc/netplan/ in lexical order, so a leftover file that still assigns the address to eno1 would conflict with the bond. Move the old files out of the directory (they are already backed up) and create a single new configuration:

sudo mv /etc/netplan/*.yaml /root/netplan-backup/
sudo nano /etc/netplan/01-bond0.yaml

Add the following content, adjusting the interface names, addresses and DNS servers:

network:
  version: 2
  renderer: networkd
  ethernets:
    eno1:
      dhcp4: false
    eno2:
      dhcp4: false
  bonds:
    bond0:
      interfaces:
        - eno1
        - eno2
      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:
        mode: active-backup
        primary: eno1
        mii-monitor-interval: 100

The member interfaces carry no addresses of their own. mii-monitor-interval: 100 checks the link state every 100 ms, and primary: eno1 makes eno1 the preferred active interface whenever it is up.

Netplan warns about world-readable files, so restrict the permissions:

sudo chmod 600 /etc/netplan/01-bond0.yaml

Step 3 - Applying the configuration safely

Validate the syntax first. This generates the backend configuration without applying it:

sudo netplan generate

No output means the file is valid. Now apply it with netplan try, which rolls back automatically unless you confirm within 120 seconds. If your SSH session freezes, wait and the old configuration returns:

sudo netplan try
Do you want to keep these settings?

Press ENTER before the timeout to accept the new configuration

Changes will revert in 118 seconds

Open a new SSH connection to the server. If it works, go back to the first session and press ENTER to keep the configuration.

Step 4 - Verifying the bond

The bonding driver exposes its full state in /proc:

cat /proc/net/bonding/bond0
Ethernet Channel Bonding Driver: v6.8.0-45-generic

Bonding Mode: fault-tolerance (active-backup)
Primary Slave: eno1 (primary_reselect always)
Currently Active Slave: eno1
MII Status: up
MII Polling Interval (ms): 100
Up Delay (ms): 0
Down Delay (ms): 0

Slave Interface: eno1
MII Status: up
Speed: 10000 Mbps
Duplex: full
Link Failure Count: 0

Slave Interface: eno2
MII Status: up
Speed: 10000 Mbps
Duplex: full
Link Failure Count: 0

Confirm that bond0 holds the address and the default route:

ip -br addr show bond0
ip route show default
bond0            UP             203.0.113.10/24 fe80::3eec:efff:fe12:3456/64
default via 203.0.113.1 dev bond0 proto static

Step 5 - Testing failover

A bond that has never failed over is untested. From another machine, start a continuous ping to the server so you can measure any interruption:

ping 203.0.113.10

On the server, from the out-of-band console, disable the active interface:

sudo ip link set eno1 down

Check which interface is active now:

grep "Currently Active Slave" /proc/net/bonding/bond0
Currently Active Slave: eno2

The ping on the other machine should lose at most one or two replies. Bring eno1 back:

sudo ip link set eno1 up

Because eno1 is the primary interface, the bond switches back to it once its link is up again, and the Link Failure Count of eno1 increases by one. For a more realistic test, unplug the cable or shut down the switch port, which also exercises the switch side.

Step 6 - Switching to LACP (802.3ad)

Once the switch ports are configured as an LACP port-channel, edit the parameters block of bond0:

sudo nano /etc/netplan/01-bond0.yaml
      parameters:
        mode: 802.3ad
        lacp-rate: fast
        mii-monitor-interval: 100
        transmit-hash-policy: layer3+4

lacp-rate: fast exchanges LACP packets every second instead of every 30 seconds, so a dead link is detected sooner; set the same rate on the switch. transmit-hash-policy: layer3+4 spreads flows across links using IP addresses and ports instead of MAC addresses only, which balances much better when most traffic goes through a single gateway. The primary key only applies to active-backup, so remove it.

Apply the change with the same safety net:

sudo netplan try

Check the LACP negotiation:

grep -E "Bonding Mode|Transmit Hash|Aggregator ID|Partner Mac" /proc/net/bonding/bond0
Bonding Mode: IEEE 802.3ad Dynamic link aggregation
Transmit Hash Policy: layer3+4 (1)
        Aggregator ID: 1
        Partner Mac Address: 44:4c:a8:9a:10:01
Aggregator ID: 1
Aggregator ID: 1

Both interfaces must show the same Aggregator ID, and the partner MAC must be non-zero. A partner address of 00:00:00:00:00:00 means the switch is not speaking LACP on that port.

Configuring a bond on Rocky Linux 9

Rocky Linux 9, AlmaLinux 9 and RHEL 9 manage the network with NetworkManager, and the legacy ifcfg files are deprecated there, so use nmcli. Create the bond with its options and addressing:

sudo nmcli connection add type bond con-name bond0 ifname bond0 \
  bond.options "mode=active-backup,miimon=100,primary=eno1" \
  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"

Add both interfaces as members:

sudo nmcli connection add type ethernet con-name bond0-eno1 ifname eno1 master bond0
sudo nmcli connection add type ethernet con-name bond0-eno2 ifname eno2 master bond0

List the connections, then deactivate the old profile of eno1 and activate the bond from the out-of-band console, since this interrupts SSH:

nmcli connection show
sudo nmcli connection down eno1
sudo nmcli connection up bond0

Verify it with cat /proc/net/bonding/bond0 as in Step 4. For LACP, change the options and reactivate the connection:

sudo nmcli connection modify bond0 bond.options "mode=802.3ad,miimon=100,lacp_rate=fast,xmit_hash_policy=layer3+4"
sudo nmcli connection up bond0

Troubleshooting

  • netplan try reverts or SSH drops: an older file in /etc/netplan/ still configures eno1 or eno2. Run sudo netplan get to see the merged configuration and make sure only the bond carries addresses.
  • Permissions for /etc/netplan/01-bond0.yaml are too open: run sudo chmod 600 on the file.
  • Bond has no connectivity in 802.3ad mode: the switch ports are not in an LACP port-channel, or they are in a static (non-LACP) one. Check the partner MAC as shown in Step 6.
  • One member shows MII Status: down: check the cable and switch port with ip -br link and sudo ethtool eno2; Link detected: no points to a physical problem.
  • LACP works but traffic uses only one link: a single flow always uses one link. With many flows, confirm Transmit Hash Policy: layer3+4.

Conclusion

You combined two interfaces into bond0 on Ubuntu 24.04, verified its state in /proc/net/bonding/bond0, proved that failover works and moved the bond to LACP. Test failover again after every switch or cabling change. As next steps, add VLAN interfaces on top of the bond with Netplan's vlans section, alert on bond member failures in your monitoring system, or bond a second NIC pair for a separate private network.