-
Notifications
You must be signed in to change notification settings - Fork 0
Home
How to Setup a VPN Router With Wireguard
This article creates a VPN Router using Wireguard, this example will use RHEL or its clones (RockyLinux / AlmaLinux) but AlpineLinux works just as well as a Linux Container (CT)..
All source code associated with this article can be found in my GitHub here.
Here’s what you’ll need to get started on this project.
A working copy of Proxmox and a RockyLinux CT Template.
I prefer using Rocky Linux because it’s lightweight and free of unnecessary extras. Since this setup will be headless, there’s no need for anything elaborate, as adding unnecessary features could compromise the security of your configuration.
WireGuard is a modern, fast, and secure VPN (Virtual Private Network) protocol designed to simplify and improve network tunneling. It operates at the network layer (Layer 3) and uses state-of-the-art cryptographic protocols, making it both secure and efficient. Unlike older VPN protocols like OpenVPN or IPSec, WireGuard is lightweight, with a minimal codebase of around 4,000 lines. This smaller size enhances security by reducing potential vulnerabilities and makes it easier to audit.
WireGuard establishes encrypted point-to-point connections between devices, ensuring confidentiality, integrity, and authenticity of the data. Its simplicity allows for quick setup and excellent performance, often outperforming traditional VPNs in terms of speed and reduced latency. It is especially popular for mobile devices because it efficiently handles network changes, such as switching between Wi-Fi and mobile data.
The protocol uses pre-shared public keys for authentication and does not require certificates, simplifying management. WireGuard is cross-platform, supporting Linux, Windows, macOS, iOS, and Android, and is integrated directly into the Linux kernel for maximum performance.
Designed for both personal and enterprise use, WireGuard is ideal for securely connecting remote workers, cloud servers, or IoT devices, offering a blend of security, simplicity, and high-speed performance.
The first step is to install some essential packages on your system. These packages will provide the necessary tools and dependencies that our scripts will use to set up your VPN router.
dnf update
dnf upgrade
dnf install openssh-server
systemctl enable sshd
systemctl start sshd
dnf -y install iptables wireguard-tools bind-utils mtr systemd-resolved
systemctl enable --now systemd-resolved
reboot
In the command above, we install WireGuard, SSH, and iptables. Since some versions may not include iptables by default, ensure it is installed. Additionally, reboot the system if the installation updates the kernel or adds a kernel module to ensure all changes are applied correctly.
/etc/wireguard/wg0.conf
[Interface]
# Bouncing = 11
# NetShield = 0
# Moderate NAT = on
# NAT-PMP (Port Forwarding) = on
# VPN Accelerator = on
PrivateKey = xxxxxxxxxxx
Address = 10.2.0.2/32
DNS = 10.2.0.1
PostUp = /root/wg_rules_up.sh eth0
PostDown = /root/wg_rules_down.sh
[Peer]
# VPN
PublicKey = xxxxxxx
AllowedIPs = 0.0.0.0/0
Endpoint = 1.2.3.4:51820
# Ensures that your home router does not kill the tunnel, by sending a ping
# every 25 seconds.
PersistentKeepalive = 25
Once you download you should be presented with the following code that allows you to do this:
wg_rules_up.sh
#!/bin/bash
if [ "$#" -ne 1 ]; then
echo "$0 <interface name>"
exit -1
fi
IFACE=$1
echo "Using interface: $1"
echo "Flushing iptables rules"
iptables -F
iptables -t nat -F
iptables -P INPUT ACCEPT
iptables -P OUTPUT ACCEPT
iptables -P FORWARD ACCEPT
echo "Current IP: `curl -s -4 ifconfig.co`"
# temporarily block forwarding so nothing leaks if we restart this script
sysctl -w net.ipv4.ip_forward=0
# allow ssh
echo "Allowing incoming/outgoing SSH established on all interfaces"
iptables -A INPUT -p tcp --dport 22 -j ACCEPT
iptables -A OUTPUT -p tcp --sport 22 -j ACCEPT
echo "Allowing DHCP traffic"
iptables -A INPUT -j ACCEPT -p udp --dport 67:68 --sport 67:68
iptables -A OUTPUT -j ACCEPT -p udp --dport 67:68 --sport 67:68
echo "Allowing traffic on lo"
iptables -A OUTPUT -j ACCEPT -o lo
iptables -A INPUT -j ACCEPT -i lo
echo "Allowing traffic on wg"
iptables -A OUTPUT -j ACCEPT -o wg+
iptables -A INPUT -j ACCEPT -i wg+
# allow traffic from established connections
echo "Allowing already established traffic"
iptables -A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
# allow wireguard uid, we need this prior we run wireguard because wireguard drops permissions at the end
# make sure the port number below reflects the one from your wireguard server
echo "Allowing wireguard traffic"
iptables -A OUTPUT -p udp -m udp --dport 51820 -j ACCEPT
# allow dns because it's a third party system app that tries to do it (and not wireguard)
echo "Allowing DNS for resolving wireguard server"
iptables -A OUTPUT -p udp --dport 53 -j ACCEPT
# allow traffic on wg0 and lo
echo "Allowing lo and wg interfaces"
iptables -A OUTPUT -j ACCEPT -o lo
iptables -A OUTPUT -j ACCEPT -o wg+
# allow forward traffic only from wg0
iptables -A FORWARD -m state --state ESTABLISHED,RELATED -j ACCEPT
# this is important we need to send all traffic that is being forwarded to wg0
iptables -A FORWARD -i $IFACE -o wg0 -j ACCEPT
# masq traffic on wg0
echo "Masquerading traffic on wg0"
iptables -t nat -A POSTROUTING -o wg0 -j MASQUERADE
# this is the path of your VPN configuration
#wireguard PATH_TO_YOUR_VPN_FILE.ovpn &
echo "Waiting for VPN to initialize"
sleep 10
#echo "Current IP: `curl -s -4 ifconfig.co`"
echo "Setting policy in output and input chain to drop"
iptables -P OUTPUT DROP
iptables -P INPUT DROP
iptables -P FORWARD DROP
# block dns because it's a third party system app that tries to do it (and not wireguard)
echo "Blocking DNS for resolving wireguard server"
iptables -D OUTPUT -p udp --dport 53 -j ACCEPT
echo "Turning on IP forwarding"
sysctl -w net.ipv4.ip_forward=1
Now add the service and start.
sudo systemctl enable wg-quick@wg0.service
sudo systemctl daemon-reload
sudo systemctl start wg-quick@wg0
To test the setup, reboot your system and configure your host operating system to use the IP address of your Rocky Linux system as its router. Once configured, visit a website that displays your public IP address. If everything is working correctly, the IP address shown should be that of your VPN service provider, not your local network.
An easy way to check this is by visiting showmyip.com or searching “What is my IP address” online. The displayed IP address should match your VPN service provider’s IP, confirming that the VPN router is functioning properly.
The script automatically takes care of you having a kill switch if the connection to your VPN drops. This is accounted by the following the destination.
wg_rules_down.sh
echo "Flushing iptables rules"
iptables -F
iptables -t nat -F
iptables -P INPUT ACCEPT
iptables -P OUTPUT ACCEPT
iptables -P FORWARD ACCEPT
echo "Current IP: `curl -s -4 ifconfig.co`"
# temporarily block forwarding so nothing leaks if we restart this script
sysctl -w net.ipv4.ip_forward=0
The reason the VPN traffic still goes through is because earlier in the script we allow any traffic going to the port of the VPN service to be allowed along with DNS requests in order to resolve any hostnames. This can be seen in the following commands:
echo "Allowing DNS for resolving wireguard server"
iptables -A OUTPUT -p udp --dport 53 -j ACCEPT
echo "Allowing openvpn traffic"
iptables -A OUTPUT -p udp -m udp --dport 51820 -j ACCEPT