OpenBSD Handbook

    Theme
    • Part I. Install & Configure
      • Introduction to OpenBSD
      • Installing OpenBSD
      • The X Window System
      • Networking on OpenBSD
      • System Configuration
      • OpenBSD Basics
      • Managing Software: Packages and Ports
    • Part II. Daily Operations
      • OpenBSD Desktop Environments
      • Multimedia
      • Printing
      • Linux Compatibility
      • Windows Compatibility
      • Games
    • Part III. System Administration
      • Virtualization
      • Storage and File Systems
      • Updating and Upgrading
      • Localization
      • The OpenBSD Boot Process
      • Security
    • Part IV. Networking & Daemons
      • Services
        • Database
          • MariaDB
          • PostgreSQL
          • Redis
          • memcached
        • Directory
          • YP (NIS)
          • LDAP
        • File
          • NFS
          • Samba
        • FTP Services
          • ftpd
          • ProFTPD
          • vsftpd
          • Pure-FTPd
          • TFTP
        • Mail
          • OpenSMTPD Mail Server
          • Dovecot IMAP and POP3 Server
          • Postfix
          • Exim
          • Rspamd
        • Name
          • Unbound DNS Resolver
          • NSD Authoritative DNS Server
          • BIND DNS Server
        • Networking
          • OpenBGPD
          • rad
          • DHCP on OpenBSD
          • slaacd
        • Web
          • Apache HTTP Server
          • nginx Web Server
          • OpenBSD httpd Web Server
          • relayd Reverse Proxy
        • Logging
          • syslogd
        • Monitoring
          • SNMP
        • Remote Access
          • Audit OpenSSH
          • OpenSSH Server
        • File Synchronization
          • rsync
        • Messaging
          • RabbitMQ Message Broker
        • Time
          • NTP Time Synchronization
        • Load Balancing
          • Build Redundant Load-Balanced Gateways
          • Load Balance Services with NAT or DSR
          • Build an HA HTTPS Load Balancer
      • PF
        • pfctl cheat sheet
        • PF Anchors
        • PF Filter Rules
        • PF Forwarding
        • PF Lists and Macros
        • PF Load Balancing
        • PF Logging
        • PF NAT
        • PF Options
        • PF Policies
        • PF Shortcuts
        • PF Tables
      • Advanced Networking
        • High Availability and State Replication
        • Multi-WAN and Policy-Based Routing
        • VPN and Cryptographic Tunneling
        • Classic and Lightweight Tunnels
        • IPv6 at Scale
        • QoS and Traffic Shaping
        • MPLS and Label Distribution
        • Network Services at Scale
        • Virtualization and Host Networking
        • Large-Scale L2 and L3 Design
        • Telemetry, Logging, and Flow Export
        • Hardening and Operational Safety
        • Reference Architectures
        • Troubleshooting Playbooks
      • Serial Communication
    • Part V. Miscellaneous
      • Virtualization Cheat Sheet
      • OpenBSD Cheatsheet
      • How-to Guides
        • Installation and First Boot
          • Complete the First 30 Minutes After Installation
          • Check Hardware Compatibility Before Installing
          • Bootstrap Wi-Fi Firmware Without Ethernet
          • Run OpenBSD as a Virtual Machine Guest
          • Install OpenBSD on a VPS or Cloud Server
          • Install OpenBSD with Full-Disk Encryption
          • Dual-Boot OpenBSD on a UEFI System
          • Automate OpenBSD Installation with Autoinstall and PXE
        • Desktops and Laptops
          • Set Up OpenBSD as a Laptop or Workstation
          • Configure Laptop Power Management
          • Troubleshoot Web Browsers on OpenBSD
          • Use Plan 9 Tools on OpenBSD
          • Build a Minimal Desktop with suckless Tools
          • Install Z shell (zsh)
        • Networking and Remote Access
          • Create an Administrator Account with doas and SSH Keys
          • Configure Secure Remote Access with OpenSSH
          • Use FIDO Security Keys with OpenSSH
          • Configure Wi-Fi Roaming and Wired Failover
          • Troubleshoot PF, NAT, and Routing
          • Route Multiple VLANs with PF
          • Configure a Road-Warrior WireGuard VPN
          • Route IPv6 Networks without NAT
          • Test OpenBGPD with Two Providers
          • Unlock an Internal Service with an SSH Key
          • Build a Simple Router and Firewall
        • Servers and Services
          • Set Up WordPress on OpenBSD
          • Build a Mail Server with OpenSMTPD, Dovecot, and Rspamd
        • Security, Maintenance and Recovery
          • Establish a Conservative Security Baseline
          • Recover Access and Reset the Root Password
          • Collect OpenBSD Diagnostic Evidence
          • Troubleshoot Package Installation and Update Failures
          • Schedule Recurring Maintenance
          • Monitor an OpenBSD System
          • Back Up and Restore an OpenBSD System
          • Configure softraid RAID1
          • Recover an OpenBSD System That Does Not Boot
        • Building, Automation and Virtual Machines
          • Manage OpenBSD with Ansible
          • Build Third-Party Software from Ports
          • Build OpenBSD from Source
          • Plan a Docker Workload Migration to OpenBSD
      • OpenBSD for Linux Users
      • OpenBSD for FreeBSD Users
      • OpenBSD for macOS Users
    • OpenBSD FAQ
    • OpenBSD Architectures
      • OpenBSD Package Search
        • Synopsis
        • Design Considerations
        • Configuration
          • 1) Service lifecycle and skeleton
          • 2) Single-homed eBGP to an upstream (announce specific prefixes)
          • 3) Dual-homed eBGP (prefer one upstream with localpref; communities on egress)
          • 4) iBGP within the AS (small fabric, full mesh)
          • 5) RPKI origin validation (using rpki-client)
          • 6) Anycast service advertisement inside the AS
        • Verification
        • Troubleshooting
        • See Also

        OpenBGPD

        Synopsis #

        Run BGP on OpenBSD with the base system daemon bgpd(8) . Write its policy in bgpd.conf(5) , manage it with bgpctl(8) , and control the service with rcctl(8) . Add optional origin validation with rpki-client(8) . The examples cover external peering, multiple providers, iBGP within a site or POP, and policies using communities and local preference.

        For a complete dual-provider setup with traffic tests, export filtering, and failover, follow Test OpenBGPD with Two Providers .

        Design Considerations #

        • Policy-first. Default to “deny” and explicitly allow intended imports and announcements. Keep filters close to neighbors and keep global defaults conservative.
        • Deterministic preference. Set localpref for inbound path selection inside the AS; use communities for structured policy signaling.
        • iBGP peers. Use a full mesh for a small network. For larger networks, use route reflectors to reduce the number of peering sessions.
        • RPKI. Validate origins for received routes; drop ovs invalid. Schedule rpki-client(8) to refresh ROAs.
        • Route checks. Inspect bgpctl show summary, show neighbor, and show rib {in,out} after changes and when diagnosing failures.
        • Change control. Stage edits, syntax-check, and keep a roll-back path (console or timed revert) when touching upstream sessions.

        Configuration #

        OpenBSD 8.0 defaults to announce as-4byte enforce: a BGP session is established only if the neighbor advertises the 4-byte AS capability. This applies even when both AS numbers fit in two bytes. For a legacy peer that lacks the capability, set announce as-4byte yes in that neighbor block only when the compatibility exception is required.

        1) Service lifecycle and skeleton #

        Create a minimal skeleton with the local AS and router ID. Enable the daemon.

        ## /etc/bgpd.conf — minimal skeleton
        AS 64512
        router-id 198.51.100.2
        
        doas rcctl enable bgpd
          # Start on boot
        doas bgpd -n -f /etc/bgpd.conf
          # Syntax check (no start)
        doas rcctl start bgpd
          # Launch the daemon
        

        2) Single-homed eBGP to an upstream (announce specific prefixes) #

        Assumptions:

        • Public prefixes: 198.51.100.0/24, 2001:db8:100::/48
        • Upstream neighbor: 203.0.113.1, neighbor AS 64500
        • eBGP source address: 203.0.113.2, on the same link as the upstream
        • The IPv6 family requires suitable IPv6 next-hop reachability; configure and test it with the provider
        ## /etc/bgpd.conf — eBGP to one ISP with explicit outbound and guarded inbound
        AS 64512
        router-id 198.51.100.2
        
        # Prefixes intended for announcement
        prefix-set "our-net" {
            198.51.100.0/24,
            2001:db8:100::/48
        }
        
        network prefix-set "our-net"
        
        neighbor 203.0.113.1 {
            remote-as 64500
            descr "ISP-A"
            local-address 203.0.113.2
            enforce neighbor-as yes
            max-prefix 500000 restart 15        # Tune per provider guidance
            announce IPv4 unicast
            announce IPv6 unicast
        }
        
        # Inbound: accept from the upstream (subject to max-prefix and future filters)
        allow from 203.0.113.1
        
        # Outbound: announce only approved prefixes to this neighbor
        allow to 203.0.113.1 prefix-set "our-net"
        

        Reload and verify:

        doas bgpctl reload
          # Graceful reconfiguration
        doas bgpctl show summary
          # Session state, prefix counts, per-neighbor stats
        doas bgpctl show neighbor 203.0.113.1
          # Capabilities and last error (if any)
        doas bgpctl show rib out neighbor 203.0.113.1
          # Only approved prefixes should be advertised
        

        3) Dual-homed eBGP (prefer one upstream with localpref; communities on egress) #

        Assumptions:

        • Second upstream: 198.51.100.1, AS 64496
        • Preference: routes from ISP-A should win over ISP-B by higher localpref
        • Egress tagging: set a reference community on announced routes (example only)
        ## /etc/bgpd.conf — two providers; deterministic preference and egress tagging
        AS 64512
        router-id 198.51.100.2
        
        prefix-set "our-net" { 198.51.100.0/24, 2001:db8:100::/48 }
        
        network prefix-set "our-net"
        
        neighbor 203.0.113.1 {
            remote-as 64500
            descr "ISP-A"
            local-address 203.0.113.2
            enforce neighbor-as yes
            max-prefix 500000 restart 15
            announce IPv4 unicast
            announce IPv6 unicast
        }
        
        neighbor 198.51.100.1 {
            remote-as 64496
            descr "ISP-B"
            local-address 198.51.100.2
            enforce neighbor-as yes
            max-prefix 500000 restart 15
            announce IPv4 unicast
            announce IPv6 unicast
        }
        
        # Inbound acceptance from both
        allow from 203.0.113.1
        allow from 198.51.100.1
        
        # Prefer ISP-A inside the AS
        match from 203.0.113.1 set localpref 200
        match from 198.51.100.1 set localpref 150
        
        # Outbound: announce the same set to both, with a reference community
        allow to 203.0.113.1 prefix-set "our-net" set community 64512:100
        allow to 198.51.100.1 prefix-set "our-net" set community 64512:100
        

        Verification focus:

        doas bgpctl show rib as 64500
          # Routes learned from ISP-A (AS path view)
        doas bgpctl show rib | egrep '198\.51\.100\.0/24|2001:db8:100::/48'
          # Originated prefixes present in the RIB before export
        doas bgpctl show rib detail
          # Inspect route local preference and communities
        

        A static network statement originates a prefix independently of an existing kernel route. Ensure the forwarding path for that prefix actually works; originating an unreachable aggregate still advertises it. An explicit export policy is also required.

        4) iBGP within the AS (small fabric, full mesh) #

        Assumptions:

        • Two routers, R1 (this host) and R2 at 10.0.0.2, both in AS 64512
        • Full-mesh iBGP; R1 preferred as exit to ISP-A via higher localpref applied to routes learned from that ISP
        ## /etc/bgpd.conf — add a simple iBGP peer
        AS 64512
        router-id 10.0.0.1
        
        neighbor 10.0.0.2 {
            remote-as 64512
            descr "iBGP-R2"
            announce IPv4 unicast
            announce IPv6 unicast
        }
        
        # iBGP acceptance
        allow from 10.0.0.2
        
        # Optional: restrict exchange to internal routes
        prefix-set "internal" { 10.10.0.0/16, 10.20.0.0/16 }
        allow to 10.0.0.2 prefix-set "internal"
        

        Verification focus:

        doas bgpctl show summary
          # iBGP session should be Established
        doas bgpctl show rib neighbor 10.0.0.2
          # Routes accepted from the peer
        doas bgpctl show rib out neighbor 10.0.0.2
          # Routes advertised to the peer (filtered by "internal")
        

        For larger topologies, introduce route reflectors to avoid a full mesh. Keep reflectors simple and limit re-advertisement to required address families and scopes.

        5) RPKI origin validation (using rpki-client) #

        Run rpki-client(8) periodically to fetch and validate ROAs, then have bgpd load the generated set. Reject ovs invalid by policy.

        doas rpki-client
        

        Schedule rpki-client periodically using cron and reload bgpd only after successful output generation. It is not an rcctl service. Follow the installed rpki-client(8) scheduling example and preserve failed-run diagnostics.

        Include the generated configuration in the main configuration:

        include "/var/db/rpki-client/openbgpd"
        

        After the normal neighbor import allowances, reject invalid origins:

        deny from any ovs invalid
        

        Filter rules use last-match semantics unless quick applies. A later broad allow would override this denial. Check both accepted and rejected routes after adding the policy.

        Observe RPKI state:

        doas bgpctl show rib in neighbor 203.0.113.1 ovs invalid
          # Routes rejected due to invalid origin
        doas bgpctl show rib ovs not-found | head
          # Routes without covering ROAs (informational)
        

        6) Anycast service advertisement inside the AS #

        For an internal anycast service (for example, resolver 10.10.255.53/32), originate the address on each serving node (lo0 alias or static route), and announce using iBGP. ECMP or policy then steers clients.

        ## /etc/bgpd.conf — originate a host route for anycast via iBGP
        AS 64512
        router-id 10.0.0.1
        
        network 10.10.255.53/32
          # Originate the prefix; add the intended neighbor and export policy
        

        Verification #

        Core commands with bgpctl(8) :

        doas bgpctl show summary
          # Session state and counters
        doas bgpctl show neighbor <addr>
          # Capabilities, timers, last error
        doas bgpctl show rib
          # Loc-RIB; append 'in' or 'out' with 'neighbor <addr>' for per-peer views
        doas bgpctl show rib community 64512:100
          # Filter by community; useful for policy checks
        doas bgpctl log verbose
          # Increase bgpd(8) log verbosity temporarily during troubleshooting
        

        Wire-level and system checks:

        doas tcpdump -ni egress port 179
          # Observe BGP OPEN/KEEPALIVE/UPDATE on the wire
        route -n show -inet ; route -n show -inet6
          # Originating/static routes present for announced prefixes
        

        Troubleshooting #

        • Session stuck Idle/Active. Confirm IP reachability, local-address, and that PF allows TCP/179. Validate that remote-as matches the peer’s configured local AS and that enforce neighbor-as is not blocking expected paths.
        • No announcements leaving. The route must exist in the RIB (network statement or static route). Confirm that the prefix is originated and an explicit allow to rule targets the neighbor. Inspect bgpctl show rib out neighbor ....
        • Excessive routes from a peer. Choose an appropriate max-prefix limit and restart interval in minutes. Constrain scope with prefix-lists or prefix-set filters.
        • Inbound path not preferred. Review localpref on received routes. Check whether more-specifics or MEDs override intent.
        • RPKI drops unexpected routes. Inspect bgpctl show rib in neighbor 203.0.113.1 ovs invalid and cross-check current ROAs on the parent ROA repository. Investigate ROA state before relaxing policy.
        • Flapping after reloads. Use bgpctl reload for graceful policy updates. For structural changes (peer add/remove), apply during maintenance windows or off-peak hours.

        See Also #

        • Networking
        • Advanced Networking
        • Man pages: bgpd(8) , bgpd.conf(5) , bgpctl(8) , rpki-client(8)
        • Related: MPLS and Label Distribution
        • Related: Reference Architectures
        Report a bug
        • Synopsis
        • Design Considerations
        • Configuration
          • 1) Service lifecycle and skeleton
          • 2) Single-homed eBGP to an upstream (announce specific prefixes)
          • 3) Dual-homed eBGP (prefer one upstream with localpref; communities on egress)
          • 4) iBGP within the AS (small fabric, full mesh)
          • 5) RPKI origin validation (using rpki-client)
          • 6) Anycast service advertisement inside the AS
        • Verification
        • Troubleshooting
        • See Also