Contents
(Simple) Private Tunnel VPN with WireGuard
If you own a Virtual Machine or Virtual Private Server, you can easily setup a VPN server with WireGuard on it to securely tunnel your internet traffic from your home or office.
Once connected to the VPN, outgoing traffic from your VPN client will appear as coming from your server.
There are multiple tutorials online describing how to achieve such a setup. This tutorial uses the default tools for a server with Debian 12 : ifupdown and nftables. For configuration using other network tools, see WireGuard
Don't follow tutorials which recommend executing a random script downloaded from github. Execute commands step by step, and read the man pages of wg(8) and interfaces(5) if you want to know more.
WireGuard setup
WireGuard uses Public Key Authentication, similarly to SSH, which means:
- client and server have both a public and a private key
the client needs to know the VPN server public key before connecting (akin to the SSH server key fingerprint saved in ~/.ssh/known_hosts)
the server authenticates the VPN client using the client public key (akin to the SSH client key saved in ~/.ssh/authorized_keys)
Installation on server
install WireGuard
# apt update # apt install wireguard
- verify the wireguard kernel module is properly installed. This should display the module details, like filename, description, author
$ /sbin/modinfo wireguard
Configuration on server
- create the server keypair:
# mkdir /etc/wireguard/ # chmod 700 /etc/wireguard/ # cd /etc/wireguard/ # wg genkey | tee vpn-server-private.key | wg pubkey > vpn-server-public.key
- print the private key, we’ll need it at the next step
# cat vpn-server-private.key ...
create the WireGuard service config file at /etc/wireguard/wg0.conf
# cat > /etc/wireguard/server.conf << EOF # define the !WireGuard service [Interface] # contents of file vpn-server-private.key PrivateKey = ... # UDP service port ListenPort = 55820 EOF
get the name of the outgoing network interface of your server (ens5 in this example)
$ ip route ls default default via 192.168.121.1 dev ens5 proto dhcp src 192.168.121.132 metric 1024
create a WireGuard network interface configuration, replacing ens5 with the value you got from the above command
# cat > /etc/network/interfaces.d/wg0 << EOF # activate on boot auto wg0 # interface configuration iface wg0 inet static address 10.0.2.1/24 pre-up ip link add wg0 type wireguard pre-up wg setconf wg0 /etc/wireguard/server.conf # route packages when the VPN interface is up post-up sysctl --write net.ipv4.ip_forward=1 # and stop routing when stopping the VPN interface post-down sysctl --write net.ipv4.ip_forward=0 post-down ip link del wg0 iface wg0 inet6 static address fc00:23:5::1/64 # route packages when the VPN interface is up post-up sysctl --write net.ipv6.conf.all.forwarding=1 # and stop routing when stopping the VPN interface post-down sysctl --write net.ipv6.conf.all.forwarding=0 EOF
- activate the new network configuration
# ifup wg0
- inspect the wireguard device created
# wg show wg0 interface: wg0 public key: 2efuG9OYmMPQpbkJ8CVxGlvQflY6p1u+o4wjcgGII0A= private key: (hidden) listening port: 55820
WireGuard client setup
install WireGuard like you did for the server
- create the client keypair:
# mkdir /etc/wireguard/ # chmod 700 /etc/wireguard/ # cd /etc/wireguard/ # wg genkey | tee vpn-client-private.key | wg pubkey > vpn-client-public.key
- create an initial configuration file for wg-quick, a wrapup around the wg command
cat > /etc/wireguard/wg0.conf << EOF [Interface] # Put here the content of vpn-client-private.key PrivateKey = ... Address = 10.0.2.2/24, fc00:23:5::2/64 DNS = 8.8.8.8 [Peer] # Put here the content of vpn-server-public.key created on the server PublicKey = ... Endpoint = wg.example.com:55820 AllowedIPs = 10.0.2.1/32 EOF
add the following at the end of /etc/wireguard/server.conf on your server, so that your client is allowed to connect:
cat >> /etc/wireguard/server.conf << EOF [Peer] # Put here the content of vpn-client-public.key PublicKey = ... AllowedIPs = 10.0.2.2/32 EOF
- finally start a connection from the client:
# wg-quick up wg0
- verify that you can ping the VPN endpoint:
$ ping -c 5 10.0.2.1/24
Routing configuration
Now that we have the VPN working, we want to configure client and server, so that all client traffic is sent to the server by default, and the server masquerades the IP address of the client outgoing packets with its own address.
Server part
define Network Address Translation for nftables. This will allow packages coming from the VPN client to go to the Internet with the IP of the VPN server. Replace ens5 with the name of the network device you got in the previous chapter.
cat >> /etc/nftables.conf << EOF add table wireguard-nat table ip wireguard-nat { chain prerouting { type nat hook prerouting priority -100; policy accept; } chain postrouting { type nat hook postrouting priority 100; policy accept; oifname "ens5" masquerade } } EOF
- make sure nftables configuration is active
systemctl enable --now nftables
- verify that wireguard-nat table and its ruleset is loaded
# nft list tables # nft list ruleset
Client part
- Forward all client traffic to the VPN
# cat >> /etc/wireguard/wg0.conf << EOF AllowedIPs = 0.0.0.0/0, ::/0 EOF
- restart the vpn client
# wg-quick down wg0 # wg-quick up wg0
- display the IP address of an outgoing connection. You should see here the IP address of your server
$ curl ipinfo.io
GUI to start / stop wireguard on the client side
If using a Debian Desktop for your VPN client, you will have NetworkManager installed to manage your wireless connections. NetworkManager can also start / stop the WireGuard tunnel. For this you just need to export your wg-quick configuration wg0.conf into a new NetworkManager profile. See https://blogs.gnome.org/thaller/2019/03/15/wireguard-in-networkmanager/ for details
References