Files
ferrix/docs/lab/prod/on-router/README.md
T
Rayhaan JaufeerallyandClaude Fable 5.1 fd496d26bf feature: run on the router itself: protoc-free build, per-peer source address
Preparing to run ferrix next to BIRD on the production router.

- build: the config proto is now parsed in pure Rust, so building needs no
  `protoc` binary. It previously worked only where one happened to be
  installed; the Dockerfile in this repo could not have built.
- peers gain `local_address`, the source IP for connections we open (and
  therefore the next hop we advertise). When both speakers share a host
  the OS would otherwise pick an arbitrary local address and the peer,
  which identifies us by address, would refuse the session. Address-family
  mismatches are rejected at config load; an address the host lacks shows
  up as the peer's backoff reason.
- docs/lab/prod/on-router: static musl cross-build instructions, config,
  hardened systemd unit (unprivileged, SIGTERM gives BIRD a Cease),
  loopback addresses for networkd, the BIRD stanza for a same-host
  multihop session, and reverse-proxy examples with TLS and a password,
  since the API has no authentication.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-20 18:15:09 +02:00

2.6 KiB

Running ferrix_bgp on the production router

ferrix and BIRD run side by side on pr01 and peer over two loopback addresses. Students reach the status page through a reverse proxy that adds TLS and a password. Nothing here has been run on the router; treat each step as something to check.

1. Build a static Linux binary (on the Mac)

The x86_64-unknown-linux-musl target and Homebrew's musl cross-linker are enough; the router needs no Rust toolchain and no protoc.

CARGO_TARGET_X86_64_UNKNOWN_LINUX_MUSL_LINKER=x86_64-linux-musl-gcc \
  cargo build --release -p bgp --target x86_64-unknown-linux-musl

scp target/x86_64-unknown-linux-musl/release/bgp pr01:/tmp/ferrix-bgp

Check the router really is x86-64 first (uname -m).

2. Install on the router

install -m 0755 /tmp/ferrix-bgp /usr/local/bin/ferrix-bgp
install -d /etc/ferrix-bgp
install -m 0644 ferrix.textpb /etc/ferrix-bgp/ferrix.textpb
install -m 0644 ferrix-bgp.service /etc/systemd/system/ferrix-bgp.service

3. Loopback addresses

Merge 05-lab-lo.network into the networkd file that matches lo, then networkctl reload and confirm with ip -6 addr show dev lo.

4. BIRD

Replace the protocol bgp ferrix stanza with bird-ferrix-local.conf, then birdc configure check and birdc configure timeout 300 / confirm.

5. Start

systemctl daemon-reload
systemctl enable --now ferrix-bgp
journalctl -u ferrix-bgp -f
birdc show protocols all ferrix

6. Let students in

The API has no authentication and announces into a real AS, so do not expose port 8080. Put a reverse proxy in front with TLS and a class password. The event stream is long-lived, so the proxy must not buffer it.

Caddy:

lab.example.net {
    basic_auth {
        student <hash from `caddy hash-password`>
    }
    reverse_proxy 127.0.0.1:8080 {
        flush_interval -1
    }
}

nginx, inside a TLS server block:

location / {
    auth_basic "BGP lab";
    auth_basic_user_file /etc/nginx/lab.htpasswd;
    proxy_pass http://127.0.0.1:8080;
    proxy_http_version 1.1;
    proxy_buffering off;
    proxy_read_timeout 1h;
}

Restricting the proxy to the university's address ranges as well is cheap and worth doing.

Things to know

  • Announced routes live in memory. A restart of the service forgets them and students have to announce again.
  • Stopping the service sends BIRD a Cease first, so restarts reconnect at once.
  • ferrix's own safety net is local_route_policy; BIRD's import filter and import limit are the second one. Keep both.