FRRouting BGP on Linux: Dual-Uplink Failover Guide for Dedicated Servers

Updated on Oct 21, 2026
Mila H
15 MINS READ
Table of Contents
Dual-ISP BGP Setup with FRRouting

Many dedicated servers run with a single network cable and a single default route. If that uplink fails, the server is offline. With two upstream providers and BGP, the server keeps its IP addresses and moves traffic to the second provider in about a second.

In this guide, you will learn how to configure FRRouting BGP on a Linux dedicated server. If you have set up BGP on a MikroTik router, this will feel familiar. Peers, filters, and route maps work the same way, but the tool is different. Our BGP configuration on MikroTik VPS guide shows the RouterOS side.

Dual-ISP Network Plan

You will build a small setup with one Linux server and two upstream providers. Here is the network plan for this guide:

Item Value
Your server (FRR 10.7) AS 65010, router ID 192.0.2.1
Your prefix 192.0.2.0/24
ISP-A (primary) AS 65001, link 198.51.100.0/30 (you are .2, ISP is .1)
ISP-B (backup) AS 65002, link 203.0.113.0/30 (you are .2, ISP is .1)
Server NICs eth0 to ISP-A, eth1 to ISP-B
  • Both ISPs send you a default route (0.0.0.0/0). You accept only that route.
  • You send only your own prefix 192.0.2.0/24 to both ISPs.
  • ISP-A is preferred for outgoing traffic (local preference 200). ISP-B is the backup (local preference 100).
  • BFD finds a dead link in about 1 second, and BGP moves traffic to the other ISP.

This small lab is a base you can reuse when you configure FRRouting BGP on Linux for a real server.

Note: The ASN 65010 and the IP ranges above are for a lab. For a real setup, use your own public ASN, your own IP block, and the link IPs and ASNs your providers give you.

Server Requirements

Before you start to configure FRRouting BGP on a Linux dedicated server, make sure you have the items below:

  • A Linux dedicated server with two network ports or two VLANs for the two uplinks. A PerLod dedicated server with routed IP space is a good option for this setup.
  • Ubuntu 24.04 LTS. Also, these steps work on Ubuntu 22.04, Ubuntu 26.04, Debian 12, and Debian 13.
  • Root or sudo access, and access for IPMI, KVM, or console. Routing changes can lock you out of SSH.
  • For a lab: two more Linux machines or VMs to act as ISP-A and ISP-B.
  • For a real setup: your own ASN, provider-independent IP space, and a BGP session from each provider.

Note: Ask your hosting provider if BGP sessions are allowed and which link IPs you should use.

Also, check your interface names with the command below. This guide uses eth0 and eth1. Replace them with your names:

Bash
ip -br link

1. Install FRRouting 10.7 on Linux

Ubuntu and Debian include an FRR package, but it is usually an older version. To get FRR 10.7, you must use the official FRR repository. Its frr-10.7 branch installs FRR 10.7.x.

First, install the tools and add the FRR key with the commands below:

Bash
sudo apt updatesudo apt install curl gnupg lsb-release -ycurl -s https://deb.frrouting.org/frr/keys.gpg | sudo tee /usr/share/keyrings/frrouting.gpg > /dev/null

Then, add the repository and install FRR with the following commands:

Bash
FRRVER="frr-10.7"echo "deb [signed-by=/usr/share/keyrings/frrouting.gpg] https://deb.frrouting.org/frr $(lsb_release -s -c) $FRRVER" | sudo tee /etc/apt/sources.list.d/frr.listsudo apt updatesudo apt install frr frr-pythontools -y

Once you are done, check the version to verify the installation:

SQL
vtysh -c "show version"

2. Turn On the BGP and BFD Daemons

FRR runs each protocol as its own small program, called a daemon. BGP and BFD are off by default, so you must turn them on before you can use them. To do this, open the daemons file:

Bash
sudo nano /etc/frr/daemons

Find the following lines and change no to yes:

Bash
bgpd=yesbfdd=yes

Once you are done, save and exit. Also, you can do the same with one command:

Bash
sudo sed -i 's/^bgpd=no/bgpd=yes/; s/^bfdd=no/bfdd=yes/' /etc/frr/daemonsgrep -E '^(bgpd|bfdd)=' /etc/frr/daemons

FRR keeps all its settings in one file, which is /etc/frr/frr.conf. You must run the command below to check that the FRR command-line shell, called vtysh, saves its changes to that file:

Bash
cat /etc/frr/vtysh.conf

If you do not see service integrated-vtysh-config, you must add it with the command below:

Bash
echo 'service integrated-vtysh-config' | sudo tee -a /etc/frr/vtysh.conf

3. Prepare Linux Server for Routing

Before FRR can route traffic, Linux needs a few settings. In this step, you must turn on IP forwarding, set up your link IPs, and open the firewall for BGP and BFD.

Enable IP Forwarding and Loose RP Filter

Your server must pass traffic between networks, so IP forwarding has to be on. With two uplinks, a reply can come back on a different network port than the one the request used. The default strict filter drops those packets, so you must also set the reverse path filter to loose mode (value 2).

First, create the following file, which holds your kernel settings for routing:

Bash
sudo nano /etc/sysctl.d/99-bgp-router.conf

Add the following settings to the file:

Bash
net.ipv4.ip_forward = 1net.ipv4.conf.all.rp_filter = 2net.ipv4.conf.default.rp_filter = 2

Once you are done, save and exit. Then, apply it and check with the commands below:

Bash
sudo sysctl --systemsysctl net.ipv4.ip_forward net.ipv4.conf.all.rp_filter net.ipv4.conf.eth0.rp_filter net.ipv4.conf.eth1.rp_filter

If an interface still shows 1, you must set it too. Linux uses the higher value of all and the interface value:

Bash
sudo sysctl -w net.ipv4.conf.eth0.rp_filter=2sudo sysctl -w net.ipv4.conf.eth1.rp_filter=2

Your server needs an IP address on each uplink to talk to your providers. Also, you need one more address for the router ID, which stays the same if a link goes down. You can set all three with a Netplan file.

First, create the Netplan file with the command below:

Bash
ls /etc/netplan/sudo nano /etc/netplan/60-uplinks.yaml

Add the following content to the file:

Bash
network:  version: 2  ethernets:    eth0:      addresses:        - 198.51.100.2/30    eth1:      addresses:        - 203.0.113.2/30  dummy-devices:    dummy0:      addresses:        - 192.0.2.1/32

Note: Do not add a static default route. BGP will give you the default route. If your current Netplan file, for example, 50-cloud-init.yaml, already has one, remove it first. Keep console access ready in case you lose your SSH connection.

Then, set safe permissions and apply with a rollback timer:

Bash
sudo chmod 600 /etc/netplan/60-uplinks.yamlsudo netplan try

Press Enter to accept. Then, check with the command below:

Bash
ip -br addr

Open the Firewall for BGP and BFD

BGP uses TCP port 179. Single-hop BFD uses UDP port 3784. You must allow them only from your two providers. Example for UFW:

Bash
sudo ufw allow from 198.51.100.1 to any port 179 proto tcpsudo ufw allow from 203.0.113.1 to any port 179 proto tcpsudo ufw allow from 198.51.100.1 to any port 3784 proto udpsudo ufw allow from 203.0.113.1 to any port 3784 proto udp

How to Configure FRRouting BGP on a Linux Dedicated Server

Now that your Linux server is ready, you can set up FRR. You must write the full config file. Back up the old file and open it with the commands below:

Bash
sudo cp /etc/frr/frr.conf /etc/frr/frr.conf.baksudo nano /etc/frr/frr.conf

Delete the old content and paste this into the file:

Bash
frr defaults traditionalhostname edge1log syslog informational!! Your own prefix. Null0 gives BGP a route to announce.ip route 192.0.2.0/24 Null0!! BFD timers: 3 x 300 ms = about 900 ms to detect a dead linkbfd profile UPLINK  detect-multiplier 3  receive-interval 300  transmit-interval 300 exit!exit!! Prefix filtersip prefix-list PL-MY-NETS seq 10 permit 192.0.2.0/24ip prefix-list PL-DEFAULT-ONLY seq 10 permit 0.0.0.0/0!! Route maps: what we accept (IN) and what we send (OUT)route-map RM-ISPA-IN permit 10 match ip address prefix-list PL-DEFAULT-ONLY set local-preference 200exit!route-map RM-ISPB-IN permit 10 match ip address prefix-list PL-DEFAULT-ONLY set local-preference 100exit!route-map RM-ISPA-OUT permit 10 match ip address prefix-list PL-MY-NETS set metric 50exit!route-map RM-ISPB-OUT permit 10 match ip address prefix-list PL-MY-NETS set as-path prepend 65010 65010 set metric 200exit!router bgp 65010 bgp router-id 192.0.2.1 bgp log-neighbor-changes no bgp default ipv4-unicast bgp graceful-restart bgp graceful-restart restart-time 120 ! neighbor 198.51.100.1 remote-as 65001 neighbor 198.51.100.1 description ISP-A-PRIMARY neighbor 198.51.100.1 bfd profile UPLINK ! neighbor 203.0.113.1 remote-as 65002 neighbor 203.0.113.1 description ISP-B-BACKUP neighbor 203.0.113.1 bfd profile UPLINK ! address-family ipv4 unicast  network 192.0.2.0/24  neighbor 198.51.100.1 activate  neighbor 198.51.100.1 route-map RM-ISPA-IN in  neighbor 198.51.100.1 route-map RM-ISPA-OUT out  neighbor 198.51.100.1 maximum-prefix 5  neighbor 203.0.113.1 activate  neighbor 203.0.113.1 route-map RM-ISPB-IN in  neighbor 203.0.113.1 route-map RM-ISPB-OUT out  neighbor 203.0.113.1 maximum-prefix 5 exit-address-familyexit!

Save and exit the file. Make sure the owner and mode are correct, then check the syntax and load it:

Bash
sudo chown frr:frr /etc/frr/frr.confsudo chmod 640 /etc/frr/frr.confsudo systemctl restart frrsudo vtysh -c "show running-config"

Note: If your provider needs a BGP password, add this line under router bgp 65010 for each neighbor. Use the password your provider gave you:

Bash
neighbor 198.51.100.1 password YOUR_SECRET

How the FRR Config Works

The config file has many lines, but each part has one clear job. This section explains them, so you know what each setting does before you go live.

ASN and router ID: router bgp 65010 starts BGP with your ASN. bgp router-id 192.0.2.1 sets a fixed ID. Always set it manually, so it does not change when an IP changes.

Prefix filters: PL-DEFAULT-ONLY lets in only the default route. PL-MY-NETS lets out only your own prefix. This stops you from leaking routes between your two providers and stops a provider from sending you a huge table. If you need more than the default route, change the first list, for example, permit 0.0.0.0/0 le 24, and plan for more memory. maximum-prefix 5 closes the session if a provider sends too many routes by mistake.

Also, FRR needs a policy on every eBGP session; bgp ebgp-requires-policy is on by default. Without an in and out route map, FRR accepts and sends nothing, and show bgp summary shows (Policy). Your route maps handle this.

Local preference: Local preference decides which path your server uses to send traffic out. The higher value wins. ISP-A has 200 and ISP-B has 100, so the server uses ISP-A until it fails.

MED and AS-path prepend: MED tells a neighbor which of your links you prefer for incoming traffic. The lower value wins. But BGP compares MED only between routes from the same neighbor AS. Because ISP-A and ISP-B are different ASes, MED will not move traffic between them. That is why ISP-B also gets an AS-path prepend. It makes the path through ISP-B longer, so the Internet prefers ISP-A to reach you. MED is still useful if one ISP has two links to you.

Graceful restart: bgp graceful-restart lets the neighbors keep your routes for a short time while bgpd restarts, so a planned restart or upgrade does not drop traffic. restart-time 120 is the default value, shown here so it is clear in the config. It is meant for daemon restarts. Link failures are handled by BFD.

BFD: BFD sends tiny packets every 300 ms. If 3 packets are lost, it tells BGP to close the session at once. Without BFD, BGP waits for the hold timer (180 seconds by default) before it notices a silent failure. You can lower the BFD timers (for example, 100 ms), but only on stable links.

Optional: Set Up Two Lab ISP Routers

Skip this part if you already have real providers. For a lab, use two more Linux machines and install FRR on them with Steps 1 and 2. Connect each one to a separate network port on your server, using its own cable, VLAN, or bridge.

On the ISP-A lab router, add the link IP and a test address that both ISPs will own:

Bash
sudo ip addr add 198.51.100.1/30 dev eth0sudo ip addr add 198.18.0.100/32 dev losudo sysctl -w net.ipv4.ip_forward=1sudo nano /etc/frr/frr.conf

Paste into /etc/frr/frr.conf file on ISP-A:

Bash
frr defaults traditionalhostname isp-a!route-map ALLOW-ALL permit 10exit!router bgp 65001 bgp router-id 198.51.100.1 no bgp default ipv4-unicast neighbor 198.51.100.2 remote-as 65010 neighbor 198.51.100.2 bfd address-family ipv4 unicast  neighbor 198.51.100.2 activate  neighbor 198.51.100.2 default-originate  neighbor 198.51.100.2 route-map ALLOW-ALL in  neighbor 198.51.100.2 route-map ALLOW-ALL out exit-address-familyexit!

On the ISP-B lab router, repeat the same steps with these changes:

  • Link IP: 203.0.113.1/30
  • Hostname: isp-b
  • BGP AS: router bgp 65002
  • Router ID: bgp router-id 203.0.113.1
  • Neighbor: 203.0.113.2
  • Test address: add the same 198.18.0.100/32 on lo

Then, restart FRR on both routers with the following command:

Bash
sudo systemctl restart frr

Confirm the BGP Setup Works

Now check that everything works before you test a failover. Run the commands below on your server. They show whether both BGP sessions are up, whether BFD is running, and which routes you send and receive:

Bash
sudo vtysh -c "show bgp summary"sudo vtysh -c "show bfd peers brief"sudo vtysh -c "show bgp ipv4 unicast"sudo vtysh -c "show ip route 0.0.0.0/0"sudo vtysh -c "show bgp ipv4 unicast neighbors 198.51.100.1 advertised-routes"sudo vtysh -c "show bgp neighbors 198.51.100.1" | grep -i gracefulip route get 198.18.0.100

Also, you can run the command below to check the kernel table:

Bash
ip route show proto bgp

Optional: Use Two ISPs at Once

Also, you can configure FRRouting BGP on Linux to use both links at once. Use this only if both links have a similar speed and you want to share outgoing traffic. For plain failover, skip it.

BGP uses more than one path only when the paths are equal. So first, make both local preferences the same. Edit the file:

Bash
sudo nano /etc/frr/frr.conf

Change set local-preference 200 in RM-ISPA-IN to set local-preference 100. Then, add two lines to the BGP block. The first goes under router bgp 65010 and the second under address-family ipv4 unicast:

Bash
 bgp bestpath as-path multipath-relax
Bash
  maximum-paths 2

multipath-relax is needed because the two paths come from different ASes. Next, tell Linux to spread flows by IP and port:

Bash
echo 'net.ipv4.fib_multipath_hash_policy = 1' | sudo tee -a /etc/sysctl.d/99-bgp-router.confsudo sysctl --system

The default route should now show two next hops. Multipath helps only the traffic that leaves your server. Incoming traffic still follows your prepend and MED settings. To go back to failover mode, you can undo these changes.

After you configure FRRouting BGP on Linux, always test failover before you move real traffic. Run these tests in the lab, or in a maintenance window on a real server. Use the console, not an SSH session via the link you are testing.

Start a ping from your router ID address. The address stays the same on both links:

Bash
ping -I 192.0.2.1 -i 0.2 198.18.0.100

In a second terminal, drop all incoming packets on eth0. This looks like a silent failure, where the link stays up, but traffic is lost:

Bash
sudo iptables -I INPUT -i eth0 -j DROP

After about 1 second, BFD goes down, and BGP closes the ISP-A session. Check with:

Bash
sudo vtysh -c "show bfd peers brief"sudo vtysh -c "show bgp summary"ip route get 198.18.0.100

Now the route uses 203.0.113.1 on eth1, and the ping works again. You should lose only a few packets. Then, remove the rule with:

Bash
sudo iptables -D INPUT -i eth0 -j DROP

BGP and BFD come back up, and traffic returns to ISP-A because it has the higher local preference.

Test 2: Graceful restart

In this test, you can restart FRR while a ping runs to see how the connection behaves. First, check that both sides support graceful restart, then restart FRR while a ping runs:

Bash
sudo vtysh -c "show bgp neighbors 198.51.100.1" | grep -i gracefulsudo systemctl restart frr

Watch the ping and the BGP summary. The time to recover depends on your neighbor. Always test a planned restart in the lab.

Test 3: Prefix filter

In this test, you can add a test prefix and check that the filter blocks it. Only your own prefix should be sent to the providers:

Bash
sudo vtysh -c "configure terminal" -c "ip route 10.99.0.0/24 Null0" -c "router bgp 65010" -c "address-family ipv4 unicast" -c "network 10.99.0.0/24"sudo vtysh -c "show bgp ipv4 unicast neighbors 198.51.100.1 advertised-routes"

Only 192.0.2.0/24 should appear. Then, remove the test prefix:

Bash
sudo vtysh -c "configure terminal" -c "router bgp 65010" -c "address-family ipv4 unicast" -c "no network 10.99.0.0/24" -c "exit-address-family" -c "exit" -c "no ip route 10.99.0.0/24 Null0"

You can save your running config if you changed anything in vtysh:

Bash
sudo vtysh -c "write memory"

Troubleshooting the FRR Setup

If something does not work, you can use the table below to find the cause. Start with the problem you see, then check the settings listed beside it.

Problem What to check
Session stuck in Active or Connect Link IPs, firewall for TCP 179, neighbor IP and remote ASN
(Policy) in show bgp summary The neighbor has no in or out route map
BFD stays down Firewall for UDP 3784, and BFD must be enabled on both sides
Default route missing PL-DEFAULT-ONLY is too strict, or the ISP is not sending a default route
Replies are dropped Reverse path filter must be loose (rp_filter = 2)
Config does not load Run sudo /usr/lib/frr/frr-reload.py --test /etc/frr/frr.conf and read the error

You can run the command below to watch FRR logs and check for errors:

Bash
sudo journalctl -u frr -f

For more network guides, you can check the Networking and Connectivity tutorials on PerLod.

Conclusion

At this point, you have learned how to configure FRRouting BGP on a Linux dedicated server with two providers, route filters, and failover. Before going live, use your real ASN and IPs, check your providers’ rules, and test failover again.

We hope you enjoy this guide. For more detailed information, you can check the FRRouting BGP documentation.

You can use PerLod dedicated servers with routed IP space or private lab networking to run advanced Linux routing workloads like this one.