Deploy WireGuard Server With Web UI Through Docker
- Introduction
- Steps
- Creating A Client
- Using Wireguard on Ubuntu
- Using Wireguard On Windows / Mac / Android / iOS
- Appendix
- References
Introduction
This tutorial will show you how to quickly deploy your own WG Easy wireguard server, which I found to be the easiest and fastest way to deploy a VPN server, which even worked behind my dedicated server's NAT (after having configured port forwarding).
If you wish to deploy a Wireguard server from scratch (e.g. not using Docker and without a nice web UI, then I would suggest you watch Christian Lempa's video on Wireguard Installation and configuration instead.
Prerequisites
- Docker and Docker Compose
Steps
Create A Password Hash
WG Easy has switched to using bcrypt hashed passwords rather than having the password as plain text in the environment variables.
To create a strong random password and generate its bcrypt form, I found the easiest solution to be this PHP script I created and ran in the terminal:
<?php
$randomPassword = base64_encode(random_bytes(32));
print "Random password is: " . PHP_EOL;
print $randomPassword . PHP_EOL . PHP_EOL;
$hash = password_hash($randomPassword, PASSWORD_BCRYPT);
print "Bcrypt hash is: " . PHP_EOL;
print $hash . PHP_EOL;
When specifying it in the .env file later, one will need to make sure to wrap the generated hash in single quotes ('
), in order for it to pass through correctly.
Create The Docker Compose File
Log into your server and create the following docker-compose.yml
file wherever you wish to "install" this.
services:
wg-easy:
image: ghcr.io/wg-easy/wg-easy:${WG_VERSION}
container_name: wg-easy
ports:
- "51820:51820/udp"
- "51821:51821/tcp"
restart: unless-stopped
cap_add:
- NET_ADMIN
- SYS_MODULE
sysctls:
- net.ipv4.ip_forward=1
- net.ipv4.conf.all.src_valid_mark=1
volumes:
- ./volumes/wireguard:/etc/wireguard
environment:
- WG_HOST
- PASSWORD_HASH
Create The Environment File
Now create a file called .env
with the following content, in the same directory as the docker-compose.yml file you just created.
Be sure to update the values as appropriate to you.
# Specify the version of WG Easy to use. Check out
# https://github.com/wg-easy/wg-easy/pkgs/container/wg-easy/versions
# or use the value "latest"
WG_VERSION="14"
# Specify the IP/FQDN that client's should try to connect to.
# E.g. your server's public IP address. E.g. "wireguard.mydomain.com" or "168.52.43.28"
WG_HOST=""
# Provide the random password outputted by the script.
PASSWORD_HASH='$2y$XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
Extra - Full List Of Possible Configuration Options
In case you are interested, the full list of possible environment variables can be found on the GitHub page.
If you make use of any additional environment variables, be sure to add them to the docker-compose.yml file as appropriate. E.g. just adding them to the .env
file won't work
on its own.
A common setting that you may wish to set is the WG_DEFAULT_DNS
which you may wish to change to an internal DNS server that you deployed, or
8.8.8.8, 8.8.4.4
if you would prefer to use Google DNS instead of the default, which is Cloudflare's on 1.1.1.1
.
You may also wish to add UI_TRAFFIC_STATS
with a value of true
, in order to turn on traffic stats which default to being off.
Deploy
Run the following command to start the Wireguard server now that we have created the docker-compose.yml
and .env
files.
docker-compose up -d
Optional - Nginx Configuration
I am using a manually deployed Nginx reverse proxy for which I added the following example configuration to have it serve up the site. Tweak it as you need, making sure to update the FQDN and your wireguard servers internal IP address.
server {
listen 80;
server_name wireguard.mydomain.com;
return 302 https://wireguard.mydomain.com$request_uri;
}
server {
listen 443 ssl;
server_name wireguard.programster.org;
access_log /var/log/nginx/access.log;
ssl_certificate ssl/wireguard.mydomain.com/site.crt;
ssl_certificate_key ssl/wireguard.mydomain.com/private.pem;
ssl_protocols TLSv1.3;
ssl_ciphers RC4:HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;
keepalive_timeout 60;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
location / {
proxy_pass http://w.x.y.z:51821/;
include /etc/nginx/proxy.conf;
}
}
Alternatively, you may be interested in using something simpler like Nginx Proxy Manager.
Optional - Change The UDP Port
Unfortuantely, I have a TURN server deployed on that IP whose UDP port range is 49152 - 65535
, for which the default wireguard UDP Port of 51820
is right in the middle of.
Thus I opted to change the Wireguard server to operate on port 40000
instead. This was as easy as adding WG_PORT=40000
to the enviornment variables, and remapping the
UDP port to be listening on the host on port 40000
. The WG_PORT
tells the website to generate the
client configurations such that it tells the client to connect on that port, and we did the port remapping at the Docker level. Below is the updated docker-compose.yml
file:
services:
wg-easy:
image: ghcr.io/wg-easy/wg-easy:${WG_VERSION}
container_name: wg-easy
ports:
- "40000:40000/udp"
- "51821:51821/tcp"
restart: unless-stopped
cap_add:
- NET_ADMIN
- SYS_MODULE
sysctls:
- net.ipv4.ip_forward=1
- net.ipv4.conf.all.src_valid_mark=1
volumes:
- ./volumes/wireguard:/etc/wireguard
environment:
- WG_HOST
- PASSWORD
- WG_PORT=40000
:4000
on the end of the Endpoint
value (assuming you also used port 4000).
Creating A Client
Now that we have deployed our Wireguard server, we need to create a client connection, and download the configuration file in order to use it. Each client will have a fixed IP on this network, meaning that client's can communicate with each other as well.
If you are not using a proxy, then one should be able to connect to the server in one's browser with HTTP on port 51821. If you are using a proxy, then you have probably configured it so that you can connect on HTTPS without specifying a port number.
http://192.168.0.18:51821/
There is no username, and the password is whatever you set in the environment file earlier.
Click on the New button in the top-right corner in order to create a new client connection configuration.
Give it a name to remember it by.
Download it's configuration by clicking on this icon.
The client configuration file will be named after the name you gave the client connection (1).
If you didn't change the DNS through the environment variables, you may wish to just manaully change it here (2).
A value of 1.1.1.1
is for Cloudflare's DNS.
The server's FQDN or IP address should show up as the Endpoint (3). Here I have port 4000 because I manually changed
the server configuration to not clash with my TURN server's UDP port range.
Using Wireguard
Install Required Packages
In order to use Wireguard on Ubuntu, you need to install wireguard and the openresolv packages.
sudo apt update \
&& sudo apt install -y wireguard openresolv
You need to install the openresolv otherwise later you will get:
/usr/bin/wg-quick: line 32: resolvconf: command not found
Move Configuration File Into Place
Move the downloaded configuration file to /etc/wireguard/$NAME_FOR_CONNECTION.conf
and make sure
that the permissions are set to 700
(that file contains your key/secret).
Connect
wg-quick up $NAME_FOR_CONNECTION
If you're used to using OpenVPN, you may find it unusual that the output just stops. Nothing went wrong and you are still connected.
Alternatively, if you don't wish to rely on sticking the configuration file in the expected location, you can simply specify the absolute path to the configuration file like so:
wg-quick up /home/username/vpns/my-wireguard-config.conf
Disconnect
To disconnect, run:
wg-quick down $NAME_FOR_CONNECTION
... or if you used an absolute path to a config file:
wg-quick down /home/username/vpns/my-wireguard-config.conf
Get Status
If you wish to get the status of the wireguard connections (such as seeing if any are up, and how much traffic has flowed through them), you can run:
sudo wg show
BASH Script
I prefer to run my VPN connection in a tmux/byobu session, and leave it running, knowing that I can press ctrl-c to close it when I am done. This also helps prevent me from forgetting that I have a VPN connection open, since it is tying up one of my first tmux session in byobu. To do this, I have a start-vpn command that runs the following BASH lines:
#!/bin/bash
wg-quick up /path/to/vpns/connection-name/client.conf
watch -n 1 sudo wg show
wg-quick down /path/to/vpns/connection-name/client.conf
By doing this, the watch -n 1 sudo wg show
line "ties up" the tmux session, outputting the connection statistics,
until I am ready to quit by pressing ctrl-c. It will then quit out of the watch command and finish by running
the command to shut the connection down, which is exactly what I want.
Using Wireguard On Windows / Mac / Android / iOS
You can download a client from the Wireguard website.
References
- Simplifying VPN Setup - An Introduction to WireGuard Easy for Self-Hosted VPNs
- GItHub - WG Easy
- Reddit - Wireguard: connection between clients?
- SuperUser - Wireguard selective routing
First published: 30th April 2024