Supported platforms

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/routerdand/var/lib/routerdfor 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-bgpGoBGP 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:
| Category | Packages |
|---|---|
| Runtime | dnsmasq-base, nftables, conntrack, iproute2, keepalived, ppp, wireguard-tools, tailscale, tailscale-archive-keyring, strongswan-swanctl, radvd |
| Diagnostics | dnsutils, iputils-ping, iputils-tracepath, tcpdump, traceroute, net-tools |
| OS control | procps, 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, andmpd5service restart Packageinstall throughpkgrender freebsd --out-diremitsinstall-packages.shfor reviewablepkg installbootstrap- FreeBSD-idiomatic
rc.conf.doutput forgateway_enable,ipv6_gateway_enable,cloned_interfaces,ifconfig_*,static_routes,ipv6_static_routes,pf_enable,pflog_enable, andmpd_enable dhclient.conf,mpd5.conf,pf.conf, dnsmasq config, and generatedrc.dscripts fromrouterd render freebsd --out-dir- pf rendering from
FirewallZone,FirewallPolicy,FirewallRule - pf NAT rendering from
NAT44Rule - automatic
pfctl -nfvalidation andpfctl -fapplication for generatedpf.conf - conntrack-equivalent traffic flows from
pfctl -ss -v pflog0ingestion 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 --testbefore 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.sourceInterfacecan targetfib:<n>for FIB-bound upstream routing - cloud VPN
IPsecConnectionvalidates and renders strongSwanswanctlconnection definitions; live cloud gateway validation remains deployment-specific - rc.d script generation, installation, and
service <name> onestartactivation from generated service artifacts - rc.d script generation for
routerd-healthcheck - rc.d script generation for
routerd-firewall-loggerwith directpflog0input - rc.d script generation for
TailscaleNode - CARP-backed
VirtualAddressinmode: vrrp, configured on the parent interface withvhid - dnsmasq rc.d ordering after
mpd5for 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.
| Category | Packages |
|---|---|
| Runtime | dnsmasq, wireguard-tools, tailscale, strongswan, mpd5 |
| Diagnostics | bind-tools, tcpdump |
| Base system | ifconfig, sysctl, service, sysrc, netstat, sockstat, ping, traceroute |
routerd render freebsd --out-dir <dir> produces:
rc.conf.d-routerddhclient.confmpd5.confpf.confdnsmasq.confrc.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:
| Area | Current gap | Backlog |
|---|---|---|
| CI/runtime coverage | CI 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 exceptions | ClientPolicy 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 bootstrap | Ubuntu 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.