Unlike on Linux, NetBSD currently uses a completely independent implemenation of the Wireguard protocol and thus it doesn't work quite the same way as the "official" implementations.
Key differences:The following steps are for a typical single-user NetBSD system and assumes the following:
$ mkdir /etc/wg
$ awk '^PrivateKey/{print $3 > "/etc/wg/wg0"}' proton-CN-ST_PN.conf
$ cat /etc/wg/wg0
z54***********************zg=
$ chmod 600 /etc/wg/wg0
# /etc/ifconfig.wg0
description 'Wireguard VPN pseudo-device'
## proton-CN-ST_PN
inet 10.2.0.2/32 # Address IPv4
inet6 fd00:2::2/96 # Address IPv6 (if available)
!wgconfig $int set private-key /etc/wg/$int
!wgconfig $int add peer Proton z54**********zg= \ # PublicKey
--allowed-ips='0.0.0.0/0,::/0' \ # AllowedIPs (comma-separated)
--endpoint=212.102.44.166:51820 # Endpoint
down
note: we explicitly set the interface down else it'll come up
by default; this allows use of wgctl managment script
for toggling the VPN on or off as needed.
$ echo 'if_wg >> /etc/modules.conf # creates file if needed
note: to skip reboot after setup run the following:
$ sudo modload if_wg # successful if no error reported
$ modstat -n if_wg # display status of loaded module
NAME CLASS SOURCE FLAG REFS SIZE REQUIRES
if_wg driver filesys - 0 - sodium,blake2s
$ sudo service network restart # should setup wg0 interface
$ ifconfig -ld # list configured & down NICs
wg0
ex: $ sed -n '/^# Vars/,/^$/p' ~/bin/wgctl
# Vars:
WGint='wg0' # wg(4) pseudo-NIC
Ngate='192.168.1.1' # non-WG gateway
# proton-CN-ST_PN
Wserv='212.102.44.166' # VPN Endpoint (minus port)
Waddr='0.0.0.0' # VPN AllowedIPs
Wgate='10.2.0.2' # VPN Address (minus subnet)
WGns4='10.2.0.1' # VPN DNS
WGns6='2a07:b944::2:1' # VPN DNS (IPv6; if avail.)
note: to get your system's non-WG gateway run the following
*BEFORE* you bring the VPN up:
$ netstat -r |grep default
default 192.168.1.1 UGS - - - fxp0
=> 192.168.1.1 is your default gateway
Lastly, copy script to ~/bin/wgctl and make it executable:
$ [ -d ~/bin ] && mkdir ~/bin # creates ~/bin if doesn't exist
$ cp ~/Downloads/wgctl ~/bin/ # example; adjust as needed
$ chmod 740 ~/bin/wgctl # only owner can execute or edit
Assuming the if_wg module is loaded, /etc/wg/wg0 is in place, and wg0 is configured via /etc/ifconfig.wg0 Proton's Wireguard VPN is ready to be launched. You may want to reboot the system and check dmesg(8) output for any errors relating to the above setup. If all looks fine the VPN is ready to use, either manually or via the wgctl.sh script.
note: uses example values from Setup section.
$ sudo ifconfig wg0 up
$ sudo route add 212.102.44.166 192.168.1.1
$ sudo route change default 10.2.0.2
$ echo 'nameserver 10.2.0.1 2a07:b944::2:1' |sudo resolvconf -x -a wg0 -
$ ( while [ -z "$(ifconfig -d wg0)" ]
do
ping -o 212.102.44.166 >/dev/null 2>&1
sleep 10
done ;) &
$ sudo ifconfig wg0 down
$ sudo route delete 212.102.44.166
$ sudo route change default 192.168.1.1
$ sudo resolvconf -f -d wg0
The wgctl.sh script basically automates the various steps shown in the Manual VPN management section. Currently only a single Wireguard peer is supported.
The wgctl script has several options; use -h to list:
$ wgctl -h
toggle Wireguard interface UP/DOWN or get status
usage: wgctl [-h|-u|-d|-t|-s|-p|-i|-n]
-h usage
-u bring VPN up
-d bring VPN down
-t test connection
-s show status (default)
-p show peer info
-i show interface info
-n show DNS info
Bringing the VPN up:
$ wgctl -u
Password: ********
add host 212.102.44.166: gateway 192.168.1.1
change net default: gateway 10.2.0.2
adding nameserver
=> Wireguard interface wg0 is UP.
Use -t to test the VPN connection:
$ wgctl -t
nslookup: ProtonVPN
Server: 10.2.0.1
Address: 10.2.0.1#53
Non-authoritative answer:
Name: protonvpn.com
Address: 185.159.159.140
PING protonvpn.com (185.159.159.140): 56 data bytes
64 bytes from 185.159.159.140: icmp_seq=0 ttl=41 time=139.170075 ms
64 bytes from 185.159.159.140: icmp_seq=1 ttl=41 time=140.068808 ms
64 bytes from 185.159.159.140: icmp_seq=2 ttl=41 time=147.346394 ms
----protonvpn.com PING Statistics----
3 packets transmitted, 3 packets received, 0.0% packet loss
round-trip min/avg/max/stddev = 139.170075/142.195092/147.346394/4.483733 ms
Displaying the peer, interface and DNS info:
$ wgctl -p
interface: wg0
private-key: (hidden)
listen-port: (none)
peer: Proton
public-key: z54+LsnV9L6PyS/MO4dPfJ650jiOVLVevYrWf2WsDzg=
endpoint: 212.102.44.166:51820
preshared-key: (hidden)
allowed-ips: 0.0.0.0/0,::/0
latest-handshake: Wed May 27 16:45:21 2026
$ wgctl -i
wg0: flags=0x8041 mtu 1420
description: "Wireguard VPN pseudo-device"
linkstate: up
status: active
input: 2914 packets, 902728 bytes
output: 2792 packets, 828635 bytes
inet6 fe80::217:31ff:fe24:7ef4%wg0/64 flags 0 scopeid 0x3
inet6 fd00:2::2/96 flags 0
inet 10.2.0.2/32 flags 0
$ wgctl -n
# resolv.conf from wg0
nameserver 10.2.0.1 2a07:b944::2:1
Use -d to bring the VPN back down:
$ wgctl -d
Password: ********
delete host 212.102.44.166
change net default: gateway 192.168.1.1
removing nameserver(s) 10.2.0.1 2a07:b944::2:1
=> Wireguard interface wg0 is DOWN.
NetBSD's Wireguard implementation is still considered experimental and currently only supports a maximum of 6 peers. While it may be possible to to extend the perceived peer count via dynamic additions and destructions within /etc/wg/, it would likely pose some coding challenges.
On some systems ssh sessions can become unresponsive when run through the VPN; if this happens try setting the following in ~/.ssh/config:
ServerAliveInterval 10 # 0 is default, ie. *no* signal is sent
ServerAliveCountMax 3 # 3 is default
According to the ssh_config(5) manpage the above values are multiplied to obtain the period of unresponsiveness in before ssh disconnects, ie. 3*10 = 30 seconds. May require experimentation..