Skip to main content

Supported platforms

Diagram showing supported platforms with Linux systemd primary integration, FreeBSD rc.d and pf groundwork, and pkg/platform feature-gated implementation rules

routerd is designed to be cross-OS, but each platform uses a different host integration model. This page lists the concrete OS surfaces routerd uses on each platform, so you can review generated files and runtime ownership before applying a router configuration.

Linux (Ubuntu / Debian)

Linux with systemd is the primary platform. Release installs land under /usr/local by default. Install from the Linux release archive and run sudo ./install.sh. The installer can install runtime packages with apt-get, dnf, or pacman.

routerd uses the following OS surfaces on Linux:

  • systemd unit files
  • /run/routerd and /var/lib/routerd for runtime and persistent state
  • dnsmasq for DHCPv4, DHCPv6, DHCP relay, and Router Advertisement
  • nftables for filtering and NAT
  • conntrack for connection observation
  • iproute2 for interfaces and routes
  • long-lived routerd-bgp GoBGP daemon for BGP peering and route installation
  • keepalived for VRRP VIP ownership
  • pppd / rp-pppoe for PPPoE
  • WireGuard, Tailscale, strongSwan, radvd

Even on Ubuntu, routerd does not assume packages are pre-installed. For first bootstrap, install.sh installs a practical default set. For ongoing declarative management, declare dependencies with the Package resource. The reference list:

CategoryPackages
Runtimednsmasq-base, nftables, conntrack, iproute2, keepalived, ppp, wireguard-tools, tailscale, tailscale-archive-keyring, strongswan-swanctl, radvd
Diagnosticsdnsutils, iputils-ping, iputils-tracepath, tcpdump, traceroute, net-tools
OS controlprocps, systemd, kmod

routerd-dhcpv6-client, routerd-dhcpv4-client, routerd-pppoe-client, and routerd-healthcheck run as systemd services on Linux.

Ubuntu 26.04 LTS (resolute) has been validated with the same Linux data-plane renderers used by Ubuntu 24.04 for managed dnsmasq, nftables, DHCPv6-PD, delegated LAN IPv6 address derivation, and the control API. The host bootstrap did need one OS-level networking adjustment: on interfaces that routerd owns for DHCPv6-PD or LAN RA/DHCPv6 service, configure installer netplan/systemd-networkd so the OS does not run its own DHCPv6 client. Otherwise systemd-networkd can bind UDP port 546 before routerd-dhcpv6-client.

For Ubuntu 26.04 router lab hosts, keep only the management interface on OS DHCP and make routerd-owned WAN/LAN interfaces link-local-only at the OS layer:

network:
version: 2
renderer: networkd
ethernets:
ens18:
dhcp4: false
dhcp6: false
accept-ra: false
link-local: [ipv6]
optional: true
ens19:
dhcp4: false
dhcp6: false
accept-ra: false
link-local: [ipv6]
optional: true
ens20:
dhcp4: true
dhcp6: false
accept-ra: false
link-local: [ipv6]
optional: true

For WAN links that still need the RA-learned IPv6 default route, declare the WAN interface and DHCPv6 / RA resources. routerd derives a systemd-networkd drop-in with IPv6AcceptRA=yes and [IPv6AcceptRA] DHCPv6Client=no, so RA is accepted while the OS DHCPv6 client stays disabled.

FreeBSD

FreeBSD uses the same routerd resource model as Ubuntu, mapped onto FreeBSD host mechanisms. The DHCPv6-PD client runs under daemon(8) and reliably keeps a lease bound. routerd maps resources to FreeBSD-native rc.conf, rc.d, pf, mpd5, ifconfig, and dnsmasq surfaces instead of using Linux tools. Install from the FreeBSD release archive and run sudo ./install.sh. The installer uses pkg for ports packages and leaves base-system tools alone.

Implemented:

  • DHCPv6-PD daemon with persistent lease
  • WireGuard interop with Linux / NixOS
  • VXLAN over WireGuard
  • PPPoE via generated mpd5.conf, mpd_enable, and mpd5 service restart
  • Package install through pkg
  • render freebsd --out-dir emits install-packages.sh for reviewable pkg install bootstrap
  • FreeBSD-idiomatic rc.conf.d output for gateway_enable, ipv6_gateway_enable, cloned_interfaces, ifconfig_*, static_routes, ipv6_static_routes, pf_enable, pflog_enable, and mpd_enable
  • dhclient.conf, mpd5.conf, pf.conf, dnsmasq config, and generated rc.d scripts from routerd render freebsd --out-dir
  • pf rendering from FirewallZone, FirewallPolicy, FirewallRule
  • pf NAT rendering from NAT44Rule
  • automatic pfctl -nf validation and pfctl -f application for generated pf.conf
  • conntrack-equivalent traffic flows from pfctl -ss -v
  • pflog0 ingestion through direct BPF reads for firewall logs; packet parsing avoids dependency on vendor-specific tcpdump text formats
  • managed dnsmasq for DHCPv4, DHCPv6, and Router Advertisement
  • dnsmasq lease persistence under /var/db/routerd/dnsmasq
  • dnsmasq config validation with dnsmasq --test before service restart
  • automatic pf holes for routerd-owned DHCP, DNS, RA, DHCPv6-PD, DS-Lite, WireGuard, and healthcheck traffic
  • DNS resolver daemon builds on FreeBSD; DNSUpstream.spec.sourceInterface can target fib:<n> for FIB-bound upstream routing
  • cloud VPN IPsecConnection validates and renders strongSwan swanctl connection definitions; live cloud gateway validation remains deployment-specific
  • rc.d script generation, installation, and service <name> onestart activation from generated service artifacts
  • rc.d script generation for routerd-healthcheck
  • rc.d script generation for routerd-firewall-logger with direct pflog0 input
  • rc.d script generation for TailscaleNode
  • CARP-backed VirtualAddress in mode: vrrp, configured on the parent interface with vhid
  • dnsmasq rc.d ordering after mpd5 for PPPoE coexistence
  • Static DS-Lite gif tunnel rendering
  • Dynamic DS-Lite apply from static AFTR IPv6, AFTR FQDN, or delegated-address local source

ClientPolicy is the one firewall feature that is intentionally Linux-only for now. It depends on nftables Ethernet source address sets for MAC-based guest isolation. The FreeBSD pf renderer rejects the resource with an explicit error instead of applying a weaker no-op policy.

FreeBSD does not use Linux-specific nftables, conntrack, or iproute2. The Package examples declare FreeBSD-native replacements: pf and pflog0 from the base system, mpd5 for PPPoE, ifconfig gif for DS-Lite, dnsmasq for LAN DHCP/RA service, and ports packages for WireGuard, Tailscale, and strongSwan.

CategoryPackages
Runtimednsmasq, wireguard-tools, tailscale, strongswan, mpd5
Diagnosticsbind-tools, tcpdump
Base systemifconfig, sysctl, service, sysrc, netstat, sockstat, ping, traceroute

routerd render freebsd --out-dir <dir> produces:

  • rc.conf.d-routerd
  • dhclient.conf
  • mpd5.conf
  • pf.conf
  • dnsmasq.conf
  • rc.d-*

routerctl apply installs the generated pf.conf, validates it with pfctl -nf, applies it with pfctl -f, validates dnsmasq with dnsmasq --test, starts generated rc.d scripts with service <name> onestart, and applies dynamic DS-Lite tunnels with ifconfig gif when static rc.conf rendering is not enough. Use routerd render freebsd for review and offline validation before pointing real traffic at a FreeBSD host.

Platform parity backlog

These are the current known level differences to track when comparing Ubuntu and FreeBSD:

AreaCurrent gapBacklog
CI/runtime coverageCI runs unit tests and Linux static checks on Ubuntu. FreeBSD is cross-built in release.Add FreeBSD VM smoke jobs that run validate, plan, real package-manager checks, service activation, and renderer syntax checks.
FreeBSD feature exceptionsClientPolicy remains Linux-only because it depends on nftables Ethernet source address sets.Keep rejecting it explicitly, and only add pf support after a design that preserves the same isolation semantics.
Package bootstrapUbuntu and FreeBSD can install packages imperatively.Keep schema, validation, installer package lists, examples, and generated docs in sync for apt and pkg.

Implementation guideline for OS abstraction

When you add a new OS-specific behaviour, do not branch on runtime.GOOS in business logic. Use the pkg/platform layer (platform.Features) or Go build tags to keep the boundaries explicit. Failing fast at validation or planning is preferred over surprising the operator at runtime on an unsupported OS.