FRRouting BGP Configuration on a Linux VPS
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 withebgp-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:
activateenables the neighbor within this address family. Required because we disabledbgp default ipv4-unicast.networktells 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 80tears down the session if the peer sends more than 500,000 IPv4 prefixes. The80generates 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 to10.- 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:
- The dummy interface is up (
ip addr show dummy-bgp). - The route exists in the kernel (
ip route show YOUR_PREFIX_V4). - The
networkstatement 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:
- Firewall: Can you reach the peer on TCP 179?
sudo nft list ruleset | grep 179 - Peer IP: Is the neighbor IP correct? Typos are the most common cause.
sudo vtysh -c "show bgp neighbors PEER_IPV4" | grep "BGP state" - 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.
- GTSM: If
ttl-security hops 1is set but the peer is multiple hops away (through a NAT or tunnel), the TTL check fails. Removettl-securityand useebgp-multihopinstead for multi-hop sessions.
Prefix not visible externally
Your session is established but the prefix does not appear on looking glasses.
-
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.
-
Check the kernel route:
ip route show YOUR_PREFIX_V4If missing, the dummy interface is down or misconfigured.
-
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