November 7, 2026
This article presents a router setup for OpenBSD where LAN clients can share one Mullvad VPN tunnel (any tunnel really). This is desirable because Mullvad limits accounts to have 5 active connections. Also, on Android, it is mostly impossible to have two active VPN connections. Thus I cannot both tunnel home and into an IP-masking VPN at the same time.
Everybody shut up and leave me alone
Everybody shut up and leave me alone
Everybody shut up and leave me alone
I'm going straight to heaven.
Here's my best effort at drawing a diagram of the network.
wg0: tunnel home
wg1: mullvad
igc0: isp
igc1: switch
[ pc1 ] ---+
|
[ pc2 ] ---+--- [ switch ] --- igc1 [ router ] igc0 --- [ wan ] --- wg1
| wg0
[ pc3 ] ---+
The tunnel home wg0 is optional.
Forego that interface if you don't care for remote access.
My configurations are tweaks of the
guide from the FAQ
/etc/hostname.igc0
inet PUBLICIP 255.255.255.0
/etc/hostname.igc1
inet 192.168.0.1 255.255.255.0
/etc/hostname.wg0
wgkey ROUTERPRIVKEY
wgport 51820
wgpeer PEERPUBKEY wgaip 172.16.0.2/32
inet 172.16.0.1/24
Standard Wireguard config. See here to learn to setup Wireguard for OpenBSD.
/etc/hostname.wg1
inet MULLVADPRIVIP 255.255.255.255
wgkey MVPRIVKEY
wgpeer MVPUBKEY wgendpoint MVENDPOINT 51820 wgaip 0.0.0.0/0
!route add MVENDPOINT ISPGW
!route add default MVPRIVIP
With the routes, we set the internal Mullvad IP as the default gateway. EXCEPT the Mullvad endpoint, we must reach that outside the tunnel. As such, for that we create a route direct through our ISP.
/etc/sysctl.conf
net.inet.ip.forwarding=1
For NAT.
/etc/dhcpd.conf
subnet 192.168.0.0 netmask 255.255.255.0 {
option routers 192.168.0.1;
option domain-name-servers 192.168.0.1;
range 192.168.0.50 192.168.0.254;
}
/var/unbound/etc/unbound.conf
server:
interface: 192.168.0.1
interface: 127.0.0.1
access-control: 192.168.0.0/24 allow
hide-identity: yes
hide-version: yes
prefetch: yes
forward-zone:
name: "."
forward-addr: 10.64.0.1
We forward Mullvad's internal DNS server. You may be able to advertise it to clients in dhcpd and not run unbound. Depends on how happy your clients are to use it.
/etc/pf.conf
set skip on lo0
block drop
match out on egress from !(egress:network) nat-to (egress)
pass out quick
pass in on { igc1 wg0 }
pass in on igc0 proto udp to port 51820 reply-to ISPGW
wg1 is not mentioned here because wg1 becomes egress as the default gateway.
reply-to is needed for any public facing ports.
Otherwise the router will try to reply through the Mullvad tunnel, which will not work.
Thazzit.
Both igc1 and wg0 clients are NAT'd through wg1.