ExaBGP
Overview
ExaBGP is the Python "BGP swiss army knife" from Exa Networks. Instead of being a traditional routing stack, it lets software talk BGP. It runs as a daemon driven by a plain text configuration, announces and withdraws routes on command through a named pipe CLI (exabgp cli), and streams every BGP event it receives as JSON to helper processes that you write in any language.
That makes it a good fit for injecting routes from scripts and controllers, steering or blackholing traffic during DDoS mitigation, announcing anycast service addresses with health checks, and prototyping BGP behaviour including FlowSpec.
A bare BGP daemon has nothing to show on its own, so this SecureAnyCloud image ships a complete, self-contained BGP reference deployment on a single VM. As soon as the VM boots, sudo exabgp cli show neighbor summary shows an established session. One announce route command later, you can watch your route arrive at the peer in real time, so you can see BGP working before you point the daemon at your own routers.
What you get:
- ExaBGP 5.0.9 (
exabgpandexabgp-cli) in a dedicated virtual environment at/opt/exabgp/venv, pinned to the official upstream release and verified by SHA-256 - A primary ExaBGP (AS 65001), the daemon you drive with
sudo exabgp cli. It dials out to the demo peer and listens nowhere. - Runtime control of the primary over the named pipe CLI:
sudo exabgp cli <command> - A demo peer ExaBGP (AS 65002) listening on an internal loopback range address only (
10.255.255.2:179), authenticated with a per-VM TCP-MD5 key - A real eBGP session between the two that reaches established, with static routes propagating in both directions and every BGP event the peer receives logged as JSON to
/var/log/exabgp/peer-events.jsonl - JSON event logs of everything the daemons receive, at
/var/log/exabgp/peer-events.jsonland/var/log/exabgp/primary-events.jsonl - A per-VM TCP-MD5 key generated at first boot and stored at
/root/exabgp-credentials.txt(root only) - Secure by default: no port is open on the public interface, and BGP listens only on the internal demo link
- The unprivileged
exabgpsystem account, with only the two capabilities it needs - 24/7 SecureAnyCloud support
Deploying on Azure
Launch the image from the Azure Marketplace on a Standard_B2s (or larger) VM. ExaBGP is a lightweight, pure Python daemon, and Standard_B2s (2 vCPU / 4 GB) is ample for the reference deployment and for a modest production route injector.
SSH in as azureuser with the key you selected at launch:
ssh azureuser@<vm-ip>On first boot the appliance generates this VM's unique TCP-MD5 session key, renders both ExaBGP configurations, validates them with exabgp validate and brings the reference deployment up. It then proves that the session establishes, routes propagate both ways and a live CLI injection lands, before it writes its first-boot sentinel.
No two VMs share a key, and the image itself contains no key at all.
Confirm the authenticated eBGP session is established
show neighbor summary lists the primary daemon's peers and their session state. The demo peer (10.255.255.2, AS 65002) is established, and it gets there only because both ends share this VM's TCP-MD5 key:
sudo exabgp cli show neighbor summaryExpected output:
Peer AS up/down state | #sent #recvd 10.255.255.2 65002 0:00:51 established 26 22Check that routes propagate in both directions
The Adjacency RIB In shows what the primary has received from the demo peer, its static route 192.0.2.0/24. The Adjacency RIB Out shows what the primary is advertising to the peer, its own static route 203.0.113.0/24:
sudo exabgp cli show adj-rib in
sudo exabgp cli show adj-rib outExpected output:
10.255.255.2 ipv4 unicast 192.0.2.0/24 next-hop 10.255.255.2 10.255.255.2 ipv4 unicast 203.0.113.0/24 next-hop 10.255.255.1You can verify the reverse direction from a file. The demo peer runs an ExaBGP API process that appends every BGP event it receives to a JSON log, and the arrival of the primary's route is recorded there:
sudo jq -c 'select(.type=="update") | .neighbor.message.update.announce // empty' /var/log/exabgp/peer-events.jsonl | head -3Expected output:
{"ipv4 unicast":{"10.255.255.1":[{"nlri":"203.0.113.0/24"}]}}Inject a route live from the CLI
Route injection is what ExaBGP is for. Announce a prefix on the primary and watch it arrive at the demo peer in real time:
sudo exabgp cli announce route 198.51.100.0/24 next-hop 10.255.255.1 sleep 3
sudo jq -c 'select(.type=="update") | .neighbor.message.update.announce // empty' /var/log/exabgp/peer-events.jsonl | tail -1Expected output:
{"ipv4 unicast":{"10.255.255.1":[{"nlri":"198.51.100.0/24"}]}}Withdraw the route just as easily. The peer logs the withdrawal too:
sudo exabgp cli withdraw route 198.51.100.0/24 next-hop 10.255.255.1 sleep 3
sudo jq -c 'select(.type=="update") | .neighbor.message.update.withdraw // empty' /var/log/exabgp/peer-events.jsonl | tail -1Expected output:
{"ipv4 unicast":[{"nlri":"198.51.100.0/24"}]}Confirm the secure defaults
Nothing is exposed on the VM's routable interface. The primary daemon listens nowhere because it dials out, and the demo peer's BGP listener is bound to the internal demo address 10.255.255.2 only. This VM's TCP-MD5 key lives only in /root/exabgp-credentials.txt, readable by root alone. Check the listeners:
sudo ss -lntH | awk '{print $1, $4}' | grep -E '10.255.255|:179'
sudo grep -v '^#' /root/exabgp-credentials.txt | head -2Expected output. BGP listens on the internal demo link only, and nothing listens on eth0:
LISTEN 10.255.255.2:179Peering with your own routers
The primary daemon's configuration is at /etc/exabgp/exabgp.conf. To peer with your own routers, add a neighbor block for each one. A minimal example:
neighbor <remote-peer-ip> { router-id <this-vm-private-ip>; local-address <this-vm-private-ip>; local-as 65001; peer-as <remote-as>; md5-password "<a-shared-md5-key>"; static { route <prefix-to-announce> next-hop self; } }Open TCP 179 to those peers in your Azure Network Security Group, then apply the change with sudo systemctl restart exabgp.
You can drive everything at runtime without editing the config. Use sudo exabgp cli announce route <prefix> next-hop <ip> and sudo exabgp cli withdraw route <prefix> next-hop <ip>, and run sudo exabgp cli help for the full command set.
To feed received routes into your own automation, add an ExaBGP process block. The shipped /usr/local/sbin/exabgp-route-log.sh is a working example that streams every event as JSON to a file.
Managing the service
sudo systemctl status exabgp --no-pager sudo journalctl -u exabgp -n 50 --no-pagerThe demo peer (exabgp-peer.service) exists only to make the shipped image a working reference deployment. Once you have configured your own peers, you can disable it for a clean single-daemon setup with sudo systemctl disable --now exabgp-peer.service.
Support
Every SecureAnyCloud deployment is patched at build time, ships with unattended security updates enabled, and includes 24/7 SecureAnyCloud support. For help with this image, contact support through the Azure Marketplace listing or at secureanycloud.com.
Deploy on Azure
Launch ExaBGP on Ubuntu 24.04 LTS on Azure with 24/7 support from SecureAnyCloud.
View this image
Need Help?
Our support team is available 24/7.
sales@secureanycloud.com