How to Configure Static Networking on FreeBSD from Scratch
A rollback-safe FreeBSD static-network workflow for interface identity, IPv4 and IPv6 addressing, routes, resolver ownership, staged activation, and validation.
A static FreeBSD network configuration combines an interface address, prefix, default route, resolver path, and often additional routes or IPv6 policy. Persisting one correct-looking line in rc.conf is not enough. The address must be unique, the gateway reachable on-link, DNS appropriate to the environment, old DHCP state removed, remote access preserved, and the boot path tested.
Make the first conversion through console or out-of-band management. Restarting the only interface over SSH can terminate the session before a typo can be repaired.
Inventory the live configuration and its owner
Identify the interface, MAC address, link state, addresses, routes, resolver, and existing rc settings:
freebsd-version -kru
ifconfig -a
netstat -rn
route -n get default
cat /etc/resolv.conf
sysrc -a | grep -E 'ifconfig_|defaultrouter|ipv6_'
pgrep -laf dhclient
FreeBSD interface names reflect drivers and device order, such as em0, igb0, or vtnet0. Match the interface to its MAC, switch port, VLAN, and current route. Do not assume the first interface listed is the management NIC.
Determine whether bsdinstall, DHCP, cloud-init, hypervisor metadata, configuration management, resolvconf, or local Unbound currently owns each value. Editing generated output while another service remains authoritative creates configuration that works until renewal or reboot and then reverts.
Validate the address plan before touching the host
Obtain an approved address, prefix, gateway, DNS servers, VLAN, hostname, and any static routes from IP address management or the network owner. This article uses 192.0.2.50/24 with gateway 192.0.2.1, an RFC 5737 documentation network that must be replaced.
The gateway normally needs to be inside the connected prefix. Confirm the address is reserved for this host and not present in DHCP pools, DNS under another name, ARP/neighbor tables, switch tables, or monitoring. A failed ping does not prove an address is unused because hosts can ignore ICMP.
Record the current working configuration and prepare exact rollback values. Back up /etc/rc.conf, /etc/rc.conf.local, resolver configuration, PF rules, and application bind settings. Know which console action restores DHCP or the old static address.
Write persistent IPv4 settings with sysrc
Review the existing value before overwriting it:
sysrc ifconfig_em0
sysrc defaultrouter
Then persist the approved configuration:
sysrc ifconfig_em0="inet 192.0.2.50 netmask 255.255.255.0"
sysrc defaultrouter="192.0.2.1"
Replace em0 and every address. sysrc updates /etc/rc.conf safely, but it cannot determine whether the values are correct. Setting ifconfig_em0 replaces a previous DHCP value; verify no separate alias or startup agent will re-add the old address.
Do not edit /etc/defaults/rc.conf. System-specific settings belong in /etc/rc.conf or, where local policy uses it, /etc/rc.conf.local. Both are shell-parsed, so preserve quoting and review duplicates.
Configure DNS according to resolver ownership
On a simple static host with no resolver manager, /etc/resolv.conf can contain the approved recursive resolvers and search policy:
search example.net
nameserver 192.0.2.53
nameserver 192.0.2.54
Those DNS addresses are examples. Corporate split DNS, DNSSEC validation, VPN namespaces, or local Unbound can require a different design. If /etc/resolv.conf points to 127.0.0.1, inspect the local resolver before replacing it. If resolvconf or another agent generates the file, configure that agent’s inputs instead of editing its output.
Do not make resolv.conf immutable as a shortcut. File flags can prevent legitimate DHCP, VPN, or resolver updates and turn a temporary workaround into a difficult outage. Ensure DNS configuration is readable but not writable by unprivileged users.
Activate in a controlled order
From console, restart only the target interface and then routing:
service netif restart em0
service routing restart
Restarting all netif instances can disrupt storage, jails, bridges, VLANs, or the management path. Even the interface-specific command interrupts connections on that NIC. If the host is remote, use a maintenance window and out-of-band access rather than hoping an existing SSH session survives.
Immediately verify the effective state:
ifconfig em0
netstat -rn -f inet
route -n get 192.0.2.1
arp -an
There should be one intended primary address, a connected route for its subnet, and a default route through the approved gateway. Remove stale temporary aliases or DHCP routes only after identifying their owner; deleting routes blindly can remove the rollback path.
Test connectivity by layer and protocol
Test local link and gateway first, then an external address, DNS, and a real application protocol:
ping -c 3 192.0.2.1
traceroute -n 1.1.1.1
drill www.freebsd.org
fetch -o /dev/null https://www.freebsd.org/
Replace the gateway. ICMP failure alone does not prove the route is broken, and ICMP success does not prove TCP, DNS, TLS, or application policy works. fetch confirms resolution, routing, TCP, and TLS together; test the actual service path too.
From a separate host, verify forward and reverse DNS, new inbound connections, monitoring, backups, and every service bound to the old address. Check PF tables and rules for literal addresses. Review logs for duplicate-address messages, route churn, failed binds, or DNS timeouts.
Add static routes without losing existing entries
For a network reached through another on-link router, named rc routes are persistent:
static_routes="internal"
route_internal="-net 10.20.0.0/16 192.0.2.254"
Before setting static_routes, inspect its current value and preserve all existing names. Replacing the list with only internal silently drops other persistent routes at the next restart. Confirm the next hop is reachable on a connected interface and that the destination network has a return route.
Test the equivalent live route during the change window, then verify:
route add -net 10.20.0.0/16 192.0.2.254
route -n get 10.20.0.1
Do not add it live twice if the route already exists. Dynamic routing is preferable when the topology changes often or static-route count becomes difficult to audit.
Treat IPv6 as an independent production path
A static IPv6 configuration uses separate rc variables, for example:
sysrc ifconfig_em0_ipv6="inet6 2001:db8:50::10 prefixlen 64"
sysrc ipv6_defaultrouter="2001:db8:50::1"
The prefix is documentation space. Confirm router advertisements, static addressing, default-route policy, DNS AAAA records, ICMPv6, PF, and service listeners. Do not leave accept_rtadv active accidentally when policy requires only a static default, and do not publish AAAA records until external IPv6 tests pass.
Reboot and prove persistence
Reboot during an approved window. Verify address, default and static routes, resolver content, DHCP absence, PF, jails, mounts, monitoring, and real application traffic. Compare the live state with the change record rather than relying on “the host came back.”
Alert on address changes, duplicate IPs, missing default routes, link loss, DNS failure, excessive errors, and monitoring sourced from the wrong address. A static network configuration is complete only when its ownership is clear, rollback is possible, reboot reproduces it, and both positive and negative client tests match policy.
Related:
- How to Configure FreeBSD as a Router with pf NAT
- FreeBSD Networking Internals: Interfaces, Routing, and netstat
Sources: