Based on the forum post:
https://www.truenas.com/community/resources/how-to-setup-a-wireguard-vpn-server-in-a-jail.147/
Modified some settings to run on its own IP, replaced outdated commands for packages, and added some of my own scripts.
Enable VNET so the jail can have a separate network interface.
The first IP address is for the LAN, ignore the second IP subnet. Clients will connect on the 10.0.0.0/24
subnet, and access the internet and 192.168.0.0
network thorugh this jail.
Enable allow_tun
so the jail can create tunnels.
Installing Wireguard
Within the jail install nano and update the system.
pkg install nano
pkg upgrade
Install Wireguard
pkg install wireguard-go wireguard-tools
Enable Wireguard interface and forwarding.
nano /etc/rc.conf
Paste the following settings in.
# 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"
Create the ipfw.rules file.
nano /usr/local/etc/ipfw.rules
Paste the following settings in.
#!/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 $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
Disable TSO.
nano /etc/sysctl.conf
Paste the following setting in.
net.inet.tcp.tso=0
Restart the jail.
Configure Server
Create a new script for moving into the Wireguard directory. (Optional)
nano cd
This is a bad name for a script, by the way.
#!/bin/bash
cd /usr/local/etc/wireguard
Save the script, and give it run permissions.
chmod +x cd
Now every time something needs to be configured the script can be used to move into the directory. Since the change directory command needs to apply to this terminal and not a new process, this script needs to be run with source cd
.
source cd
Now all actions shall be performed inside /usr/local/etc/wireguard
.
Create a key generating script.
nano generate_keys.sh
#!/bin/sh
# Check if the correct number of arguments is provided
if [ "$#" -ne 1 ]; then
echo "Usage: $0 <peer_name>"
exit 1
fi
# Extract the peer name from the command line argument
peer_name="$1"
# Generate a new private key
private_key=$(wg genkey)
# Generate the corresponding public key
public_key=$(echo "$private_key" | wg pubkey)
# Print the keys to the console
echo "Private Key for $peer_name:"
echo "$private_key"
echo "Public Key for $peer_name:"
echo "$public_key"
# Save the keys to files
private_key_file="${peer_name}.private"
public_key_file="${peer_name}.public"
echo "$private_key" > "$private_key_file"
echo "$public_key" > "$public_key_file"
echo "Keys have been saved to:"
echo "Private Key: $private_key_file"
echo "Public Key : $public_key_file"
Give it run permissions, then generate a keypair for the server, and a client.
chmod +x generate_keys.sh
./generate_keys.sh wg0
./generate_keys.sh peer1
This will generate private and public keys for the server and one peer.
Keep in mind that out of the two sets of keys (the public + private keys of the server and the public + private keys of the peer) each entity of this tunnel knows only three things:
The public and private keys of itself, and only the public key of the target, be it the server or peer.
Create a Wireguard interface.
nano wg0.conf
[Interface]
Address = 10.0.0.1/32
PrivateKey = << wg0.private key>>
ListenPort = 51820
# Peer 1
[Peer]
PublicKey = << peer1.public key>>
AllowedIPs = 10.0.0.2/32
PersistentKeepalive = 10
The PersistentKeepalive
parameter is not recommended. This goes against the silent characteristics of Wireguard and makes it “chatty”. Use it only if the server is behind a NAT. This option will make Wireguard to send a packet every ten seconds and force the NAT to keep the connection open.
Start Wireguard
service wireguard start
Configure Server on Client Side
Create an interface for the peer to use.
nano peer1.conf
[Interface]
Address = 10.0.0.2/32
PrivateKey = << peer1.private key >>
DNS = 1.1.1.1
[Peer]
PublicKey = << wg0.public key >>
AllowedIPs = 0.0.0.0/0,::/0
Endpoint = << Public IP of server >>:<< Exposed port >>
Importing a config on the client can be done manually, or by scanning a QR code.
Create a script to generate a QR code.
nano generate_qrcode.sh
#!/bin/sh
# Check if the correct number of arguments is provided
if [ "$#" -ne 1 ]; then
echo "Usage: $0 <filename>"
exit 1
fi
# Extract the parameter file name from the command line argument
parameter_file="$1"
# Check if the parameter file exists
if [ ! -f "$parameter_file" ]; then
echo "Error: File '$parameter_file' not found."
exit 1
fi
# Run the qrencode command with the specified parameter file
qrencode -t ansiutf8 < "$parameter_file"
Generate a QR code for the peer config file.
./generate_qrcode peer1.conf
Router Configuration
A port needs to be forwarded to the Wireguard server’s IP, and the routing table needs to be modified to send LAN traffic back to the server.
Add a route to the 10.0.0.0
network, telling the router that traffic going to this network should be handed over to the jail running at 192.168.0.24
.
Check Server Status
If a peer connected successfully, check the server’s status.
In the jail, run:
wg
This will return a summary of the connections.
interface: wg0
public key: (hidden)
private key: (hidden)
listening port: 51820
peer: (hidden)
endpoint: << peer1's public IP >>
allowed ips: 10.0.0.2/32
latest handshake: 52 seconds ago
transfer: 69.63 MiB received, 1.05 GiB sent
persistent keepalive: every 10 seconds