create your own VPN server with WireGuard in Docker

In this tutorial, I will show you how to easily create your own private VPN server with WireGuard running in a Docker container. I will walk you step by step through the installation, configuration, and how to add clients to your VPN server.

You can follow this tutorial with any Ubuntu- or Debian-based Linux distro. Other distros may also work, but it isn’t tested and optimized by the creator of the docker image, we’re using. In my case, I’ve used Ubuntu 20.04 LTS, because it already has installed the WireGuard kernel module.


install docker and docker-compose

Before we can create and start containers, we need to install Docker and Docker-compose. If you already have installed docker and docker-compose on your server, you may skip these steps.

sudo apt-get install apt-transport-https ca-certificates curl gnupg-agent software-properties-common
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"
sudo apt-get update && sudo apt-get install docker-ce docker-ce-cli containerd.io
sudo curl -L "https://github.com/docker/compose/releases/download/1.26.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose
sudo usermod -aG docker $USER
newgrp docker

Create a docker-compose file

Next, we need to create a docker-compose file to easily manage your WireGuard container. To do that, I’m using a docker image and template from the website https://linuxserver.io. The guys from linuxserver.io are ethusiasts and manage docker images for the community.

First, I create a new folder in the /opt directory called /opt/wireguard-server and create a new docker-compose.yaml file in this directory. You should also change the ownership of this folder to your Linux user.

sudo mkdir /opt/wireguard-server
sudo chown christian:christian /opt/wireguard-server
vim /opt/wireguard-server/docker-compose.yaml

In this file, you can use the following template, please refer to the linuxserver/wireguard documentation: https://hub.docker.com/r/linuxserver/wireguard

version: "2.1"
services:
  wireguard:
    image: linuxserver/wireguard
    container_name: wireguard
    cap_add:
      - NET_ADMIN
      - SYS_MODULE
    environment:
      - PUID=1000
      - PGID=1000
      - TZ=Europe/London
      - SERVERURL=wireguard.domain.com #optional
      - SERVERPORT=51820 #optional
      - PEERS=1 #optional
      - PEERDNS=auto #optional
      - INTERNAL_SUBNET=10.13.13.0 #optional
    volumes:
      - /opt/wireguard-server/config:/config
      - /lib/modules:/lib/modules
    ports:
      - 51820:51820/udp
    sysctls:
      - net.ipv4.conf.all.src_valid_mark=1
    restart: unless-stopped

Replace the SERVERURL with the public IP address of your WireGuard Server, because your clients will need to connect from outside your local network. You can also set this to auto, the docker container will automatically determine your public IP address and use this in the client’s configuration.


start your WireGuard Server

Now you can start your WireGuard container with the following command and clients should be able to connect.

cd /opt/wireguard-server
docker-compose up -d

Distribute the config files to clients

You could also use the linuxserver/wireguard docker image for your clients. But I think it’s more practical for a client to install WireGuard directly on the host OS. If you want to know how to do that, you can also refer to my article about WireGuard installation and configuration on Linux.

When you have started the WireGuard container, it should automatically create all configuration files in your /opt/wireguard-server/config folder. All you need to do is to copy the corresponding peer1/peer1.conf file to your client and use that as your wg0.conf, for instance. If you want to connect mobile phones you can also just scan the peer1.png QR code, to print the QR code to the console, simply use the following command

docker exec -it wireguard /app/show-peer <peer-number>

Add additional clients

If you want to add additional clients, you simply can increase the PEERS parameter in the docker-compose.yaml file. After changing this value you need to restart your docker container with the –force-recreate parameter.

docker-compose up -d --force-recreate

Summary

I hope you like this article and this was useful to you. Please leave me a comment if you enjoyed it and also don’t forget to have a look at my YouTube channel for upcoming videos, for instance.

9 thoughts on “create your own VPN server with WireGuard in Docker”

  1. Hallo Christian, erstmals danke für die tolle Dokumentation. Ich spiele gerade mit dem Gedanken, VPN für mein Smarthome einzurichten. Wie sicher ist es einen Tunnel im Docker Container zu terminieren? Auf dem Docker Host laufen doch einige interne Dienste wie Smarthome, NAS, etc. Danke und LG, Cavediver

    Reply
    • Hallo 😉 Ingesamt ist WireGuard meine Meinung nach ein sehr sicheres Protokoll. Ich weis zwar nicht genau was dein Anwendungsfall ist, du solltest aber ohne Probleme WireGuard für eine VPN (egal mit oder ohne Docker) dafür einsetzen können. Was beim Docker Container zu beachten ist: Hier musst du eventuell etwas mit dem Netzwerk experimentieren, ob du das im host-modus laufen lässt, damit der Docker Container das Interface auf dem Host-System verwendet, oder ob du das Interface in dem Container terminieren lässt und der Traffic dann entsprechend geroutet wird. Generell ist das aber alles Möglich, da WireGuard sehr flexibel ist und es eigentlich nur darauf ankommt, wie du es konfigurierst.

      Reply
  2. Hello,

    I did the setup exactly as mentioned by you and added a peer using the qr code. It shows connected but i cannot browse the internet when i get connected to the vpn server. please can you advise what could be wrong.

    Reply
    • I would try to check if the network packets are arriving at the hosts wg0 interface. You should try with tcpdump -envi wg0 on the docker containers wg0 interface. Note you need to execute from the docker container via docker exec -it wireguard "tcpdump -envi wg0". Possible reasons are the packets are not arriving at the host or the host can’t process or forward these packets.

      Reply
  3. I think I followed the instructions, but it does not seem to be creating the peer1.conf
    any suggestions where to start looking?
    Thanks

    Reply
    • Check if the “wireguard” kernel module is loaded on the host OS with lsmod | grep wireguard. If it’s not loaded it won’t create any configs. I had the same issue when there were pending software updates on the host OS, or sometimes it fails to install the kernel module on the host OS.

      Reply
    • If you’re using the docker image from this tutorial, you can simply change the number of peers in the compose file. It will automatically create new peer configs once you restart the container.

      Reply

Leave a Comment

I accept the Privacy Policy