OpenBSD Handbook

    • Part I. Install & Configure
      • Introduction
      • Installing OpenBSD
      • The X Window System
      • Networking
      • System Configuration
      • OpenBSD Basics
      • Managing Software: Packages and Ports
    • Part II. Daily Operations
      • Graphical Environments
      • Multimedia
      • Printing
      • Linux Compatibility
      • Windows Compatibility
      • Games
    • Part III. System Administration
      • Security
      • Virtualization
      • Storage and File Systems
      • Updating and Upgrading
      • Localization
      • The OpenBSD Boot Process
    • Part IV. Networking & Daemons
      • Services
        • Database
          • MariaDB
          • PostgreSQL
          • Redis
          • memcached
        • Directory
          • YP (NIS)
          • LDAP
        • File
          • NFS
          • Samba
        • FTP Services
          • ftpd
          • ProFTPD
          • vsftpd
          • TFTP
        • Mail
          • Dovecot
          • smtpd
          • Postfix
          • Exim
          • Rspamd
        • Name
          • Named
          • Unbound
          • NSD
        • Networking
          • OpenBGPD
          • rtadvd
          • DHCP
          • slaacd
        • Web
          • Apache
          • nginx
          • httpd
          • relayd
        • Logging
          • syslogd
        • Monitoring
          • SNMP
        • Remote Access
          • Audit OpenSSH
          • sshd
        • File Synchronization
          • rsync
        • Messaging
          • RabbitMQ
        • Time
          • NTP
      • 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
      • Howto
        • Install Z shell (zsh)
        • Set Up WordPress
        • Build a Simple Router and Firewall
      • OpenBSD for Linux Users
      • OpenBSD for FreeBSD Users
      • OpenBSD for macOS Users
    • Package Search
      VPN and Cryptographic Tunneling
      • Synopsis
      • Design Considerations
      • Configuration
        • Baseline system settings (both sites)
        • PF allowances for IKEv2 and ESP (both sites)
        • Site-to-site IKEv2 with PSK
        • Minimal WireGuard-style tunnel with wg(4)
      • Verification
      • Troubleshooting
      • See Also

      VPN and Cryptographic Tunneling

      Synopsis #

      This chapter covers site-to-site virtual private networks (VPNs) and host-to-host cryptographic tunnels on OpenBSD. It focuses on IKEv2 using the base system iked(8) and the kernel IPsec stack ipsec(4) , with practical patterns for NAT traversal, selector design, and observability. It also shows a minimal pattern for WireGuard-style tunnels with the in-kernel interface wg(4) . Runtime management uses ikectl(8) , packet filtering is handled by pf.conf(5) and pfctl(8) , and link inspection uses tcpdump(8) . The encrypted interface for IPsec is enc(4) .

      Use these patterns to interconnect sites over untrusted networks, to publish internal services across providers securely, or to replace legacy tunnels with modern cryptography.

      Design Considerations #

      • Selectors and scope. Define traffic by networks (for example, 10.0.0.0/24 ↔ 10.20.0.0/24) rather than any. Keep selectors minimal and symmetric on both peers.
      • Authentication. Pre-shared key (PSK) is simplest for site-to-site. Certificates scale better and are preferred where third-party trust or revocation is needed.
      • NAT traversal. Permit UDP ports 500 and 4500 and protocol ESP on WAN. IKEv2 NAT-T is automatic when address translation is detected.
      • Routing. For routed sites, enable IPv4/IPv6 forwarding and add static routes (or dynamic routing inside the tunnel).
      • Performance. Prefer AES-GCM proposals to offload integrity to the cipher. Keep MTU and MSS in mind where encapsulation crosses constrained links.
      • Operations. Ensure time sync on all peers (for example, with ntpd(8) ). Log IKE and PF events during rollout.

      Configuration #

      The examples assume:

      • Site A WAN: 198.51.100.10, LAN: 10.0.0.0/24
      • Site B WAN: 203.0.113.10, LAN: 10.20.0.0/24

      Adjust interface names and addresses to match your environment.

      Baseline system settings (both sites) #

      # printf '%s\n' \
          'net.inet.ip.forwarding=1' \
          'net.inet6.ip6.forwarding=1' \
          >> /etc/sysctl.conf
        # Enable L3 forwarding for routed traffic through the firewall/router
      
      # sysctl net.inet.ip.forwarding=1 net.inet6.ip6.forwarding=1
        # Apply immediately
      

      PF allowances for IKEv2 and ESP (both sites) #

      Permit IKE (UDP 500/4500) and ESP on the WAN, and allow traffic between the protected subnets on the inside. Syntax is defined in pf.conf(5) .

      ## /etc/pf.conf — minimal allowances for IKEv2/IPsec
      
      set skip on lo
      
      wan     = "em0"           # adjust
      lan_net = "{ 10.0.0.0/24, 10.20.0.0/24 }"
      
      block all
      
      # IKE and IPsec on the WAN
      pass in on $wan proto udp to ($wan) port { 500, 4500 } keep state
      pass in on $wan proto esp keep state
      pass out on $wan proto { udp, esp } keep state
      
      # Permit protected subnets after decryption
      pass on enc0 from 10.0.0.0/24 to 10.20.0.0/24 keep state
      pass on enc0 from 10.20.0.0/24 to 10.0.0.0/24 keep state
      

      Reload and confirm with pfctl(8) .

      # pfctl -f /etc/pf.conf
      # pfctl -sr | egrep 'udp .* (500|4500)|proto esp|enc0'
      

      Site-to-site IKEv2 with PSK #

      Configuration is in iked.conf(5) . One side initiates (active), the other listens (passive). Proposals below use AES-GCM.

      Site A (initiator) #

      ## /etc/iked.conf — Site A
      
      ikev2 "s2s-a2b" active esp from 10.0.0.0/24 to 10.20.0.0/24 \
          peer 203.0.113.10 \
          ikesa enc aes-256-gcm prf sha256 group 14 \
          childsa enc aes-256-gcm \
          psk "change-this-shared-secret"
      

      Site B (responder) #

      ## /etc/iked.conf — Site B
      
      ikev2 "s2s-b2a" passive esp from 10.20.0.0/24 to 10.0.0.0/24 \
          ikesa enc aes-256-gcm prf sha256 group 14 \
          childsa enc aes-256-gcm \
          psk "change-this-shared-secret"
      

      Enable and start iked(8) on both peers with rcctl(8) ):

      # rcctl enable iked
        # Start at boot
      # rcctl start iked
        # Launch now (initiator will dial the responder)
      

      If either peer is behind NAT, IKEv2 will encapsulate ESP in UDP 4500 automatically (NAT-T). Ensure the upstream allows those ports.

      Minimal WireGuard-style tunnel with wg(4) #

      The wg(4) interface provides a compact, static-key tunnel. Keys are Curve25519; generate them per the wg(4) documentation and place the private key on each host (for example, /etc/wg/private.key). Interface attributes are set with ifconfig(8) .

      Example: point-to-point /30 between hosts with inside addresses 10.99.0.1/30 (Site A) and 10.99.0.2/30 (Site B), UDP port 51820.

      Site A #

      # ifconfig wg0 create
        # Create the interface
      # ifconfig wg0 inet 10.99.0.1/30
        # Assign inside address
      # ifconfig wg0 wgport 51820
        # Listen on UDP/51820
      # ifconfig wg0 wgkey `cat /etc/wg/private.key`
        # Load this host's private key
      # ifconfig wg0 wgpeer <SITE_B_PUBLIC_KEY> wgendpoint 203.0.113.10 51820
        # Configure peer's public key and endpoint
      # ifconfig wg0 wgpeer <SITE_B_PUBLIC_KEY> wgaip 10.99.0.2/32
        # Allowed-IPs for the peer (peer's inside address)
      # route add -net 10.20.0.0/24 10.99.0.2
        # Route a remote LAN via the tunnel if needed
      

      Site B #

      # ifconfig wg0 create
      # ifconfig wg0 inet 10.99.0.2/30
      # ifconfig wg0 wgport 51820
      # ifconfig wg0 wgkey `cat /etc/wg/private.key`
      # ifconfig wg0 wgpeer <SITE_A_PUBLIC_KEY> wgendpoint 198.51.100.10 51820
      # ifconfig wg0 wgpeer <SITE_A_PUBLIC_KEY> wgaip 10.99.0.1/32
      # route add -net 10.0.0.0/24 10.99.0.1
      

      Permit the WireGuard UDP port on each WAN and allow the inside prefixes on wg0 in PF as appropriate.

      Verification #

      • IKEv2 state and flows with ikectl(8) :
      $ ikectl show sa
        # IKE_SA and CHILD_SA state, SPIs, lifetimes
      $ ikectl show flows
        # Traffic selectors currently installed
      
      • Encapsulated traffic on the wire with tcpdump(8) :
      # tcpdump -ni em0 port 500 or port 4500 or proto esp
        # IKE_SA negotiation and ESP/NAT-T on the WAN
      # tcpdump -ni enc0 host 10.20.0.50
        # Plaintext (post-decrypt) traffic on enc0 for IPsec
      # tcpdump -ni em0 udp port 51820
        # WireGuard UDP transport
      
      • Path testing:
      $ ping -n -c 3 10.20.0.1
        # From a host behind Site A to a host behind Site B (IKEv2)
      $ ping -n -c 3 10.99.0.2
        # Between tunnel endpoints (WireGuard)
      
      • PF and routes:
      $ pfctl -vvsr | egrep 'udp .* (500|4500)|proto esp|udp .* 51820'
        # Confirm allowances
      $ netstat -rn | egrep '10\.99\.0\.|10\.20\.0\.'
        # Confirm inside/tunnel routes
      

      Troubleshooting #

      • No IKE negotiation. Verify UDP 500/4500 reachability and that the responder is in passive mode. Inspect logs in /var/log/daemon for iked.
      • Selector mismatch. If one side uses 10.0.0.0/24 ↔ 10.20.0.0/24 and the other uses 10.0.0.0/24 ↔ 10.0.0.0/24, CHILD_SA will not install. Align from/to networks. Check ikectl show flows.
      • NAT or path asymmetry. Ensure upstreams carry UDP 4500 unchanged and that return traffic follows the same egress. For IPsec, enc0 rules should allow the protected subnets.
      • MTU black holes. If large transfers stall, clamp MSS on the WAN during testing in PF (scrub in max-mss ...) and refine after measuring path MTU.
      • Clock skew. Certificates and IKE lifetimes are time-sensitive. Ensure NTP is working with ntpd(8) .
      • WireGuard handshake fails. Confirm the correct public keys, matching wgport, reachable wgendpoint, and that each side has the other’s inside /32 as an allowed IP. Use ifconfig wg0 to view current peers and statistics.

      See Also #

      • Networking
      • OpenBGPD
      • Related: Classic and Lightweight Tunnels
      • Related: Hardening and Operational Safety
      Report a bug
      • Synopsis
      • Design Considerations
      • Configuration
        • Baseline system settings (both sites)
        • PF allowances for IKEv2 and ESP (both sites)
        • Site-to-site IKEv2 with PSK
        • Minimal WireGuard-style tunnel with wg(4)
      • Verification
      • Troubleshooting
      • See Also