DEV Community

Young Gao
Young Gao

Posted on

BGP from Scratch: Setting Up Your First Autonomous System with BIRD 2 in 2026

BGP from Scratch: Setting Up Your First Autonomous System with BIRD 2

Running your own Autonomous System isn't just for ISPs anymore. If you're multihoming across data centers, need provider-independent addressing, or want to control your traffic engineering — BGP is how you get there.

This guide takes you from zero to a working BGP setup with BIRD 2, including getting your ASN, configuring peering, and setting up RPKI.

Prerequisites

  • A server (VPS or dedicated) with a public interface
  • Your own ASN and at least one IP prefix (see below)
  • At least one upstream provider willing to establish a BGP session with you
  • Basic Linux networking knowledge

Getting Number Resources

Before you can run BGP, you need:

  1. An ASN — Your unique identifier in the global routing table
  2. IP space — At least a /48 IPv6 (or /24 IPv4, though these are scarce and expensive)

Through an RIR Directly

If you're in the RIPE NCC region (Europe, Middle East, parts of Central Asia), you can request resources directly if you're a LIR (Local Internet Registry) member, or through a sponsoring LIR if you're not.

The sponsorship path is most common for small operators:

  • Find a LIR sponsor that serves your region
  • The LIR submits a resource request to RIPE NCC on your behalf
  • Resources are registered under your organization — you maintain ownership
  • Annual costs are typically $60-90/year for ASN + IPv6

Important: Resources obtained through sponsorship belong to you, not the LIR. You can transfer sponsorship to any other LIR at any time.

For ARIN (North America), the process is similar but with different fee structures and policies.

Installing BIRD 2

BIRD 2 is the standard BGP daemon for Linux. It's lightweight, fast, and handles both IPv4 and IPv6 in a single instance.

# Debian/Ubuntu
sudo apt install bird2

# Or build from source for latest version
git clone https://gitlab.nic.cz/labs/bird.git
cd bird
autoreconf
./configure --prefix=/usr --sysconfdir=/etc/bird
make && sudo make install
Enter fullscreen mode Exit fullscreen mode

BIRD 2 Configuration

The main config lives at /etc/bird/bird.conf. Here's a production-ready starting point:

# /etc/bird/bird.conf

# Your ASN
define MY_ASN = 215000;

# Your prefixes
define MY_PREFIX_V6 = 2001:db8:abcd::/48;

# Router ID (use a stable IPv4 address, even for IPv6-only networks)
router id 10.0.0.1;

# Logging
log syslog all;
log "/var/log/bird.log" { warning, error, fatal };

# Device protocol - scans interfaces
protocol device {
    scan time 10;
}

# Direct protocol - learns connected routes
protocol direct {
    ipv6;
    interface "lo";
}

# Static routes for your prefixes (announce via BGP)
protocol static static_v6 {
    ipv6;
    route MY_PREFIX_V6 blackhole;
}

# Kernel protocol - installs routes into OS routing table
protocol kernel {
    ipv6 {
        export filter {
            # Only install routes learned from BGP
            if source = RTS_BGP then accept;
            reject;
        };
        import none;
    };
    scan time 15;
    learn;
}

# ============ Filters ============

# What we announce to upstreams
filter export_upstream {
    # Only announce our own prefixes
    if net = MY_PREFIX_V6 then accept;
    reject;
}

# What we accept from upstreams
filter import_upstream {
    # Accept default route
    if net = ::/0 then accept;

    # Reject bogons
    if net ~ [ ::/8+, fe80::/10+, fc00::/7+ ] then reject;

    # Reject too-specific prefixes
    if net.len > 48 then reject;

    accept;
}

# ============ BGP Sessions ============

# Template for upstream providers
template bgp upstream {
    local as MY_ASN;

    ipv6 {
        import filter import_upstream;
        export filter export_upstream;
        import limit 200000 action restart;
    };

    graceful restart on;
    long lived graceful restart on;

    error wait time 30, 300;
    error forget time 3600;
}

# Upstream Provider A
protocol bgp upstream_a from upstream {
    neighbor 2001:db8:1::1 as 64500;
    description "Transit Provider A";
}

# Upstream Provider B
protocol bgp upstream_b from upstream {
    neighbor 2001:db8:2::1 as 64501;
    description "Transit Provider B";
}
Enter fullscreen mode Exit fullscreen mode

Understanding the Data Flow

Your server
├── BIRD 2 daemon
│   ├── static_v6: Blackhole route for your prefix
│   ├── upstream_a: BGP session with Provider A
│   │   ├── Export: Your prefix (2001:db8:abcd::/48)
│   │   └── Import: Routes from Provider A (including ::/0)
│   ├── upstream_b: BGP session with Provider B
│   │   ├── Export: Your prefix
│   │   └── Import: Routes from Provider B
│   └── kernel: Installs best routes into Linux routing table
└── Linux kernel
    └── Routing table with learned routes
Enter fullscreen mode Exit fullscreen mode

When you start BIRD:

  1. The static_v6 protocol creates a blackhole route for your prefix
  2. BIRD announces your prefix to both upstreams via BGP
  3. Upstreams propagate your route to the global Internet
  4. Upstreams send you their routes (or just a default route)
  5. BIRD selects the best path and installs it in the kernel

Establishing Sessions

After starting BIRD, check session status:

sudo birdc show protocols all upstream_a
Enter fullscreen mode Exit fullscreen mode

Expected progression:

Idle → Connect → OpenSent → OpenConfirm → Established
Enter fullscreen mode Exit fullscreen mode

If it sticks at Connect or Active:

  • Check firewall allows TCP port 179 (BGP)
  • Verify neighbor IP and ASN are correct
  • Confirm the upstream has configured their end
# Debug BGP issues
sudo birdc show protocols all upstream_a
sudo birdc show route export upstream_a
sudo birdc show route import table upstream_a

# Check if your prefix is being announced
sudo birdc show route for 2001:db8:abcd::/48 all
Enter fullscreen mode Exit fullscreen mode

Securing Your Routes with RPKI

RPKI (Resource Public Key Infrastructure) protects against BGP hijacking by cryptographically verifying which ASN is authorized to announce a prefix.

Step 1: Create ROAs in the RIPE Portal

Log into the LIR portal (or ask your sponsoring LIR) and create Route Origin Authorizations:

Prefix: 2001:db8:abcd::/48
Origin ASN: AS215000
Max Length: 48
Enter fullscreen mode Exit fullscreen mode

Step 2: Run an RPKI Validator

# Install Routinator (RPKI validator by NLnet Labs)
sudo apt install routinator

# Initialize the TAL (Trust Anchor Locators)
routinator init --accept-arin-rpa

# Run as a service
sudo systemctl enable --now routinator
Enter fullscreen mode Exit fullscreen mode

Routinator serves validated ROAs over RTR protocol on port 3323.

Step 3: Configure BIRD to Use RPKI

# RPKI validator connection
protocol rpki rpki_validator {
    roa6 { table roa_v6; };
    remote "127.0.0.1" port 3323;
    retry keep 5;
    refresh keep 30;
    expire 600;
}

# ROA table
roa6 table roa_v6;

# Updated import filter with RPKI validation
filter import_upstream_rpki {
    if net = ::/0 then accept;
    if net ~ [ ::/8+, fe80::/10+, fc00::/7+ ] then reject;
    if net.len > 48 then reject;

    # RPKI validation
    if (roa_check(roa_v6, net, bgp_path.last) = ROA_INVALID) then {
        print "RPKI INVALID: ", net, " from AS", bgp_path.last;
        reject;
    }

    accept;
}
Enter fullscreen mode Exit fullscreen mode

Traffic Engineering Basics

With two upstreams, you can control traffic flow:

Prefer One Upstream for Outbound

filter import_upstream_preferred {
    # Same as import_upstream...

    # Prefer this upstream by setting higher local preference
    bgp_local_pref = 200;
    accept;
}

filter import_upstream_backup {
    # Lower preference = backup path
    bgp_local_pref = 100;
    accept;
}
Enter fullscreen mode Exit fullscreen mode

Influence Inbound Traffic with AS Path Prepending

filter export_upstream_prepend {
    if net = MY_PREFIX_V6 then {
        # Make this path look longer = less preferred by remote networks
        bgp_path.prepend(MY_ASN);
        bgp_path.prepend(MY_ASN);
        accept;
    }
    reject;
}
Enter fullscreen mode Exit fullscreen mode

Monitoring

Looking Glass

Check if your prefix is visible globally:

# Use Hurricane Electric's looking glass
curl -s "https://lg.he.net/api/v1/routes/2001:db8:abcd::/48" | jq

# Or check bgp.tools
# https://bgp.tools/prefix/2001:db8:abcd::/48
Enter fullscreen mode Exit fullscreen mode

Alerting

Set up BGP session monitoring:

# Simple check script
birdc show protocols | grep -E "upstream_[ab]" | grep -v Established && \
    echo "BGP SESSION DOWN" | mail -s "BGP Alert" noc@yourcompany.com
Enter fullscreen mode Exit fullscreen mode

Common Mistakes

  1. Not filtering bogons: Always filter RFC 1918, RFC 6598, documentation prefixes, and overly specific routes on import.

  2. No import limits: Without import limit, a misconfigured peer can crash your router by sending millions of routes. Set reasonable limits.

  3. Forgetting reverse DNS: Set up PTR records for your IP space. Essential for email and professional appearance.

  4. Single upstream = no benefit: An ASN with one upstream is just extra complexity. The value comes from multihoming.

  5. Not monitoring ROA status: ROAs expire. Set up monitoring to alert before expiry.

Next Steps

Once your basic setup is running:

  • Join an Internet Exchange (IX): Free peering with hundreds of networks. Most IXes require an ASN and a /48.
  • Set up communities: Use BGP communities to signal routing preferences to your upstreams.
  • Automate with IRR: Register your routing policy in an Internet Routing Registry for automated peering.
  • Consider Anycast: Announce the same prefix from multiple locations for geographic load balancing.

Running your own AS? What's your setup look like? Share your BIRD configs and peering stories in the comments.

Top comments (0)