Running Wireguard Access Server in an LXC

So it's wireguard in Docker in LXC on Proxmox

This tutorial will tell you how you can run your own Wireguard VPN server with a webgui in an LXC container. Wireguard is a relatively new VPN protocoll which is just as secure as the long-established OpenVPN, but simpler to configure and easier on the hardware which results in faster speeds. The webgui will allow you to easily create configs for each client to grand access to your VPN to all the devices you want.

This guide is largely based on this article on Nix vs Evil.

Assumptions

  • Proxmox 6.2 or newer as the host
  • Ubuntu 18.04 or newer in the container
  • Have docker-compose installed and configured (i.e. nesting activated) in the container

Though it should also work on any other host and client OS.

The Host

Install the kernel headers

sudo apt update
sudo apt upgrade
sudo apt install pve-headers

Install wireguard

This one depends on your distribution and version, because wireguard is part of the 5.6 kernel and may be in your default repository. For Proxmox you have to add it to your repository list though. So open your sources.list.

sudo nano /etc/apt/sources.list

and add the following line

deb http://deb.debian.org/debian buster-backports main

now run

sudo apt update
sudo apt install -t buster-backports wireguard-dkms

If you haven't restarted after the last time you updated the kernel, you have to restart now as the headers get install for the newest installed kernel and not the one you are currently running.

Enable the kernel module

modprobe wireguard
echo "wireguard" >> /etc/modules-load.d/modules.conf

Enable IP-forwarding

If you want to use regular wireguard in the LXC this step is not needed for the host (but maybe for the container. I don't know tbh). But when you want to use the access server via docker you need to do this for the host.

So open /etc/sysctl.conf

sudo nano /etc/sysctl.conf

and uncomment (i.e. remove the #) from the line

#net.ipv4.ip_forward=1

then run

sudo sysctl -p

Forward the tun device

In my case I want to run wireguard in the LXC with the number 100. If yours has a different number, you need to change the following command accordingly.

Open the config of the container. It is usually located under /etc/pve/lxc

sudo nano /etc/pve/lxc/100.conf

and add the line

lxc.mount.entry: /dev/net/tun dev/net/tun none bind,create=file

This completes the steps for the host. Let's switch to the container.

LXC

Install wireguard-tools

You may try this step first without adding the repository as the packet is now usually included in the official repositories. If that fails you can still add the repo and try the installation again.

sudo apt update
sudo apt install software-properties-common
sudo add-apt-repository ppa:wireguard/wireguard
sudo apt install --no-install-recommends wireguard-tools

Create the docker-compose.yml

Create an empty docker-compose.yml where you usually store them (e.g. ~/docker/wg-access-server/) and paste the example docker-compose.yml into it, but uncomment the second volume and set a admin password under environment.

Set a private key

Just run

wg genkey

and put that output also in the docker-compose.yml as your WG_WIREGUARD_PRIVATE_KEY. If you are unsure you did it corrent, compare to my example compose file at the end.

Create a config

In the same directory as the docker-compose.yml create a config.yaml (notice the silghtly different extension) and paste

loglevel: info
storage: sqlite3:///data/db.sqlite3
dns:
  upstream:
    - "8.8.8.8"

into it. If you want to know what all this does, have a look at the documentation of wg-access-server.

Run it

You are now ready to fire it up.

docker-compose up -d

In case docker-compose complains about an unsupported version of the docker-compose file, you can either update your docker-compose or just reduce the version number of your file to 3.6 of even 3.0. More information about this issue con be found on github.

If you now visit your server on port 8000 you can add a device to your VPN with two clicks.

Example docker-compose.yml

version: "3.7"
services:
  wg-access-server:
    # to build the docker image from the source
    # build:
    #   dockerfile: Dockerfile
    #   context: .
    image: place1/wg-access-server
    container_name: wg-access-server
    cap_add:
      - NET_ADMIN
    volumes:
      - "wg-access-server-data:/data"
      - "./config.yaml:/config.yaml" # if you have a custom config file
    environment:
      - "WG_ADMIN_USERNAME=admin"
      - "WG_ADMIN_PASSWORD=mysupersecurepassword"
      - "WG_WIREGUARD_PRIVATE_KEY=cB6grOG+NReoxjXXAqQOP5gm6KHgxkaljTHQ8GmQ40U="
    ports:
      - "8000:8000/tcp"
      - "51820:51820/udp"
    devices:
      - "/dev/net/tun:/dev/net/tun"

# shared volumes with the host
volumes:
  wg-access-server-data:
    driver: local