WireGuard has risen in popularity over the last year or so with several adoptions by commercial VPN services. Its
simplicity and speed make it a great choice for a private VPN replacement and having recently been accepted
net-next maintainer tree for inclusion in an upcoming kernel, I figured now was a good time
to give it a try. So, I retired my Raspberry Pi running PiVPN at home and instead set up a LXC in Proxmox to tunnel
all my mobile devices through. I was able to find several guides floating around the net but none of them covered
exactly what I wanted to do. Having to jump between several browser tabs to piece together all the information is a
pain, so I decided to write this up for anyone else who might find it useful. Here is a (hopefully complete) guide to
setting up WireGuard in a container on Proxmox with a sample Android device configuration.
- Proxmox Version: 6.1-3
- Container: Ubuntu 18.04
- Android Phone: Anything compatible with the official WireGuard app.
First, we need to make sure the kernel headers are installed for our current kernel. It's a good idea to make sure everything is up to date first, if a new kernel is installed, boot into it prior to installing the headers.
apt update apt dist-upgrade apt install pve-headers
Now to install WireGuard. As of this writing WireGuard is packaged in Debian Unstable, so a little work needs to be done before it's available to install. The below will create an unstable apt source list file then create an apt preference file to limit automatic installation from this repo. More info about this is available on the Debian Wiki: WireGuard and AptConfiguration
echo "deb http://deb.debian.org/debian/ unstable main" > /etc/apt/sources.list.d/unstable-wireguard.list printf 'Package: *\nPin: release a=unstable\nPin-Priority: 90\n' > /etc/apt/preferences.d/limit-unstable
Now we can install WireGuard and enable the kernel module. We also need to add WireGuard to
modules.conf so that
it will be forced to load at boot time. This is required as the host isn't aware of the container at boot time and
won't know to load the module automatically.
apt install wireguard modprobe wireguard echo "wireguard" >> /etc/modules-load.d/modules.conf
Finally, we need to enable packet forwarding. To do this edit
/etc/sysctl.conf and uncomment the needed line.
Then we'll enable it with the
#net.ipv4.ip_forward=1 # This is the default, uncomment to match below. net.ipv4.ip_forward=1
That's it for the host, on to the container.
Setting up an LXC container is a simple process and many distributions and versions are available, so I'm going to assume you already have one of your preference ready to go. I chose Ubuntu 18.04 because I had a template ready to quickly clone. Here is a link to the WireGuard install page with instructions for all other operating systems. The key difference to keep in mind is that since we're installing into a container that uses the host's kernel, we only need to install the user-space tools and not the kernel module itself.
apt update apt install software-properties-common add-apt-repository ppa:wireguard/wireguard apt install --no-install-recommends wireguard-tools
That should take care of the installation, on to the configuration.
Simple WireGuard VPN Configuration
If you're not familiar with WireGuard, I recommend going here and reading through the conceptual overview to get more background on what's being done here. That said, you should be able to copy these configuration files, substitute values where needed and have a working installation.
The first thing we need to do is create encryption keys for both the container and each device we want to connect.
Normally this would be done on each device individually but, since we're going to use
qrencode to generate a QR
code from the configuration data for the Android app, we'll create the configuration for both the container and
phone alongside each other in the container. For other devices, like a laptop or a remote computer, the configuration
and encryption key generation should be done on the device itself for security purposes.
Let's move into the
/etc/wireguard directory, creating it if necessary, and generate key pairs for both the server
and the phone. Note that we are using
umask here to ensure the proper directory permissions are set prior to key
cd /etc/wireguard/ umask 077 wg genkey | tee server-privatekey | wg pubkey > server-publickey wg genkey | tee android-privatekey | wg pubkey > android-publickey
Next, let's create a configuration file for the server. Using your favorite editor create a file for the interface
configuration. By convention, as this is our first WireGuard interface, we'll call the file
interface needs to be on a different subnet than the host to avoid conflicts, for simplicity here I've chosen
192.168.2.1/24 as the host in this example is on the 192.168.1.0/24 subnet. The entries for private and public keys
need to be substituted with the contents of the previously created key files. The default
can be changed to your choosing, just make sure the
Endpoint entry in the next step reflects this. Also, note the
interface name used in the
PostDown entries, here it is
eth0 but if yours differs
(check by running
ip addr) change it accordingly.
[Interface] Address = 192.168.2.1/24 PrivateKey = <server-privatekey file contents> ListenPort = 51820 PostUp = iptables -A FORWARD -i %i -j ACCEPT; iptables -A FORWARD -o %i -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE PostDown = iptables -D FORWARD -i %i -j ACCEPT; iptables -D FORWARD -o %i -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE [Peer] PublicKey = <android-publickey file contents> AllowedIPs = 192.168.2.2/32
Now we need to create a configuration file for the Android phone. You'll need to substitute your server's IP address
here for the
Endpoint entry and make sure the
ListenPort chosen earlier is copied here if changed from the default
If you don't have a static IP address for your server you'll want to use a service such as DynDNS or some other
method to keep a domain pointed to your server's IP if it changes. I usually purchase a cheap domain name from a
registrar that provides free dynamic DNS service, then I keep it updated using ddclinet on the server. You will
also want to make sure to have the
ListenPort you've chosen forwarded through any router or firewall you may have
to the IP/port of the WireGuard LXC to enable access from outside your LAN.
DNS entry can be inside the local network or outside. Again, the entries for private and public keys need to be
substituted with the contents of the previously created key files. The
PersistentKeepalive entry is helpful if
you're behind NAT and need to keep the connection alive, 25 is the recommended value.
[Interface] PrivateKey = <android-privatekey file contents> Address = 192.168.2.2/24 DNS = 192.168.1.1 [Peer] PublicKey = <server-publickey file contents> Endpoint = <server-ip>:51820 AllowedIPs = 0.0.0.0/0, ::/0 PersistentKeepalive = 25
Finally, lets ensure proper permissions are set for the WireGuard directory, enable and start the service, then create the QR code we need to transfer the configuration over to the phone.
chown -R root:root /etc/wireguard chmod -R og-rwx /etc/wireguard systemctl enable email@example.com systemctl start firstname.lastname@example.org apt install qrencode qrencode -t ansiutf8 < android.conf
After this last step, you should have a QR code displayed in your terminal. If you haven't already, install the official WireGuard Android app from either the Google Play Store or F-Droid. The app is very simple to use and you should only have to open the plus menu on the bottom right, choose ‘create from QR code’, and scan the code. You will be allowed to name the connection and then enable it. If all went well you'll now have a VPN setup that routes all traffic from your phone through the LXC and your local LAN should be accessible. Hope this was helpful, happy tunneling!