The Handbook

    Theme
    • Guides
        • Check a system before installing FreeBSD
        • Orient a Linux administrator on FreeBSD
        • Supported FreeBSD releases
        • Choose a FreeBSD documentation and support channel
        • Move files safely without GNU mv -t
        • Update, upgrade, or update packages?
        • Upgrade 14.4 or 15.0 to FreeBSD 15.1
        • Choose packages, ports, or poudriere
        • Choose the quarterly or latest package branch
        • Choose a FreeBSD download or package mirror
        • Make a system setting persistent
        • Configure locale, keyboard, and time zone
        • Configure a serial console for recovery
        • Choose a custom kernel, module, or loader setting
        • Run a Linux binary with the compatibility layer
        • Check desktop and laptop hardware before installation
        • Choose and check a graphics driver
        • Choose Xorg or Wayland
        • Build a maintainable desktop baseline
        • Install and check a desktop browser
        • Check laptop Wi-Fi, power, and suspend
        • Check multimedia readiness
        • Choose and configure a printing stack
        • Run Windows applications with Wine
        • Snapshot and replicate a ZFS dataset
        • Choose a filesystem and storage layout
        • Operate ZFS without losing the recovery path
        • Restore files from a ZFS snapshot
        • Read ZFS pool health and run a scrub
        • Replace a failed device in a ZFS mirror
        • Replicate a ZFS dataset over SSH
        • Change PF safely on a remote host
        • Configure a narrow WireGuard tunnel
        • Plan a FreeBSD home server
        • Choose a mail server or an outgoing relay
        • Publish a network service safely
        • Choose a jail network model
        • Choose native jails or a jail manager
        • Choose a jail or a bhyve virtual machine
        • Establish a FreeBSD security baseline
        • Choose a MAC policy
        • Audit security-relevant activity
        • Start a DTrace performance investigation
    • Integrations
        • Create a first jail with Bastille
        • Compare jail managers and OCI tooling
        • Publish a Bastille service through PF
        • Mount a ZFS dataset in a Bastille jail
        • Update and upgrade Bastille jails
        • Back up and restore a Bastille jail
        • Prepare bhyve and vm-bhyve
        • Choose NFS or Samba for file sharing
        • Choose ZFS backup automation
        • Operate a signed poudriere repository
        • Manage FreeBSD configuration with Ansible or Salt
        • Run Motion with webcamd on FreeBSD
        • Design a reverse proxy, certificates, and monitoring
    • FAQ
    • Troubleshooting
        • Recover an interrupted freebsd-update run
        • Resolve a package repository or ABI mismatch
        • Diagnose the FreeBSD boot path
        • Recover with a ZFS boot environment
        • Diagnose DNS, routing, and firewall paths
        • Diagnose network mbuf exhaustion
        • Bind a service to a low port without running it as root
        • Diagnose audio output or input
        • Diagnose webcamd, cuse, and a webcam
        • Fix USB device permissions without opening every device
    • About this handbook
    • Synopsis
    • Define the two peers
    • Install tools and create keys
    • Create the server configuration
    • Create the client configuration
    • Start and verify manually
    • Extend routing separately
    • Primary references

    Configure a narrow WireGuard tunnel

    Last reviewed
    13 August 2026
    Applies to
    15.1-RELEASE, 15.0-RELEASE, 14.4-RELEASE

    Synopsis #

    WireGuard associates peers with public keys and AllowedIPs. On transmit, AllowedIPs selects the peer for a destination; on receive, it also limits which source addresses that peer may use. A broad value such as 0.0.0.0/0 can replace the default route when wg-quick brings up the interface.

    This procedure builds only a private routed subnet between two peers. It does not turn either peer into a default-route VPN gateway. Forwarding, NAT, DNS replacement, and public service exposure are separate policy decisions.

    Define the two peers #

    The examples use:

    Peer Tunnel address Endpoint
    Server 10.77.0.1/24 Public UDP port 51820
    Client 10.77.0.2/24 Dynamic or private address

    Confirm that 10.77.0.0/24 does not overlap LAN, jail, cloud, or other VPN routes. Record the server’s receiving interface and public address before changing PF.

    Install tools and create keys #

    Install the WireGuard management tools on both peers:

    # pkg install wireguard-tools
    # install -d -m 700 /usr/local/etc/wireguard
    # sh -c 'umask 077; wg genkey > /usr/local/etc/wireguard/private.key'
    # sh -c 'wg pubkey < /usr/local/etc/wireguard/private.key > /usr/local/etc/wireguard/public.key'
    $ cat /usr/local/etc/wireguard/public.key
    

    Exchange only public keys. Never paste private keys into a ticket, command history, or diagnostic output. Restrict each final configuration file to root.

    Create the server configuration #

    Create /usr/local/etc/wireguard/wg0.conf with the server private key and client public key substituted locally:

    [Interface]
    Address = 10.77.0.1/24
    PrivateKey = SERVER_PRIVATE_KEY
    ListenPort = 51820
    
    [Peer]
    PublicKey = CLIENT_PUBLIC_KEY
    AllowedIPs = 10.77.0.2/32
    

    Protect the file:

    # chmod 600 /usr/local/etc/wireguard/wg0.conf
    

    PF must admit UDP 51820 only on the intended server address and interface. Add that narrow rule through the method in Change PF safely on a remote host . No forwarding or NAT is required for traffic whose endpoint is the server itself.

    Create the client configuration #

    Create the same path on the client:

    [Interface]
    Address = 10.77.0.2/24
    PrivateKey = CLIENT_PRIVATE_KEY
    
    [Peer]
    PublicKey = SERVER_PUBLIC_KEY
    AllowedIPs = 10.77.0.0/24
    Endpoint = vpn.example.net:51820
    PersistentKeepalive = 25
    

    The keepalive is useful when the client is behind stateful NAT. It is not normally necessary for a peer with a stable directly reachable address.

    Start and verify manually #

    Bring up the server and then the client:

    # wg-quick up wg0
    $ ifconfig wg0
    # wg show wg0
    $ netstat -rn
    

    Verify that no default route was replaced and that the only new route covers the intended tunnel prefix. From the client:

    $ ping -c 3 10.77.0.1
    # wg show wg0
    

    The latest handshake and transfer counters establish WireGuard state. A configured interface without a recent handshake does not prove endpoint reachability.

    When the tested configuration should start at boot:

    # sysrc wireguard_enable=YES
    # sysrc wireguard_interfaces=wg0
    # service wireguard restart
    

    Use the rc script installed by the selected wireguard-tools package. Do not combine that script, hand-created cloned interfaces, and another network manager unless their ownership has been designed explicitly.

    Extend routing separately #

    Access to another LAN or jail network requires all of the following: a matching AllowedIPs entry, a route on the opposite peer, IP forwarding on the routing host, a PF policy that permits the flow, and a valid return route or deliberate NAT. Add these controls as a separate change and diagnose them with Diagnose DNS, routing, and firewall paths .

    Primary references #

    • WireGuard tools
    • wg(8)
    • wg-quick(8)
    • wg(4)
    • route(8)

    Independent documentation. Not affiliated with or endorsed by the FreeBSD Project or the FreeBSD Foundation.

    Report a bug
    • Synopsis
    • Define the two peers
    • Install tools and create keys
    • Create the server configuration
    • Create the client configuration
    • Start and verify manually
    • Extend routing separately
    • Primary references