OpenBSD Handbook

    Theme
    • Part I. Install & Configure
      • Introduction to OpenBSD
      • Installing OpenBSD
      • The X Window System
      • Networking on OpenBSD
      • System Configuration
      • OpenBSD Basics
      • Managing Software: Packages and Ports
    • Part II. Daily Operations
      • OpenBSD Desktop Environments
      • Multimedia
      • Printing
      • Linux Compatibility
      • Windows Compatibility
      • Games
    • Part III. System Administration
      • Virtualization
      • Storage and File Systems
      • Updating and Upgrading
      • Localization
      • The OpenBSD Boot Process
      • Security
    • Part IV. Networking & Daemons
      • Services
        • Database
          • MariaDB
          • PostgreSQL
          • Redis
          • memcached
        • Directory
          • YP (NIS)
          • LDAP
        • File
          • NFS
          • Samba
        • FTP Services
          • ftpd
          • ProFTPD
          • vsftpd
          • Pure-FTPd
          • TFTP
        • Mail
          • OpenSMTPD Mail Server
          • Dovecot IMAP and POP3 Server
          • Postfix
          • Exim
          • Rspamd
        • Name
          • Unbound DNS Resolver
          • NSD Authoritative DNS Server
          • BIND DNS Server
        • Networking
          • OpenBGPD
          • rad
          • DHCP on OpenBSD
          • slaacd
        • Web
          • Apache HTTP Server
          • nginx Web Server
          • OpenBSD httpd Web Server
          • relayd Reverse Proxy
        • Logging
          • syslogd
        • Monitoring
          • SNMP
        • Remote Access
          • Audit OpenSSH
          • OpenSSH Server
        • File Synchronization
          • rsync
        • Messaging
          • RabbitMQ Message Broker
        • Time
          • NTP Time Synchronization
      • PF
        • pfctl cheat sheet
        • PF Anchors
        • PF Filter Rules
        • PF Forwarding
        • PF Lists and Macros
        • PF Load Balancing
        • PF Logging
        • PF NAT
        • PF Options
        • PF Policies
        • PF Shortcuts
        • PF Tables
      • Advanced Networking
        • High Availability and State Replication
        • Multi-WAN and Policy-Based Routing
        • VPN and Cryptographic Tunneling
        • Classic and Lightweight Tunnels
        • IPv6 at Scale
        • QoS and Traffic Shaping
        • MPLS and Label Distribution
        • Network Services at Scale
        • Virtualization and Host Networking
        • Large-Scale L2 and L3 Design
        • Telemetry, Logging, and Flow Export
        • Hardening and Operational Safety
        • Reference Architectures
        • Troubleshooting Playbooks
      • Serial Communication
    • Part V. Miscellaneous
      • Virtualization Cheat Sheet
      • OpenBSD Cheatsheet
      • How-to Guides
        • Installation and First Boot
          • Complete the First 30 Minutes After Installation
          • Check Hardware Compatibility Before Installing
          • Bootstrap Wi-Fi Firmware Without Ethernet
          • Run OpenBSD as a Virtual Machine Guest
          • Install OpenBSD on a VPS or Cloud Server
          • Install OpenBSD with Full-Disk Encryption
          • Dual-Boot OpenBSD on a UEFI System
          • Automate OpenBSD Installation with Autoinstall and PXE
        • Desktops and Laptops
          • Set Up OpenBSD as a Laptop or Workstation
          • Configure Laptop Power Management
          • Troubleshoot Web Browsers on OpenBSD
          • Use Plan 9 Tools on OpenBSD
          • Build a Minimal Desktop with suckless Tools
          • Install Z shell (zsh)
        • Networking and Remote Access
          • Create an Administrator Account with doas and SSH Keys
          • Configure Secure Remote Access with OpenSSH
          • Use FIDO Security Keys with OpenSSH
          • Configure Wi-Fi Roaming and Wired Failover
          • Troubleshoot PF, NAT, and Routing
          • Route Multiple VLANs with PF
          • Configure a Road-Warrior WireGuard VPN
          • Route IPv6 Networks without NAT
          • Test OpenBGPD with Two Providers
          • Unlock an Internal Service with an SSH Key
          • Build a Simple Router and Firewall
        • Servers and Services
          • Set Up WordPress on OpenBSD
          • Build a Mail Server with OpenSMTPD, Dovecot, and Rspamd
        • Security, Maintenance and Recovery
          • Establish a Conservative Security Baseline
          • Recover Access and Reset the Root Password
          • Collect OpenBSD Diagnostic Evidence
          • Troubleshoot Package Installation and Update Failures
          • Schedule Recurring Maintenance
          • Monitor an OpenBSD System
          • Back Up and Restore an OpenBSD System
          • Configure softraid RAID1
          • Recover an OpenBSD System That Does Not Boot
        • Building, Automation and Virtual Machines
          • Manage OpenBSD with Ansible
          • Build Third-Party Software from Ports
          • Build OpenBSD from Source
          • Plan a Docker Workload Migration to OpenBSD
      • OpenBSD for Linux Users
      • OpenBSD for FreeBSD Users
      • OpenBSD for macOS Users
    • OpenBSD FAQ
    • OpenBSD Architectures
      • OpenBSD Package Search
        • Synopsis
        • Network Topology and Assumptions
        • Enable IPv4 Forwarding
        • Configure Network Interfaces
        • Configure DHCP Service
        • Configure the Firewall and NAT with PF
        • Configure Local DNS Caching with Unbound
        • Verification

        Build a Simple Router and Firewall

        Synopsis #

        An OpenBSD router and firewall can use two network interfaces: one WAN interface that connects to the Internet service provider and one LAN interface that connects to the local network. The configuration enables IPv4 forwarding, network address translation (NAT), stateful firewalling, IPv4 address assignment with DHCP, and local DNS caching.

        A router forwards IP packets between networks. A firewall enforces a policy controlling which packets are permitted. NAT translates addresses on egress to a public address, allowing multiple local hosts to share one public address. OpenBSD uses Packet Filter pf(4) for filtering, NAT, and traffic normalization. See pf(4) .

        All commands in this chapter require root privileges unless explicitly noted. For non-root administration, [set up `doas` access](/admin-account).
        This configuration uses two example interfaces, `re0` for the WAN and `re1` for the LAN. Substitute the interface names that exist on the system, as shown by [ifconfig(8)](https://man.openbsdhandbook.com/man.cgi?page=ifconfig§ion=8).

        Network Topology and Assumptions #

        The examples assume:

        • WAN interface: re0, configured by DHCP from the ISP, or configured with a static address if required by the ISP.
        • LAN interface: re1, configured with the IPv4 subnet 10.0.0.0/24. The router uses 10.0.0.1 on the LAN.

        Adjust addresses and interface names to match the target environment.

        Enable IPv4 Forwarding #

        Enable IPv4 packet forwarding at runtime with sysctl(8) :

        doas sysctl net.inet.ip.forwarding=1
        

        Persist the setting in sysctl.conf(5) :

        net.inet.ip.forwarding=1
        

        This guide does not enable IPv6 forwarding. An IPv6 router also requires an IPv6 addressing and prefix policy, router advertisements, PF rules, and tested upstream routing. The advanced networking chapter covers those requirements separately.

        Configure Network Interfaces #

        Configure the WAN interface. If the ISP assigns addresses by DHCP, write the interface configuration file described in hostname.if(5) :

        doas sh <<'ROOT'
        printf 'inet autoconf\n' > /etc/hostname.re0
        ROOT
        

        If the ISP assigns a static address, set address, netmask, and broadcast accordingly:

        doas sh <<'ROOT'
        cat > /etc/hostname.re0 <<'EOF'
        inet 203.0.113.10 255.255.255.0 203.0.113.255
        EOF
        ROOT
        

        For the static WAN alternative, place the ISP’s actual default gateway in /etc/mygate and configure DNS through /etc/resolv.conf. The example address requires replacement.

        Configure the LAN interface with a static address:

        doas sh <<'ROOT'
        cat > /etc/hostname.re1 <<'EOF'
        inet 10.0.0.1 255.255.255.0 10.0.0.255
        EOF
        ROOT
        

        Apply interface configuration with netstart(8) :

        doas sh /etc/netstart
        

        Verify the addresses with ifconfig(8) :

        ifconfig re0
        ifconfig re1
        

        Configure DHCP Service #

        The DHCP server dhcpd(8) assigns IPv4 addresses and options to LAN clients. Create /etc/dhcpd.conf as described in dhcpd.conf(5) for the 10.0.0.0/24 network. This example sets the default router and DNS server to the router itself and allocates a dynamic pool.

        subnet 10.0.0.0 netmask 255.255.255.0 {
          option routers 10.0.0.1;
          option domain-name-servers 10.0.0.1;
          range 10.0.0.51 10.0.0.250;
        }
        

        Optional fixed address assignment by hardware (MAC) address:

        host server1 {
          fixed-address 10.0.0.30;
          hardware ethernet 00:00:00:00:00:00;
        }
        

        Enable dhcpd at boot, restrict it to the LAN interface, and start it using rcctl(8) :

        doas rcctl enable dhcpd
        doas rcctl set dhcpd flags re1
        doas rcctl start dhcpd
        doas rcctl check dhcpd
        

        Key directives:

        • subnet and netmask define the served IPv4 network.
        • option routers sets the default gateway for clients.
        • option domain-name-servers advertises DNS resolvers to clients.
        • range defines the dynamic address pool available for lease.
        • fixed-address and hardware ethernet bind a static lease to a client MAC address.

        Configure the Firewall and NAT with PF #

        Use pf.conf(5) to define the firewall rules and NAT policy for pf(4). Create /etc/pf.conf with the following baseline policy. Adjust interface names and networks to match the environment.

        # /etc/pf.conf - minimal router/firewall with NAT for a LAN
        
        # Interfaces and networks
        lan_if = "re1"
        lan_net = "10.0.0.0/24"
        
        # Non-routable and reserved address space
        table <martians> { \
          0.0.0.0/8, 10.0.0.0/8, 127.0.0.0/8, 169.254.0.0/16, \
          172.16.0.0/12, 192.0.0.0/24, 192.0.2.0/24, 198.18.0.0/15, \
          198.51.100.0/24, 203.0.113.0/24, 224.0.0.0/3, 192.168.0.0/16 \
        }
        
        # Default behaviors
        set block-policy drop
        set loginterface egress
        set skip on lo
        
        # Normalize traffic
        match in all scrub (no-df random-id)
        
        # NAT for LAN to the current egress address
        match out on egress inet from $lan_net to any nat-to (egress:0)
        
        # Anti-spoofing
        antispoof quick for { egress, $lan_if }
        block in  quick on egress from <martians> to any
        block return out quick on egress from any to <martians>
        
        # Default deny
        block all
        
        # Allow new outbound IPv4 connections and their stateful replies
        pass out on egress inet keep state
        
        # Allow initial DHCP requests before the client has a LAN address
        pass in quick on $lan_if inet proto udp from 0.0.0.0 port bootpc to 255.255.255.255 port bootps
        pass out on $lan_if inet proto udp from ($lan_if) port bootps to any port bootpc
        
        # Allow LAN to anywhere
        pass in on $lan_if inet from $lan_net to any keep state
        

        PF is enabled by default on a standard OpenBSD installation. Use pfctl(8) to validate, load, enable, and inspect the ruleset:

        doas pfctl -nf /etc/pf.conf
        doas pfctl -f /etc/pf.conf
        doas pfctl -e
          # Enable PF at runtime if it was disabled
        doas pfctl -sr
        doas pfctl -sr
        

        The martian table assumes a public WAN. If the upstream router uses private addressing, adapt those quick rules to permit the actual upstream network and DHCP traffic.

        The egress keyword matches the interface that carries the default route, as documented in pf.conf(5) . The policy drops unsolicited inbound traffic from the Internet, permits LAN to initiate connections, and performs NAT on outbound IPv4 traffic.

        Configure Local DNS Caching with Unbound #

        unbound(8) provides a validating, recursive DNS resolver for the LAN clients in this design. Configure it to listen only on the router’s LAN address and to permit queries only from the LAN. Without a forward-zone, Unbound performs recursive resolution from the DNS root. Create /var/unbound/etc/unbound.conf as specified in unbound.conf(5) :

        server:
          interface: 10.0.0.1
        
          access-control: 10.0.0.0/24 allow
          access-control: 0.0.0.0/0 refuse
        
          hide-identity: yes
          hide-version: yes
          auto-trust-anchor-file: "/var/unbound/db/root.key"
        

        Enable and start the service with rcctl(8) :

        doas unbound-anchor -a /var/unbound/db/root.key
        doas chown _unbound:_unbound /var/unbound/db /var/unbound/db/root.key
          # Initialize the DNSSEC trust anchor before the first configuration check
        doas unbound-checkconf /var/unbound/etc/unbound.conf &&
            doas rcctl enable unbound && doas rcctl start unbound
        doas rcctl check unbound
        

        LAN clients receive 10.0.0.1 as their DNS server through DHCP. The router itself continues to use the upstream proposals that resolvd(8) merges into /etc/resolv.conf; this procedure does not point the router at Unbound. Using the local resolver for both the router and LAN clients requires a separate, deliberate resolver-ownership and fallback design.

        Verification #

        After completing the configuration, connect a client to the LAN and confirm it receives an address in the configured pool, the default router 10.0.0.1, and the DNS server 10.0.0.1.

        Verify IP connectivity and name resolution from the client. Use ping(8) for a basic reachability test to a public IP and ftp(1) to fetch a resource by hostname, which exercises DNS:

        ping -n 8.8.8.8
        ftp -o - https://example.com/ >/dev/null
        

        On the router, confirm that NAT and states are present with pfctl(8) :

        doas pfctl -ss
        doas pfctl -s state
        

        Refer to the Handbook for a concise pfctl cheat sheet at /pf/cheat_sheet/ . For detailed reference, use the Handbook-hosted manual pages: pf.conf(5) , pfctl(8) , dhcpd.conf(5) , dhcpd(8) , unbound.conf(5) , unbound(8) , hostname.if(5) , sysctl(8) , and sysctl.conf(5) .

        Report a bug
        • Synopsis
        • Network Topology and Assumptions
        • Enable IPv4 Forwarding
        • Configure Network Interfaces
        • Configure DHCP Service
        • Configure the Firewall and NAT with PF
        • Configure Local DNS Caching with Unbound
        • Verification