This resource was originally created by user: FreeVel on the TrueNAS Community Forums Archive. Please DM this account or comment in this thread to claim it.
Goal
- To setup a VPN server based on the Wireguard technology and running from within a Jail.
- The VPN server would allow remote devices to connect and access resources in the local network
- All remote traffic should be routed via the VPN channel
Approach Overview
- [1] The FreeNas host is running on the local network 192.x.x.x/24 using the bge0 iface
- [2] The Jail is setup with VNET and network 172.x.x.x/24
- [3] Since Wireguard will be running from within the Jail’s network (e.g. 10.x.x.x/32:51820) we’ll need to expose the Wireguard listening port outside the Jail (192.x.x.x:51820) , hence we need
- NAT active on VNET
- port-forwarding for 192.x.x.x:51820 (local) <–>172.x.x.x/24 (jail)
- Firewall rules on Jail for 172.x.x.x:51820 (jail) ↔ 10.x.x.x:51820 (wireguard)
- [4] Finally port-forwarding from WAN <—> 192.x.x.x:51820
Step 1: Setting up Jail with NAT and port-forwarding (local ↔ jail)
a. Go to Jail wizard and switch to “Advanced Mode”
b. Enable NAT, VNET and (optional) set default iface to your NIC, in my case: bg0
c. Under network properties set “NAT Port-forwarding” as shown. You can leave “NAT Interface” empty as in my case the jail picks bge0 as default at start-up
Note:
- If bge0 has IP 192.168.20.2 then your Jail wireguard server will listen on 192.168.20.2:51820
d. Jail properties enable “allow_tun”
e. Save your jail config
Step 2: Install Wireguard
a. Enter your jail
# iocage console << your jail name >>
b. Setup “pkg” to upgrade against latest base
# pkg install nano
# mkdir -p /usr/local/etc/pkg/repos
# nano /usr/local/etc/pkg/repos/FreeBSD.conf
c. Paste the below setup, press Ctrl+X, and “Yes”
FreeBSD: {
url: "pkg+http://pkg.FreeBSD.org/${ABI}/latest",
mirror_type: "srv",
signature_type: "fingerprints",
fingerprints: "/usr/share/keys/pkg",
enabled: yes
}
d. upgrade your base to the latest
# pkg upgrade
e. install wireguard
# pkg install wireguard wireguard-go libqrencode
Step 3: Set up wireguard & Jail networking (jail ↔ wireguard)
a. Enable Wireguard iface, NAT & IP forwarding in “rc.conf”
# nano /etc/rc.conf
b. ensure the following lines exist in your rc.conf
# Enable Wireguard
wireguard_enable="YES"
wireguard_interfaces="wg0"
#Enable ip forwarding
gateway_enable="YES"
#Enable Firewall NAT in kernel mode
firewall_enable="YES"
firewall_nat_enable="YES"
#firewall_logging="YES" # Optional
firewall_script="/usr/local/etc/ipfw.rules"
c. Create the ipfw.rules file
# nano /usr/local/etc/ipfw.rules
d. Paste the below lines into the file, Ctrl+X and “Yes”
Note: I have commented most rules out for the basic/simple config however feel free to uncomment and experiment if you need a more complex filtering.
#!/bin/sh
# ipfw config/rules
# from FBSD Handbook, rc.firewall, et. al.
# Flush all rules before we begin.
ipfw -q -f flush
# Set rules command prefix
cmd="ipfw -q add "
# Internet-facing iface
vif="epair0b"
# Used for outboud NAT rules
skip="skipto 1000"
#### WG-specific Options ####
# Listen Port
wg_port="51820"
# Subnet
wg_subnet="10.0.0.1/32"
# Wireguard interface, matching the name in /etc/wireguard/*.conf
wg_iface="wg0"
# Allow NAT
ipfw disable one_pass
ipfw -q nat 1 config if $vif same_ports unreg_only reset
# allow all for localhost
$cmd 00010 allow ip from any to any via lo0
$cmd 00011 allow ip from any to any via $wg_iface
# NAT-specific rules
$cmd 00099 reass all from any to any in # reassemble inbound packets
$cmd 00100 nat 1 ip from any to any in via $vif # NAT any inbound packets
# checks stateful rules. If marked as "keep-state" the packet has
# already passed through filters and is "OK" without futher
# rule matching
$cmd 00101 check-state
# allow WG
#$cmd 00233 $skip udp from any to any src-port $wg_port out via $vif keep-state
#$cmd 00234 $skip udp from $wg_subnet to any out via $vif keep-state
#$cmd 00235 $skip tcp from $wg_subnet to any out via $vif setup keep-state
#$cmd 00320 $skip udp from any to any out via $vif keep-state
#$cmd 00325 $skip tcp from any to any out via $vif setup keep-state #$cmd 00330 $skip icmp from any to any out via $vif keep-state
#$cmd 999 deny ip from any to any
# NAT
$cmd 1000 nat 1 ip from any to any out via $vif # skipto location for outbound stateful rules
#$cmd 1001 allow ip from any to any
e. Using in-kernel NAT requires to disable TCP segmentation offloading (TSO). Set the following in Jail’s /etc/sysctl.conf
net.inet.tcp.tso="0"
f. Restart the Jail & go get back to the console
# exit
# iocage restart <<wireguard jail>>
* Stopping wireguard
+ Executing prestop OK
+ Stopping services OK
+ Tearing down VNET OK
+ Removing devfs_ruleset: 10 OK
+ Removing jail process OK
+ Executing poststop OK
wireguard: nat requires nat_interface, using bge0
* Starting wireguard
+ Started OK
+ Using devfs_ruleset: 6
+ Configuring VNET OK
+ Using IP options: vnet
+ Starting services OK
+ Executing poststart OK
# iocage console <<wireguard jail>>
g. Confirm firewall settings loaded. Note: The above config of ipfw rules should look like this
# ipfw list
00010 allow ip from any to any via lo0
00011 allow ip from any to any via wg0
00099 reass ip from any to any in
00100 nat 1 ip from any to any in via epair0b
00101 check-state :default
01000 nat 1 ip from any to any out via epair0b
65535 allow ip from any to any
# ipfw nat show config
ipfw nat 1 config if epair0b same_ports unreg_only reset
Step 4: Setup Wireguard Server & remote host configs
a. Create public/private key pairs for wireguard server and remote host
# cd /usr/local/etc/wireguard/
# wg genkey | tee wg.private | wg pubkey > wg.public
# wg genkey | tee remote.private | wg pubkey > remote.public
b. Create Wireguard server config
# nano wg0.conf
c. Add the Server (interface) and remote (peer) by pasting the below config, then press Ctrl+X & “Yes”
[Interface]
Address = 10.0.0.1/32
PrivateKey = << Paste wg.private here >>
ListenPort = 51820
[Peer]
PublicKey = << Paste remote.public here >>
AllowedIPs = 10.0.0.2/32
d. Start Wireguard service
# service wireguard start
[#] wireguard-go wg0
INFO: (wg0) 2020/07/09 22:35:10 Starting wireguard-go version 0.0.20200320
[#] wg setconf wg0 /tmp/tmp.xw963cv4/sh-np.h2wle2
[#] ifconfig wg0 inet 10.0.0.1/32 10.0.0.1 alias
[#] ifconfig wg0 mtu 1420 [#] ifconfig wg0 up
[#] route -q -n add -inet 10.0.0.2/32 -interface wg0
[+] Backgrounding route monitor
Step 5: Setup wireguard on remote host
a. Create remote host config
# nano remote.conf
b. Add the following lines with the relevant values, press Ctrl+X and “yes”.
Note:
- [Interface] address should match the [Peer] value in server’s wg.conf;
- DNS entry can is optional
- Allowed IPs can be limited to the remote subnet e.g 192.168.0.0/24
[Interface]
Address = 10.0.0.2/32
PrivateKey = << your remote.private key here >>
DNS = 8.8.8.8
[Peer] PublicKey = << your wg.public key here >>
AllowedIPs = 0.0.0.0/0,::/0
Endpoint = << your WAN IP >>:<<WAN exposed port>>
as an example your remote conf could look like this
[Interface]
Address = 10.0.1.2/32
PrivateKey = 8Ng/rzsuTlbZobnRqp2XC2bOgZP29P0K8d2Oa9m9pUA=
DNS = 192.168.1.1
[Peer]
PublicKey = bAUcryyyQ1x95zR27pMO7kwuskLpYM6fCOC211111gE=
AllowedIPs = 0.0.0.0/0,::/0
Endpoint = 242.72.48.124:51820
c. Install wireguard on remote host and load the remote host config file using QR scan code (easier)
# qrencode -t ansiutf8 < remote.conf
Step 6: Setup port-forwarding on your router
a. Setup port-forwarding on your router so
<<WAN_IP>>:51820 <---> <<bge0_ip>>:51820
Step 7: Confirm VPN connectivity
a. Activate VPN connection from the remote host. You should be able to see something like this on your server if all setup correctly
# wg show
interface: wg0
public key: bAUcnaxxxx95zR27pxxxkwuskLpYM6fCOC219hz1gE=
private key: (hidden)
listening port: 51820
peer: ehISAoqcc1TuuuuuuuuoWGAr4yyyyyy5Oq8qU1i1SA=
endpoint: 85.255.235.8:28431
allowed ips: 10.0.0.2/32
latest handshake: 13 hours, 45 minutes, 5 seconds ago
transfer: 87.82 MiB received, 1.69 GiB sent
References
[1] Building a WireGuard Jail with the FreeBSD's Standard Tools - genneko
[2] Chapter 33. Firewalls | FreeBSD Documentation Portal
[3] FreeBSD IPFW rules for WireGuard | SirToffski