Ultimate WireGuard Docker Compose: with CF and Traefik Support

Wireguard Docker Compose configuration to provide unique VPN user’s experience, reliable and secure VPN for accessing our networks from, basically, everywhere!

In this guide, we are going to see how to implement a Wireguard Docker Compose configuration to deploy our Wireguard VPN docker. Docker compose makes it very simple to deploy Wireguard VPN.

But before we dive in, let's cover some basics.

Background Information for Wireguard Docker Compose Setup

WireGuard Basics

A lot of words have already been spent on Wireguard, but here's a quick review on it anyway (source Wikipedia):

WireGuard is a communication protocol and free and open-source software that implements encrypted virtual private networks (VPNs), and was designed with the goals of ease of use, high speed performance, and low attack surface. It aims for better performance and more power than IPsec and OpenVPN, two common tunneling protocols. The WireGuard protocol passes traffic over UDP.

Wireguard vs IPsec vs OpenVPN

Up to now, it is faster and more performant than its primary competitors IPsec and OpenVPN:

Wireguard Benchmark With His Competitors
Wireguard Benchmark With His Competitors (Source Wireguard)

These benchmarks are old, crusty, and not super well conducted. In the intervening time, WireGuard and IPsec have both gotten faster, with WireGuard stil edging out IPsec in some cases due to its multi-threading, while OpenVPN remains extremely slow.

But they are useful to give an idea of the superiority of the protocol.
If we ever wanted to test it by ourself, we can find some scripts here.

It is also well documented, easy to implement, cross-plattform and, last but not least, open-source and easy to audit, as the source code is way lighter than his competitors.

For a quick introduction to this amazing protocol, review our previous WireGuard articles:

Other Posts in the Wireguard Series:

Docker Basics

We should be already familiar with Docker, anyway:

Docker is a tool that is used to automate the deployment of applications in lightweight containers so that applications can work efficiently in different environments in isolation.

If you need help installing and configuring docker, I suggest to read these Anand's articles and set it all EASILY:

I also recommend to take some time and read these other two articles, that will also come in handy for other purposes:

After this short smattering, let's get our hands dirty starting with docker compose configuration file.

Note: I'm going to use Anand's docker configuration (filename, folder structure, etc.), so if something is not clear about it, you know what to do.

1. Wireguard Docker Compose Configuration

The configuration reported ahead is the simplest, shortest, minimalist configuration that we need to use to have a Wireguard VPN Server up and running. We will use the WireGuard Docker image from Linuxserver.io:

version: '3.9'

services:
  wireguard:
  image: lscr.io/linuxserver/wireguard:latest
  container_name: Wireguard
  cap_add:
    - NET_ADMIN
  environment:
    - PUID=$PUID
    - PGID=$PGID
    - TZ=$TZ
    - PEERS=Profile1,Profile2,OtherProfile
  volumes:
    - $DOCKERDIR/appdata/wireguard:/config
  ports:
    - 51820:51820/udp
  sysctls:
    - net.ipv4.conf.all.src_valid_mark=1
  restart: unless-stopped

Naturally, we need to setup a port forward from external port 51820 to our Docker Compose Server, on the same port: I only used default Wireguard Server port in all the configuration to keep it simple, but no one forbids us to set different port numbers.

Port 51820 from the WireGuard Docker container is mapped to the same port on the host machine.

Explanation of Docker Compose for Wireguard

Here is a schematic of what's going on:

Wireguard Forwarding Path
Reaching Wireguard Server Docker

Changing Default Wireguard Port

As I mentioned before, we could set different ports keeping in mind a few things. Here are a few things to ensure when using a port other than the default 51820:

  • Remember to do a port forward from that port to the docker compose stack's port (quite obvious).
  • Set it in the "ports" section of wireguard service in the yaml file:
              ports:
                - 51700:51820/udp # First number is the port used by docker compose stack, second one is the port used by Wireguard server docker
            
  • Set it in the "environment" section of wireguard service in the yaml file:
              environment:
                - PUID=$PUID
                - PGID=$PGID
                - TZ=$TZ
                - PEERS=Profile1,Profile2,OtherProfile
                - SERVERPORT=51699
            

    In this case, we need to adjust the "ports" section too:

              ports:
                - 51700:51699/udp 
            
Note: For the rest of this tutorial I'll use standard port 51820 everywhere, I just wanted to show how to change ports just in case someone needed it.

Wireguard Peer Configuration

After this, basically, we could retrieve our configuration file or QR code and get instantly connected to our network from the outside.

  1. Configuration files:
  2. These files are located inside the /config/peer_ProfileName folder (folder names are the same chosen in the PEERS environment variable plus the "peer_" suffix (ex: peer_Profile1)) and are named like "peer_Profile1.conf":

                  environment:
                    [...]
                    - PEERS=Profile1,Profile2,OtherProfile
                    [...]
                  volumes:
                    - $DOCKERDIR/appdata/wireguard:/config
              

    We could save and import them (Android/iOS app, Windows/Linux/Mac client) to get the configuration of the corresponding profile.

  3. QR codes:
  4. To display the QR code(s), we need to run a command inside the Wireguard server docker, followed by the names of the profiles we need:

                 # Run this on the docker compose stack terminal
                 # this will be executed inside the Wireguard server docker,
                 # thanks to docker exec command
                 docker exec -it Wireguard /app/show-peer Profile1,Profile2
             

    And like magic, the codes are displayed directly on our terminal, ready to be scanned from our Android/iOS app. Of course, in the profile folders, mentioned before, there are the .png files with the QR codes, but I strongly discourage their use because there's nothing more beautiful than seeing them displayed directly on the terminal. TRUST ME!

2. Wireguard Docker Compose Configuration with Optional Fields

The above standard Wireguard VPN docker compose works great. But why stop there if you can customize a few more options to enhance the experience?

I'll write the optional fields commented, then we're going to discuss them:

version: '3.9'

services:
    wireguard:
    image: lscr.io/linuxserver/wireguard:latest
    container_name: Wireguard
#   networks:                                 
#      t2_proxy:                                
#         ipv4_address: 192.168.2.10          
    cap_add:
      - NET_ADMIN
    environment:
      - PUID=$PUID
      - PGID=$PGID
      - TZ=$TZ
#      - SERVERURL=<OUR PUBLIC IP>               
#      - SERVERPORT=51820                       
#      - PEERS=Profile1,Profile2,OtherProfile       
#      - PEERDNS=<DNS IP>                        
#      - INTERNAL_SUBNET=192.168.10.0/24        
#      - ALLOWEDIPS=0.0.0.0/0                   
#      - LOG_CONFS=false                          
    volumes:
      - $DOCKERDIR/appdata/wireguard:/config
    ports:
      - 51820:51820/udp
    sysctls:
      - net.ipv4.conf.all.src_valid_mark=1
    restart: unless-stopped

Networks Block

This is used if we want to set a local static ip to our Wireguard server docker (check Anand's guide for more info about this configuration).

Environment Variables

    - SERVERURL: our public IP, if not specified it will be automatically detected. We could also use our customized domain name.
    - SERVERPORT: needed if we want to use a different port for our Wireguard Server Docker.
    - PEERS: optional field but useful, as we can choose the profile names we want and avoid wasting time trying to figure out the association between users and random name configuration files.
    - PEERDNS: the DNS server, if we have an internal DNS solution like Pi-Hole or AdGuard Home we can use it.
    - INTERNAL_SUBNET: the subnet used for peers IP.
    - ALLOWEDIPS: we can configure the allowed IP that could be reached through the tunnel. If configured with 0.0.0.0/0, or omitted, all the traffic from the client will be routed through the tunnel, and all the devices on the network would be reachable.
    - LOG_CONFS: the generated QR codes are visible in the docker log.

3. Cloudflare & Traefik Configuration (OPTIONAL)

The docker compose configuration we've just analyzed, with the appropriate port forwarding, is enough to have our Wireguard Server Docker up and running. But if we use services, like Cloudflare, to hide our public IP we need to have some trade-offs.

Cloudflare Proxy Proxied Ports

In the Cloudflare Free Plan the port proxied by default are:

HTTP ports supported by Cloudflare:

  • 80
  • 8080
  • 8080
  • 8880
  • 2052
  • 2082
  • 2086
  • 2095

HTTPS ports supported by Cloudflare:

  • 443
  • 2053
  • 2083
  • 2087
  • 2096
  • 8443

Ports supported by Cloudflare, but with caching disabled:

  • 2052
  • 2053
  • 2082
  • 2083
  • 2086
  • 2087
  • 2095
  • 2096
  • 8880
  • 8443

All of these ports could be only used to proxy HTTP and HTTPS, not suitable for our purposes.

Using Domain Names with Wireguard

So, if we still want to use our customized domain name for Wireguard, we have two options:

  • Expose our real ip, disabling the proxy function from the Cloudflare dashboard.
  • Cloudflare Dns Only Configuration
    Cloudflare Dns Only Configuration
  • Configure a Spectrum application (CLOUDFLARE PAID PLANS ONLY) from Cloudflare dashboard, but I cannot guarantee that this will work as I haven't tested this option. If someone want to try this option, this is the Cloudflare page with instructions to do so.

If we don't care about having our customized domain name, we can of course use our public ip in the Wireguard server docker configuration (environment variable SERVERURL).

Wireguard Server Docker with Traefik Reverse Proxy

Let's assume we have chosen to expose our real ip and use our custom domain name, now we could configure our reverse proxy, Traefik in this case, in order to forward the requests to the Wireguard Server Docker.

This step could safely be skipped, because, as I said before, our configuration is already working without the need for further modifications, but is very useful for keeping monitored which ports we've exposed, directly from our Traefik dashboard, on our Docker Compose Stack.

Let's edit our docker compose configuration file docker-compose.yml:

The configuration below shows only the additional parts implemented for Wireguard Server Docker. To view the complete configuration file, check Anand's Traefik Docker Compose Guide.
version: '3.9'

services:
    traefik:
      #### other traefik compose options not shown ####
      ports:
      # Port WIREGUARD
        - target: 51820
          published: 51820
          protocol: udp
          mode: host
      command:
        - --entryPoints.wg.address=:51820/udp

    wireguard:
      image: lscr.io/linuxserver/wireguard:latest
      container_name: Wireguard         
      cap_add:
        - NET_ADMIN
      environment:
        - PUID=$PUID
        - PGID=$PGID
        - TZ=$TZ
        - SERVERURL=wireguard.mydomain.com                                     
        - PEERS=Profile1,Profile2,OtherProfile                         
      volumes:
        - $DOCKERDIR/appdata/wireguard:/config
#      Ports section could be omitted as Traefik 
#      will take care of it
#      ports:
#        - 51820:51820/udp
      sysctls:
        - net.ipv4.conf.all.src_valid_mark=1
      restart: unless-stopped
      labels:
        - "traefik.enable=true"
        - "traefik.udp.routers.wg.entrypoints=wireguard"
        - "traefik.udp.routers.wg.service=wireguard-udp-svc"
        - "traefik.udp.services.wg-udp-svc.loadbalancer.server.port=51820"

Personally, I prefer to not expose real IP using "DNS only" option from Cloudflare. This is because if we have more than one domain name proxied and our real public IP would be discovered and associated to one of them, all the extra protection layer provided by Cloudflare becomes futile.

Now that everything has been configured, the only remaining thing to do is start Wireguard Server Docker and spread some love for this amazing protocol.

!BONUS TRACK! Ad-Blocking on-the-go

Time for extra content that could make our life easier.

Membership Required

You must be a member to access this content.

View Membership Levels

Already a member? Log in here

FAQ

What is the difference between Wireguard, Wireguard Server Docker, Wireguard VPN docker?

"Wireguard VPN Docker" and "Wireguard Server Docker" are basically the same thing, that is our Wireguard Server deployed inside a docker container. "Wireguard" the protocol.

Can WireGuard run in Docker?

Yes, Wireguard Server can run in Docker or can be configured directly on Linux. Server installation could also be deployed on Windows, but this configuration is not officially supported.

How secure is WireGuard?

Wireguard uses cryptographic protocols and primitives that are consolidated and reviewed by cryptographers, so the data sent through the VPN tunnel can be considered safe. Like all the protocols, we have some known limitations listed on the official Wireguard site.

Does WireGuard work on Linux?

Wireguard client runs on every operating system (Android, iOS, Windows, Linux, Mac), the server runs officially on Linux only.

How do I host a WireGuard VPN?

We could choose different ways: we could use docker to host our Wireguard Server Docker, or we could use Linux to install and configure our Wireguard Server.

Concluding Remarks on Wireguard VPN Docker

We have written a lot about Wireguard and a lot about Docker. Wireguard has simplified what has long been a cumbersome task with lots of overhead. The result is increased performance with some or better security.

Therefore, it is no surprise that some of the major VPN providers (shout out to our favorite VPN provider, Surfshark) are starting to offer this protocol.

With this guide, we combined two of our favorites to install WireGuard VPN server using Docker. We also tried to address some advanced scenarios such as working with Cloudflare and Traefik. We hope that this simple WireGuard Docker Compose guide get you started with enough basics to level up your setup and knowledge.

Be the 1 in 200,000. Help us sustain what we do.
104 / 150 by Dec 31, 2024
Join Us (starting from just $1.67/month)