FRRouting BGP Configuration on a Linux VPS

13 min read·Matthieu·BGPFRRoutingFRRNetworkingIPv6Firewall|

Step-by-step FRRouting BGP setup for announcing your own IPv4 and IPv6 prefixes from a Linux VPS. Covers installation, vtysh configuration, prefix-lists, route-maps, GTSM, and nftables firewall rules.

This tutorial walks through configuring FRRouting (FRR) to announce your own IPv4 and IPv6 prefixes via BGP from a Linux VPS. Every command is tested on Debian 12 and Ubuntu 24.04 with FRR 10.5.

By the end you will have a running eBGP session with your upstream provider, dual-stack prefix origination through persistent dummy interfaces, inbound and outbound route filtering, GTSM session security, and nftables firewall rules locking down TCP 179.

If you are evaluating whether to use FRR or BIRD2, both are solid choices. FRR uses a Cisco-style CLI (vtysh) which feels familiar if you have worked with IOS or JunOS. BIRD2 uses a declarative config file. This guide covers FRR. For BIRD2, see BIRD2 BGP Configuration on a Linux VPS.

For background on bringing your own IP space to a VPS, see BGP: Bring Your Own IP to a VPS.

Prerequisites

Before starting, you need:

  • A public ASN (Autonomous System Number). If you do not have one yet, see Register an ASN at RIPE NCC.
  • At least one IPv4 /24 or IPv6 /48 prefix assigned to your ASN.
  • ROA (Route Origin Authorization) objects created in your RIR's RPKI dashboard. See .
  • An upstream provider offering a BGP session (IP transit or peering). You will need: the provider's ASN, the peer IPv4 and IPv6 addresses, and an agreed MD5 password if applicable.
  • A Linux VPS running Debian 12 (Bookworm) or Ubuntu 24.04 (Noble). Root or sudo access.

Throughout this guide, replace these placeholders with your actual values:

Placeholder Meaning Example
YOUR_ASN Your AS number 212345
PEER_ASN Upstream provider AS number 6939
PEER_IPV4 Provider's BGP peer IPv4 198.51.100.1
PEER_IPV6 Provider's BGP peer IPv6 2001:db8:1::1
YOUR_IPV4 Your side of the BGP peering (IPv4) 198.51.100.2
YOUR_IPV6 Your side of the BGP peering (IPv6) 2001:db8:1::2
YOUR_PREFIX_V4 Your IPv4 prefix 203.0.113.0/24
YOUR_PREFIX_V6 Your IPv6 prefix 2001:db8:abc::/48
MD5_PASSWORD Agreed TCP MD5 password (from your provider)

How do I install FRRouting on Debian 12 and Ubuntu 24.04?

Install FRR from the official apt repository to get the latest stable release (10.5.x as of March 2026). The distribution packages in Debian and Ubuntu are often several major versions behind. The official repo tracks current stable and supports both Bookworm and Noble.

Add the GPG signing key:

curl -s https://deb.frrouting.org/frr/keys.gpg | sudo tee /usr/share/keyrings/frrouting.gpg > /dev/null

Add the repository. Use frr-stable to track the latest stable branch:

FRRVER="frr-stable"
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.list

Install FRR and the Python tools (needed for frr-reload.py):

sudo apt update && sudo apt install -y frr frr-pythontools

Verify the installed version:

sudo vtysh -c "show version" | head -1

Expected output:

FRRouting 10.5.3 (<hostname>) on Linux(6.8.0-xxx-generic).

FRR installs as a systemd service. Enable it so it survives reboots and start it immediately:

sudo systemctl enable --now frr

Verify it is running:

systemctl status frr

You should see active (running) in the output. FRR runs multiple daemons (zebra, bgpd, etc.) managed by a single parent process.

How do I enable the BGP daemon in FRR?

FRR ships with all protocol daemons disabled except zebra. You must explicitly enable bgpd in the daemons file before FRR will start a BGP process. The daemons file lives at /etc/frr/daemons.

Edit the daemons file:

sudo nano /etc/frr/daemons

Find the bgpd line and set it to yes:

bgpd=yes

All other daemons (ospfd, isisd, etc.) can stay at no unless you need them. Zebra is always enabled and manages the kernel routing table.

Here is what each daemon does:

Daemon Purpose Default
zebra Kernel route management, interface tracking always on
bgpd BGP protocol no
ospfd OSPFv2 no
ospf6d OSPFv3 (IPv6) no
ripd RIP no
isisd IS-IS no
staticd Static routes via vtysh no

Restart FRR to pick up the change:

sudo systemctl restart frr

Verify bgpd is running:

sudo vtysh -c "show bgp summary"

You should see % BGP instance not found. That is expected: bgpd is running, but no router bgp has been configured yet. We will do that next.

vtysh basics

vtysh is FRR's integrated shell. It provides a Cisco-like CLI for configuring all FRR daemons from a single interface. A few essentials before we start configuring.

Enter vtysh:

sudo vtysh

You are now in the FRR CLI. The prompt shows the hostname. The modes you will use:

Mode Enter with Prompt Purpose
Exec (default) # Show commands, verification
Config configure terminal (config)# Global configuration
Router BGP router bgp ASN (config-router)# BGP configuration
Address-family address-family ipv4 unicast (config-router-af)# Per-AFI/SAFI config

To save the running configuration to disk:

write memory

This writes to /etc/frr/frr.conf. FRR uses an integrated config model by default: all daemon configurations live in a single file.

Exit vtysh with exit or end (returns to exec mode from any sub-mode).

How do I configure a BGP session with my upstream provider?

Enter vtysh and configure terminal mode to set up the core BGP configuration. This creates the router process, sets the router ID, disables automatic IPv4 unicast (so you control exactly which address families are active per neighbor), and defines the upstream peer.

sudo vtysh
configure terminal

router bgp YOUR_ASN
 bgp router-id YOUR_IPV4
 no bgp default ipv4-unicast

 neighbor PEER_IPV4 remote-as PEER_ASN
 neighbor PEER_IPV4 description Upstream-v4
 neighbor PEER_IPV4 password MD5_PASSWORD
 neighbor PEER_IPV4 ttl-security hops 1
 neighbor PEER_IPV4 soft-reconfiguration inbound

 neighbor PEER_IPV6 remote-as PEER_ASN
 neighbor PEER_IPV6 description Upstream-v6
 neighbor PEER_IPV6 password MD5_PASSWORD
 neighbor PEER_IPV6 ttl-security hops 1
 neighbor PEER_IPV6 soft-reconfiguration inbound

What each directive does:

  • bgp router-id: A 32-bit identifier, typically your primary IPv4 address. Must be unique on the peering.
  • no bgp default ipv4-unicast: Prevents FRR from automatically activating IPv4 unicast for every neighbor. You activate address families explicitly. This is standard practice for dual-stack setups.
  • ttl-security hops 1: Enables GTSM (RFC 5082). Requires packets to arrive with TTL 254 (one hop away). Drops spoofed BGP packets from remote sources. Mutually exclusive with ebgp-multihop.
  • password: Sets TCP MD5 authentication (RFC 2385). Both sides must agree on the same string. Not all providers use this. Omit if your provider does not require it.
  • soft-reconfiguration inbound: Stores received routes in memory so you can apply policy changes without resetting the session. Uses more RAM but avoids session flaps during filter updates.

Do not exit config mode yet. We will add address families and filters next.

How do I announce my own IPv4 and IPv6 prefixes?

Prefix origination in FRR requires two things: a network statement in the BGP config, and the prefix present in the kernel routing table. The simplest way to inject the prefix into the kernel is through a dummy interface. We will set up the dummy interfaces first, then configure the BGP address families.

How do I create persistent dummy interfaces for prefix origination?

A dummy interface is a loopback-like interface that holds an IP address without being tied to physical hardware. FRR's zebra picks up routes from the kernel, so if your prefix is assigned to a dummy interface, zebra installs it and bgpd can announce it.

Create the dummy interfaces using systemd-networkd so they persist across reboots.

Create the netdev file:

sudo tee /etc/systemd/network/10-dummy-bgp.netdev > /dev/null << 'EOF'
[NetDev]
Name=dummy-bgp
Kind=dummy
EOF

Create the network file with your prefixes:

sudo tee /etc/systemd/network/10-dummy-bgp.network > /dev/null << 'EOF'
[Match]
Name=dummy-bgp

[Address]
Address=YOUR_PREFIX_V4

[Address]
Address=YOUR_PREFIX_V6
EOF

For the IPv4 address, use the first usable IP in your prefix (e.g., 203.0.113.1/24). For IPv6, use any address within your prefix (e.g., 2001:db8:abc::1/48).

Enable systemd-networkd if not already active, and restart it:

sudo systemctl enable --now systemd-networkd
sudo systemctl restart systemd-networkd

Verify the dummy interface is up:

ip addr show dummy-bgp

You should see both your IPv4 and IPv6 addresses assigned to the interface.

Verify the routes are in the kernel:

ip route show dev dummy-bgp
ip -6 route show dev dummy-bgp

Address-family configuration

Back in vtysh config mode (or re-enter with sudo vtysh then configure terminal then router bgp YOUR_ASN):

 address-family ipv4 unicast
  network YOUR_PREFIX_V4
  neighbor PEER_IPV4 activate
  neighbor PEER_IPV4 route-map EXPORT-V4 out
  neighbor PEER_IPV4 route-map IMPORT-V4 in
  neighbor PEER_IPV4 prefix-list BOGONS-V4 in
  neighbor PEER_IPV4 maximum-prefix 500000 80
 exit-address-family

 address-family ipv6 unicast
  network YOUR_PREFIX_V6
  neighbor PEER_IPV6 activate
  neighbor PEER_IPV6 route-map EXPORT-V6 out
  neighbor PEER_IPV6 route-map IMPORT-V6 in
  neighbor PEER_IPV6 prefix-list BOGONS-V6 in
  neighbor PEER_IPV6 maximum-prefix 200000 80
 exit-address-family

Details:

  • activate enables the neighbor within this address family. Required because we disabled bgp default ipv4-unicast.
  • network tells bgpd to originate this prefix. The prefix must exist in the kernel routing table (zebra picks it up from the dummy interface).
  • maximum-prefix 500000 80 tears down the session if the peer sends more than 500,000 IPv4 prefixes. The 80 generates a warning at 80% (400,000). Adjust based on whether you receive a full table or default route only. For a default-route-only session, set this to 10.
  • The route-map and prefix-list references point to filters we define next.

How do I filter BGP routes with prefix-lists and route-maps?

Route filtering is not optional. Without outbound filters, a misconfiguration could leak prefixes you do not own. Without inbound filters, you accept bogon routes and potentially blackhole traffic. This follows RFC 7454 (BGP Operations and Security).

For a deeper look at filtering strategies, see .

Outbound prefix-lists

Only announce prefixes you own. Nothing else.

ip prefix-list OUR-PREFIXES-V4 seq 10 permit YOUR_PREFIX_V4
ip prefix-list OUR-PREFIXES-V4 seq 999 deny any

ipv6 prefix-list OUR-PREFIXES-V6 seq 10 permit YOUR_PREFIX_V6
ipv6 prefix-list OUR-PREFIXES-V6 seq 999 deny any

If you announce multiple prefixes, add more permit lines with increasing sequence numbers.

Inbound bogon prefix-lists

Reject prefixes that should never appear on the public internet. This list follows the NLNOG BGP Filter Guide:

ip prefix-list BOGONS-V4 seq 10 deny 0.0.0.0/8 le 32
ip prefix-list BOGONS-V4 seq 20 deny 10.0.0.0/8 le 32
ip prefix-list BOGONS-V4 seq 30 deny 100.64.0.0/10 le 32
ip prefix-list BOGONS-V4 seq 40 deny 127.0.0.0/8 le 32
ip prefix-list BOGONS-V4 seq 50 deny 169.254.0.0/16 le 32
ip prefix-list BOGONS-V4 seq 60 deny 172.16.0.0/12 le 32
ip prefix-list BOGONS-V4 seq 70 deny 192.0.2.0/24 le 32
ip prefix-list BOGONS-V4 seq 80 deny 192.88.99.0/24 le 32
ip prefix-list BOGONS-V4 seq 90 deny 192.168.0.0/16 le 32
ip prefix-list BOGONS-V4 seq 100 deny 198.18.0.0/15 le 32
ip prefix-list BOGONS-V4 seq 110 deny 198.51.100.0/24 le 32
ip prefix-list BOGONS-V4 seq 120 deny 203.0.113.0/24 le 32
ip prefix-list BOGONS-V4 seq 130 deny 224.0.0.0/4 le 32
ip prefix-list BOGONS-V4 seq 140 deny 240.0.0.0/4 le 32
ip prefix-list BOGONS-V4 seq 999 permit 0.0.0.0/0 le 24

ipv6 prefix-list BOGONS-V6 seq 10 deny ::/8 le 128
ipv6 prefix-list BOGONS-V6 seq 20 deny 100::/64 le 128
ipv6 prefix-list BOGONS-V6 seq 30 deny 2001:2::/48 le 128
ipv6 prefix-list BOGONS-V6 seq 40 deny 2001:10::/28 le 128
ipv6 prefix-list BOGONS-V6 seq 50 deny 2001:db8::/32 le 128
ipv6 prefix-list BOGONS-V6 seq 60 deny 3fff::/20 le 128
ipv6 prefix-list BOGONS-V6 seq 70 deny 2002::/16 le 128
ipv6 prefix-list BOGONS-V6 seq 80 deny 3ffe::/16 le 128
ipv6 prefix-list BOGONS-V6 seq 90 deny 5f00::/16 le 128
ipv6 prefix-list BOGONS-V6 seq 100 deny fc00::/7 le 128
ipv6 prefix-list BOGONS-V6 seq 110 deny fe80::/10 le 128
ipv6 prefix-list BOGONS-V6 seq 120 deny fec0::/10 le 128
ipv6 prefix-list BOGONS-V6 seq 130 deny ff00::/8 le 128
ipv6 prefix-list BOGONS-V6 seq 999 permit ::/0 le 48

The final permit line on each list accepts everything not explicitly denied. The le 24 (IPv4) and le 48 (IPv6) reject overly specific prefixes: no one should announce a /25 or longer on IPv4, or a /49 or longer on IPv6.

Route-maps

Route-maps tie the prefix-lists together and give you a place to add more policy later (local-pref, communities, AS-path prepending).

route-map EXPORT-V4 permit 10
 match ip address prefix-list OUR-PREFIXES-V4

route-map EXPORT-V6 permit 10
 match ipv6 address prefix-list OUR-PREFIXES-V6

route-map IMPORT-V4 permit 10
 match ip address prefix-list BOGONS-V4

route-map IMPORT-V6 permit 10
 match ipv6 address prefix-list BOGONS-V6

The export route-maps only permit your own prefixes. Everything else is implicitly denied (FRR denies anything not explicitly matched by a route-map). The import route-maps pass traffic through the bogon prefix-list, which denies the bogon ranges and permits everything else.

Save the configuration:

write memory

Verify the config was written:

ls -la /etc/frr/frr.conf

The file should show a recent modification timestamp with ownership frr:frr and permissions 640.

How do I secure the BGP session and protect TCP 179?

BGP runs on TCP port 179. Any host on the internet can attempt to connect to it. Beyond the GTSM and MD5 authentication already configured, you need firewall rules to restrict TCP 179 to your peer addresses.

nftables firewall rules

Install nftables if it is not already present. On Ubuntu 24.04 minimal installs, it is not included by default:

sudo apt install -y nftables

Create the /etc/nftables.d/ directory for drop-in config files and add an include directive to the main nftables config so custom rules survive reboots:

sudo mkdir -p /etc/nftables.d
echo 'include "/etc/nftables.d/*.conf"' | sudo tee -a /etc/nftables.conf

Create a dedicated nftables config file for BGP:

sudo tee /etc/nftables.d/bgp.conf > /dev/null << 'EOF'
table inet bgp-filter {
    set bgp_peers_v4 {
        type ipv4_addr
        elements = { PEER_IPV4 }
    }

    set bgp_peers_v6 {
        type ipv6_addr
        elements = { PEER_IPV6 }
    }

    chain input {
        type filter hook input priority 0; policy accept;

        # Allow BGP from known peers only
        tcp dport 179 ip saddr @bgp_peers_v4 accept
        tcp dport 179 ip6 saddr @bgp_peers_v6 accept

        # Allow BGP return traffic (our side initiates)
        tcp sport 179 ip saddr @bgp_peers_v4 accept
        tcp sport 179 ip6 saddr @bgp_peers_v6 accept

        # Drop all other BGP attempts
        tcp dport 179 drop
        tcp sport 179 drop
    }
}
EOF

If you already have an nftables configuration, merge these rules into your existing input chain instead of creating a separate table. The approach above is self-contained and does not interfere with other firewall rules.

To add multiple peers, add their IPs to the elements set:

elements = { 198.51.100.1, 203.0.113.1 }

Enable nftables so rules persist across reboots, then reload to pick up the new include:

sudo systemctl enable --now nftables
sudo systemctl reload nftables

Verify the rules are loaded:

sudo nft list table inet bgp-filter

You should see your peer IPs in the sets and the chain rules listed.

Security summary

Protection What it does Configured where
GTSM (ttl-security hops 1) Drops BGP packets not from a directly connected peer vtysh, per neighbor
TCP MD5 (password) Authenticates TCP segments, prevents RST injection vtysh, per neighbor
Prefix-list (outbound) Only announces your own prefixes vtysh, route-map
Prefix-list (inbound) Rejects bogon/reserved ranges vtysh, per neighbor
maximum-prefix Tears down session if peer sends too many routes vtysh, per address-family
nftables Restricts TCP 179 to known peer IPs /etc/nftables.d/bgp.conf

How do I verify the BGP session and prefix propagation?

After saving the config with write memory, the BGP session should start establishing. Verification happens in three stages: local vtysh checks, kernel routing table, and external looking glasses.

vtysh verification commands

Command What it shows
show bgp summary All peers, their state, prefixes received
show bgp ipv4 unicast IPv4 BGP table
show bgp ipv6 unicast IPv6 BGP table
show bgp ipv4 unicast neighbors PEER_IPV4 advertised-routes What you are sending to the peer
show bgp ipv4 unicast neighbors PEER_IPV4 received-routes What the peer is sending you (requires soft-reconfiguration inbound)
show ip bgp neighbors PEER_IPV4 Detailed neighbor state, uptime, capabilities

Check the session state:

sudo vtysh -c "show bgp summary"

Expected output (trimmed):

IPv4 Unicast Summary:
BGP router identifier YOUR_IPV4, local AS number YOUR_ASN, vrf default
Neighbor        V    AS   MsgRcvd  MsgSent  TblVer   InQ  OutQ  Up/Down  State/PfxRcd
PEER_IPV4       4  PEER_ASN   1205     843       0      0     0 01:23:45        12

Notice the State/PfxRcd column. A number means the session is established and that many prefixes were received. If you see Active, Connect, or OpenSent, the session is not up yet. Check the next section for troubleshooting.

Verify your prefix is being advertised:

sudo vtysh -c "show bgp ipv4 unicast neighbors PEER_IPV4 advertised-routes"

Your prefix should appear in the output. If it does not, check that:

  1. The dummy interface is up (ip addr show dummy-bgp).
  2. The route exists in the kernel (ip route show YOUR_PREFIX_V4).
  3. The network statement matches the exact prefix and mask.

External verification

Check from outside your network that the prefix is visible on the internet.

From your local machine (not the VPS):

traceroute YOUR_PREFIX_V4_FIRST_IP

Use bgp.tools to look up your prefix and verify:

  • The origin AS matches your ASN.
  • The ROA status shows "Valid" (not "Unknown" or "Invalid").
  • The prefix is visible from multiple vantage points.

You can also query the RIPE RIS looking glass:

curl -s "https://stat.ripe.net/data/looking-glass/data.json?resource=YOUR_PREFIX_V4" | python3 -m json.tool | head -50

Persisting the configuration

FRR saves its configuration to /etc/frr/frr.conf when you run write memory in vtysh. As long as the FRR service is enabled (systemctl enable frr), it reads this file on boot.

Double-check both persistence mechanisms:

sudo systemctl is-enabled frr

Should return enabled.

sudo vtysh -c "show running-config" | head -5

Compare with the saved file:

head -5 /etc/frr/frr.conf

They should match. If they diverge, run write memory again.

The dummy interface persists through systemd-networkd (configured earlier). Verify:

sudo systemctl is-enabled systemd-networkd

Complete annotated frr.conf

Here is a complete example configuration for reference. Replace all placeholders with your values.

frr version 10.5.3
frr defaults traditional
hostname bgp-vps
log syslog informational
!
! --- Prefix-lists: outbound (only our prefixes) ---
ip prefix-list OUR-PREFIXES-V4 seq 10 permit 203.0.113.0/24
ip prefix-list OUR-PREFIXES-V4 seq 999 deny any
!
ipv6 prefix-list OUR-PREFIXES-V6 seq 10 permit 2001:db8:abc::/48
ipv6 prefix-list OUR-PREFIXES-V6 seq 999 deny any
!
! --- Prefix-lists: inbound bogon filters ---
ip prefix-list BOGONS-V4 seq 10 deny 0.0.0.0/8 le 32
ip prefix-list BOGONS-V4 seq 20 deny 10.0.0.0/8 le 32
ip prefix-list BOGONS-V4 seq 30 deny 100.64.0.0/10 le 32
ip prefix-list BOGONS-V4 seq 40 deny 127.0.0.0/8 le 32
ip prefix-list BOGONS-V4 seq 50 deny 169.254.0.0/16 le 32
ip prefix-list BOGONS-V4 seq 60 deny 172.16.0.0/12 le 32
ip prefix-list BOGONS-V4 seq 70 deny 192.0.2.0/24 le 32
ip prefix-list BOGONS-V4 seq 80 deny 192.88.99.0/24 le 32
ip prefix-list BOGONS-V4 seq 90 deny 192.168.0.0/16 le 32
ip prefix-list BOGONS-V4 seq 100 deny 198.18.0.0/15 le 32
ip prefix-list BOGONS-V4 seq 110 deny 198.51.100.0/24 le 32
ip prefix-list BOGONS-V4 seq 120 deny 203.0.113.0/24 le 32
ip prefix-list BOGONS-V4 seq 130 deny 224.0.0.0/4 le 32
ip prefix-list BOGONS-V4 seq 140 deny 240.0.0.0/4 le 32
ip prefix-list BOGONS-V4 seq 999 permit 0.0.0.0/0 le 24
!
ipv6 prefix-list BOGONS-V6 seq 10 deny ::/8 le 128
ipv6 prefix-list BOGONS-V6 seq 20 deny 100::/64 le 128
ipv6 prefix-list BOGONS-V6 seq 30 deny 2001:2::/48 le 128
ipv6 prefix-list BOGONS-V6 seq 40 deny 2001:10::/28 le 128
ipv6 prefix-list BOGONS-V6 seq 50 deny 2001:db8::/32 le 128
ipv6 prefix-list BOGONS-V6 seq 60 deny 3fff::/20 le 128
ipv6 prefix-list BOGONS-V6 seq 70 deny 2002::/16 le 128
ipv6 prefix-list BOGONS-V6 seq 80 deny 3ffe::/16 le 128
ipv6 prefix-list BOGONS-V6 seq 90 deny 5f00::/16 le 128
ipv6 prefix-list BOGONS-V6 seq 100 deny fc00::/7 le 128
ipv6 prefix-list BOGONS-V6 seq 110 deny fe80::/10 le 128
ipv6 prefix-list BOGONS-V6 seq 120 deny fec0::/10 le 128
ipv6 prefix-list BOGONS-V6 seq 130 deny ff00::/8 le 128
ipv6 prefix-list BOGONS-V6 seq 999 permit ::/0 le 48
!
! --- Route-maps ---
route-map EXPORT-V4 permit 10
 match ip address prefix-list OUR-PREFIXES-V4
!
route-map EXPORT-V6 permit 10
 match ipv6 address prefix-list OUR-PREFIXES-V6
!
route-map IMPORT-V4 permit 10
 match ip address prefix-list BOGONS-V4
!
route-map IMPORT-V6 permit 10
 match ipv6 address prefix-list BOGONS-V6
!
! --- BGP configuration ---
router bgp 212345
 bgp router-id 198.51.100.2
 no bgp default ipv4-unicast
 !
 ! IPv4 peer
 neighbor 198.51.100.1 remote-as 6939
 neighbor 198.51.100.1 description Upstream-v4
 neighbor 198.51.100.1 password SECRET
 neighbor 198.51.100.1 ttl-security hops 1
 neighbor 198.51.100.1 soft-reconfiguration inbound
 !
 ! IPv6 peer
 neighbor 2001:db8:1::1 remote-as 6939
 neighbor 2001:db8:1::1 description Upstream-v6
 neighbor 2001:db8:1::1 password SECRET
 neighbor 2001:db8:1::1 ttl-security hops 1
 neighbor 2001:db8:1::1 soft-reconfiguration inbound
 !
 address-family ipv4 unicast
  network 203.0.113.0/24
  neighbor 198.51.100.1 activate
  neighbor 198.51.100.1 route-map EXPORT-V4 out
  neighbor 198.51.100.1 route-map IMPORT-V4 in
  neighbor 198.51.100.1 prefix-list BOGONS-V4 in
  neighbor 198.51.100.1 maximum-prefix 500000 80
 exit-address-family
 !
 address-family ipv6 unicast
  network 2001:db8:abc::/48
  neighbor 2001:db8:1::1 activate
  neighbor 2001:db8:1::1 route-map EXPORT-V6 out
  neighbor 2001:db8:1::1 route-map IMPORT-V6 in
  neighbor 2001:db8:1::1 prefix-list BOGONS-V6 in
  neighbor 2001:db8:1::1 maximum-prefix 200000 80
 exit-address-family
!

Troubleshooting

BGP session stuck in Active or Connect state

The session is trying to establish but TCP 179 cannot connect. Check in order:

  1. Firewall: Can you reach the peer on TCP 179?
    sudo nft list ruleset | grep 179
    
  2. Peer IP: Is the neighbor IP correct? Typos are the most common cause.
    sudo vtysh -c "show bgp neighbors PEER_IPV4" | grep "BGP state"
    
  3. MD5 mismatch: If using TCP MD5, both sides must have the exact same password string. There is no helpful error message for this. The session silently fails to establish.
  4. GTSM: If ttl-security hops 1 is set but the peer is multiple hops away (through a NAT or tunnel), the TTL check fails. Remove ttl-security and use ebgp-multihop instead for multi-hop sessions.

Prefix not visible externally

Your session is established but the prefix does not appear on looking glasses.

  1. Check advertised routes:

    sudo vtysh -c "show bgp ipv4 unicast neighbors PEER_IPV4 advertised-routes"
    

    If your prefix is not listed, the outbound filter is blocking it. Verify the prefix-list matches your exact prefix.

  2. Check the kernel route:

    ip route show YOUR_PREFIX_V4
    

    If missing, the dummy interface is down or misconfigured.

  3. Check ROA validity: If your ROA is missing or incorrect, RPKI-validating networks will drop your announcement. Verify at RIPE RPKI Validator.

Reading the logs

FRR logs to syslog by default. To follow BGP-specific events:

journalctl -u frr -f --grep="bgpd"

For more verbose output, enable debug temporarily in vtysh:

debug bgp updates
debug bgp keepalives

Turn it off when done (it is very verbose):

no debug bgp updates
no debug bgp keepalives

Next steps

  • Add RPKI validation: Configure FRR's built-in RPKI support to validate incoming routes against ROA data. See .
  • Advanced filtering: Build more granular route-maps with community matching, AS-path filters, and local-preference tuning. See .
  • Monitoring: Set up BGP session monitoring with tools like Prometheus + bgp_exporter or Zabbix SNMP traps to get alerts when a session drops.

Copyright 2026 Virtua.Cloud. All rights reserved. This content is original work by the Virtua.Cloud team. Reproduction, republication, or redistribution without written permission is prohibited.

Ready to try it yourself?

Deploy your own server in seconds. Linux, Windows, or FreeBSD.

See VPS Plans