Register for the iXsystems Community to get an ad-free experience and exclusive discounts in our eBay Store.
Resource icon

How-To: Setup a Wireguard VPN Server in a Jail

[DRAFT] open to comments

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 "Advance Mode"
jail1.png


b. Enable NAT, VNET and (optional) set default iface to your NIC, in my case: bg0
jail2.png


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
jail3.png

jail5.png


d. Jail properties enable "allow_tun"
jail4.png


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
Code:
# 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"
Code:
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 libqrencode

Step 3: Set up wireguard & Jail networking (jail <-> wireguard)

a. Enable Wireguard iface, NAT & IP forwarding in "rc.conf"
# nano /etc/rc.conf

d. ensure the following lines exist in your rc.conf
Code:
# 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"


e. Create the ipfw.rules file
# nano /usr/local/etc/ipfw.rules

d. Paste the below lines into the file, Ctrx+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.

Code:
#!/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-specifig rules
$cmd 00099 reass all from any to any in       # reassamble 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 $pif keep-state
#$cmd 00325 $skip tcp from any to any out via $pif setup keep-state
#$cmd 00330 $skip icmp from any to any out via $pif 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
Code:
net.inet.tcp.tso="0"


e. Restart the Jail & go get back to the console
Code:
# exit
# iocase 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

# iocase console <<wireguard jail>>



f. Confirm firewall settings loaded. Note: The above config of ipfw rules should look like this
Code:
# 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 3: Setup Wireguard Server & remote host configs

a. Create public/private key pairs for wireguard server and remote host
Code:
# 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"
Code:
[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


c. Start Wireguard service
Code:
# 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

Code:
[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
Code:
[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)
Code:
# 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
Code:
# 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] https://genneko.github.io/playing-with-bsd/networking/freebsd-wireguard-jail/
[2] https://www.freebsd.org/doc/handbook/firewalls-ipfw.html
[3] https://sirtoffski.github.io/docs/freebsd-ipfw/
Author
FreeVel
Views
593
First release
Last update
Rating
5.00 star(s) 1 ratings

Latest reviews

Works perfectly first time and so simple!
Top