Files
ferrix/docs/content/docs/operations/deployment.md
T
Rayhaan JaufeerallyandClaude Opus 5.5 dc275f99d7
ci / check (push) Canceled after 0s
ci / docs (push) Canceled after 0s
ci / interop (push) Canceled after 0s
ci / fuzz (push) Canceled after 0s
Add a documentation website, built with Zola
The documentation moves from READMEs into a site in docs/: getting
started, a user guide, operations, a reference, and development pages,
written in the style of network vendors' documentation (docs/STYLE.md).
bin/bgp/README.md and docs/RFCs.md are folded into it.

- A theme of its own in the International Typographic Style, in blues,
  with self-hosted Inter and JetBrains Mono, search over Zola's index,
  dark mode, and no resources loaded from other hosts.
- Example configurations in docs/examples/, shown on the pages and
  checked with `bgp --check` in CI.
- A test that fails when a field of config.proto is missing from the
  configuration reference.
- A CI job that builds the site; Zola fails on broken links and anchors.
- A hardened systemd unit, tried under systemd with kernel routes on.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-03 15:12:43 +02:00

6.0 KiB

+++ title = "Deploying Ferrix" description = "Describes how to run Ferrix as a systemd service, secure the hosts and interfaces around it, change its configuration, and restart it." weight = 1

[extra] nav = "Deployment" +++

This topic describes how to deploy Ferrix on a Linux router as a systemd service, and the security measures that a production deployment requires.

Running Ferrix as a systemd Service

The provided systemd unit runs the daemon as an unprivileged user, with only the capabilities that it requires, and restricts its access to the rest of the system.

To install the service:

  1. Create the system user and the configuration directory.

    sudo useradd --system --no-create-home --shell /usr/sbin/nologin ferrix
    sudo install -d -m 0750 -o root -g ferrix /etc/ferrix
    sudo install -m 0640 -o root -g ferrix server.textpb /etc/ferrix/server.textpb
    
  2. Install the unit file as /etc/systemd/system/ferrix.service.

    {{ file(name="ferrix.service", lang="ini") }}

  3. Enable and start the service.

    sudo systemctl daemon-reload
    sudo systemctl enable --now ferrix
    
  4. Verify that the service is running.

    systemctl status ferrix
    journalctl -u ferrix -f
    

The ExecStartPre command validates the configuration before the daemon starts. If the configuration is invalid, the service does not start, and the journal contains the error.

The sandboxing options in the unit have been tested with kernel route installation enabled. The command systemd-analyze security ferrix rates the unit's exposure level as 2.1 (OK).

Securing the Deployment

HTTP Interface

Caution

The status page and HTTP API do not require authentication. They expose the configuration, all received routes, and the state of every neighbor. Bind http_endpoint to a loopback address, or place it behind a reverse proxy that requires authentication.

BGP Port Filtering

Ferrix closes connections from addresses that are not configured neighbors before it reads from them. Ferrix does not support TCP-AO or TCP MD5 authentication. Configure the host firewall to accept connections to TCP port 179 only from neighbor addresses.

The following nftables rules, in the input chain of an inet filter table, drop BGP connections from any other address:

nft add rule inet filter input tcp dport 179 ip saddr != { 203.0.113.0, 203.0.113.2 } drop
nft add rule inet filter input tcp dport 179 ip6 saddr != { 2001:db8:ffff:1::1 } drop

RPKI Cache Connection

The RTR connection is not authenticated. Run the RPKI validator on the same host or on a trusted network. See RPKI.

Metrics Collection

Collect metrics from /metricz over the loopback interface, or through the authenticating reverse proxy.

Neighbor Policy

Configure max_prefixes and role for every EBGP neighbor, and prefix and origin AS lists for every neighbor whose routes are known. See Import Policy.

Logging

The daemon writes its log to standard output. Under systemd, the log is stored in the journal. When standard output is not a terminal, the log contains no color codes.

The --level option sets the minimum level for the daemon's own messages. The RUST_LOG environment variable sets the level for other components. Table 1 lists the messages at each level.

Level Messages
info (default) Session state changes, the first rejected route from each neighbor and at most one per minute thereafter, and kernel route installation state
debug Additionally, one message for each UPDATE received and each route advertised

Note

At the debug level, a full routing table produces millions of log messages.

Ferrix rate-limits log messages that a neighbor can trigger, such as messages about malformed attributes or rejected connections. Each occurrence is counted in a metric. The log contains at most one message for each interval, with the number of suppressed occurrences.

Changing the Configuration

Ferrix reads its configuration at startup only. To change the configuration:

  1. Validate the new configuration.

    sudo bgp --check /etc/ferrix/server.textpb.new
    
  2. Replace the active configuration.

    sudo mv /etc/ferrix/server.textpb.new /etc/ferrix/server.textpb
    
  3. Restart the service.

    sudo systemctl restart ferrix
    

Restart Behavior

When the daemon stops in response to SIGTERM, it sends a Cease NOTIFICATION message with the subcode Administrative Shutdown to every neighbor, and removes its routes from the kernel. The neighbors withdraw the routes that they received from Ferrix. Traffic uses alternative paths until the sessions are reestablished and the routing tables are exchanged again. For a full routing table, this takes several seconds.

If the daemon terminates unexpectedly, its routes remain in the kernel, and the router continues to forward traffic. At the next start, Ferrix retains these routes for stale_seconds (default: 120 seconds) while the neighbors readvertise their routes, and then removes the routes that were not readvertised.

Warning

A restart interrupts forwarding through the router for the time that the sessions take to converge. Restart Ferrix in a maintenance window, or after traffic has been drained to another router.

Running Ferrix in a Container

The container image built from the repository's Dockerfile runs bgp /etc/ferrix/server.textpb --level info. The container requires the host network namespace and the configuration directory. If kernel route installation is enabled, it also requires the NET_ADMIN capability.

docker run -d --name ferrix --restart unless-stopped \
  --network host --cap-add NET_ADMIN \
  -v /etc/ferrix:/etc/ferrix:ro \
  ferrix

Note

The container image runs the daemon as root. Because the container uses the host network namespace, the systemd service is the recommended deployment method on a router.