This configuration is for a standalone Wireguard VPN service (without integration with Traefik Proxy).
Note
This config is not to be confused with the other wireguard config that is integrated with Traefik. The one included with Traefik is a layer 7 (HTTP) proxy. On the other hand, this config is used as a generic layer 4 (TCP/UDP) VPN service, which is lower level than the one integrated with Traefik. On the whole, this one is much simpler to configure, but each one has specific tradeoffs.
Reasons you may wish to use this wireguard config:
- If you want a layer 4 (TCP/UDP) tunnel for privacy enhanced internet access with roaming capability (eg. a typical consumer privacy shield, with SNAT IP masquerading). All of your internet traffic will appear to originate from your fixed public server IP address (not your local router's).
- If you want to expose a layer 4 private service (TCP/UDP), running behind a NAT firewall, to the public internet (DNAT port forwarding), using a public gateway (running on a droplet/VPS) as the go between. This does not require any opening of ports on the local router (only the public gateway server needs open ports).
- You want optional IPv6 support.
Reasons you may wish to use the other Traefik integrated wireguard instead of this one:
- If you want to run a private layer 7 (HTTP) service in the cloud, accessible from various locations, (eg. a company wide intranet service).
- If you want to expose select layer 7 (HTTP) applications (routed based on domain name), to the public internet, from a fixed location (eg. home or office), and you are capable of opening a public UDP port (eg. 51820) in each location's firewall.
-
Setup d.rymcg.tech on a public server (VPS) according to the main README.md (Note: you do not need to install Traefik on the public VPS.)
-
Create a public DNS entry for your wireguard server (eg.
wireguard.example.com
) pointing to the IP address of your Docker host server.
Next, from this directory, run:
make config # This creates the .env_{CONTEXT} config file.
Answer the questions to enter the following required config settings:
WIREGUARD_HOST
- Enter the fully qualified domain name you chose for this wireguard service (eg.wireguard.example.com
).WIREGUARD_PEERS
- Enter the comma separated list of all the peer configs to create. Each peer name must be alphanumeric with no spaces, no dashes, no underscores. (eg.myclient1,myclient2,myclient3
)
There are additional variables in the .env_{CONTEXT}
file you may
wish to edit by hand, see the comments in .env-dist.
You may wish to run public services at home, which typically are not
accessible from the internet. To expose these services to the world,
set WIREGUARD_PUBLIC_PEER_PORTS
in your .env file, and this will
setup port forwarding (DNAT) through the VPN tunnel. There is no need
to open any port in your LAN router, and so it should work from any
random internet hotspot, or most other networks outside of your
control.
For example, to open ports 443
and 53
publicly, running on two
separate VPN clients:
# Format is a comma separated list of 4-tuples:
# PEER_IP_ADDRESS-PEER_PORT-PUBLIC_PORT-PORT_TYPE,...
WIREGUARD_PUBLIC_PEER_PORTS=10.13.17.2-443-443-tcp,10.13.17.3-53-53-udp
Note
The 4-tuple port mapping is separated with dashes -
not the traditional colon
:
because that is reserved for IPv6 addresses. If you want create a public peer port for an IPv6 address it would be like WIREGUARD_PUBLIC_PEER_PORTS=fd8c:8ac3:9074:5183::2-443-443-tcp
For each peer that runs a server behind a NAT firewall, you must
enable the "keep alive" setting. This will ensure that the wireguard
connection stays available for incoming requests. Set
WIREGUARD_PERSISTENTKEEPALIVE_PEERS
:
# Specify the list of peers to send keep alive packets to:
# (eg 'all', or a comma separated list of peer names. Set blank to turn it off.)
WIREGUARD_PERSISTENTKEEPALIVE_PEERS=all
For more details, see the full comments in .env-dist.
From this directory, run:
make install
From this directory, run:
make show-wireguard-peers ## Prints ALL of the peer configs.
All of the peer config files will be printed to the screen in
sequence. Notice that they are each separated by a comment at the top
starting like ## /config/peer_myclient1/peer_myclient1.conf
.
If you want to setup mobile clients (android), you may instead wish to see the QR encoded copy of the same information. Run:
make show-wireguard-peers-qr ## Prints the QR code for every peer config.
There are many different wireguard clients you can choose from, including:
- wg-quick which is included with the main wireguard-tools distribution.
- NetworkManager which includes a GUI style configuration.
- vpn.sh included in this repository as our own custom script for this config.
This repository includes its own script vpn.sh which is a
simple Bash script that invokes the wg
and ip
commands directly,
requiring no further dependencies.
Client requirements:
-
Any Linux machine, native or virtual, with
root
access or any account withsudo
privileges. (No Docker required!) -
Install all dependent packages:
bash
,iproute2
,wireguard-tools
.- Arch:
pacman -S bash iproute2 wireguard-tools
- Debian/Ubuntu:
apt install bash iproute2 wireguard-tools
- Fedora:
dnf install bash iproute wireguard-tools
- Arch:
Download the script:
curl -O https://raw.githubusercontent.com/EnigmaCurry/d.rymcg.tech/master/wireguard/vpn.sh
Simply copy all of the settings shown from your peer config (make show-wireguard-peers
) into the variables at the top of the script and
then run the script to start the VPN:
chmod +x vpn.sh
./vpn.sh up
To bring the connection back down again, run:
./vpn.sh down
Test that the connection behaves correctly using tools like ping
,
tracepath
(or traceroute
), and external IP finding tools like
curl ifconfig.me
. Now that you know it works, continue reading to
learn about how to enable the systemd service, so that it starts
automatically on boot.
This script was written according to "The Classic Solutions: Improved Rule-based Routing" from wireguard.com, which it is documented that this loosly follows the same thing that wg-quick does, just in a more transparent fashion. The wireguard.com guide shows an even cooler, superior method, using network namespaces, and they included a script for that method. It is slightly more complex than this "classic solution", and their script does not appear to be compatible with tools like NetworkManager, so vpn.sh has not yet attempted to implement the namespace method.
Suppose that when you ran make config
you created three clients:
archdev,bob,mary
.
In order to setup the clients, you need to view the configuration for each of these peers (which includes the unique wireguard keys required for each client to connect).
Run make show-wireguard-peers
. It will print the config for all
three peers archdev
, bob
, and mary
.
Let's consider only the first one, archdev
. Here is an example
output for the config file for archdev
:
## Example output of `make show-wireguard-peers` ...
## /config/peer_archdev/peer_archdev.conf
[Interface]
Address = 10.13.17.2
PrivateKey = oNnzcPVu/iXpfxQQSS84U0vwdm4ODHJm2/gVONV10kU=
ListenPort = 51820
DNS = 10.13.17.1
[Peer]
PublicKey = vHH1QfTfX0exdowq4HkChUiwl5cVHSG35iDELm+vFno=
PresharedKey = IWJpkj8FeajeoqnRATnccNZAo+KZOwEPF8m0mRTHYUY=
Endpoint = wireguard.example.net:51820
AllowedIPs = 0.0.0.0/0,::0/0
### bob and mary configs follow after this, ignore them for now ....
Notice that the archdev
config is annotated with the comment showing
the config file path inside the server wireguard container
(/config/peer_archdev/peer_archdev.conf
), and the bob
and mary
ones are printed after that.
Log into the client computer that archdev
uses, and download the
vpn.sh script onto that computer. Open the script in a text
editor, and you will need to copy the information shown from the peer
config into the variables at the top of the script. Here is what you
need to edit into the top part of that file, with the same values as
shown in the peer config (make sure you changeWG_ADDRESS
, WG_PRIVATE_KEY
,
WG_PEER_PUBLIC_KEY
, WG_PEER_PRESHARED_KEY
, and WG_PEER_ENDPOINT
,
your actual values WILL BE DIFFERENT, all of the other settings can
probably be left alone.):
## An Excerpt from the vpn.sh script (near the top of the file)
## You'll need to change at least these four variables according to your config:
WG_ADDRESS=10.13.17.2
WG_PRIVATE_KEY=oNnzcPVu/iXpfxQQSS84U0vwdm4ODHJm2/gVONV10kU=
WG_PEER_PUBLIC_KEY=vHH1QfTfX0exdowq4HkChUiwl5cVHSG35iDELm+vFno=
WG_PEER_PRESHARED_KEY=IWJpkj8FeajeoqnRATnccNZAo+KZOwEPF8m0mRTHYUY=
WG_PEER_ENDPOINT=wireguard.example.net:51820
In order to run the script, the user will need to be root
, or at
least have sudo privileges.
Now that the file is edited, you can run it to start the VPN client:
## Make the script executable:
chmod a+x ./vpn.sh
## To start the VPN client:
./vpn.sh up
## To stop the VPN client:
./vpn.sh down
By default, the vpn.sh client script is setup to force ALL
non-local (non-LAN) traffic over the VPN. If you want to make it so
only some traffic goes over the VPN, while the rest should go over
your normal connection, you can customize the variable called
WG_PEER_ALLOWED_IPS
in the script.
By default, this value is set to
WG_PEER_ALLOWED_IPS=0.0.0.0/0,::0/0
, which means that ALL non-local
(non-LAN) traffic (both ipv4 and ipv6) will go over the VPN. That's
usually what you want for a typical consumer privacy shield.
If you have more advanced use cases, you can customize it. For
example, if you have two subnets you want to go over the VPN, but
everything else you want to go over the normal connection, set it like
this (comma separated CIDR
notation):
WG_PEER_ALLOWED_IPS=10.13.17.0/24,192.168.100.0/24
. Every network
range that is listed in this list will go over the VPN, and
conversely, everything NOT in that list will go over your normal
internet connection.
You can use a tool like tracepath to confirm which route a particular connection will take.
vpn.sh automatically manages your system /etc/resolv.conf
by default, configurable by the following environment variables:
WG_USE_VPN_DNS=true
(default) -true
means to create a new/etc/resolv.conf
file using theWG_DNS
nameserver value.false
means don't touch/etc/resolv.conf
, leaving whatever setting is already there.WG_DNS=10.13.17.1
(default) - set this to your preferred DNS resolver address.
The default values are setup for preventing DNS leaks, forcing all
system level DNS queries to go to the wireguard server directly. (in
this case, a "leak" would be where the DNS was allowed to go to your
local LAN resolver, instead of through the VPN. The default values
prevent this.) Please be advised that not all applications will honor
/etc/resolv.conf
, and may use their own settings (especially
browsers with a DNS-over-HTTP privacy setting.)
If you do not want vpn.sh
to touch your /etc/resolv.conf
, set
WG_USE_VPN_DNS=false
.
Note
When you run ./vpn.sh up
, with the setting WG_USE_VPN_DNS=true
,
the script will copy the original (ie. non-vpn) /etc/resolv.conf
to
/tmp/vpn.sh.non-vpn-resolv.conf
as a backup, and then creates a new
/etc/resolv.conf
that forces the use of the WG_DNS
nameserver
address. This is so that when you run ./vpn.sh down
it can restore
the original /etc/resolv.conf
. It is important that this occurs
before system reboots, otherwise the wrong file will be in place on
next boot. Therefore, it is recommended to use the systemd service,
which takes care of this step for you.
When you run ./vpn.sh up
, it only sets up the VPN temporarily. If
you reboot the machine, the VPN will no longer be running. You can
install a systemd service
in order to automatically start the VPN every time you start your
computer.
To create the systemd service, run:
./vpn.sh systemd-enable
This will create a systemd unit file at
/etc/systemd/service/vpn.service
.
You can now manage the VPN as any other systemd service.
To view the status, run:
systemctl status vpn
To view the logs, run:
journalctl -u vpn
To disable the VPN, run:
systemctl disable --now vpn
To re-enable the VPN, run:
systemctl enable --now vpn
With the service enabled, the service will start automatically on every system boot.
To completely remove the systemd service:
./vpn.sh systemd-disable
## Or simply delete /etc/systemd/system/vpn.service
Note
The entire configuration for the VPN still lives inside vpn.sh. The systemd unit file (/etc/systemd/system/vpn.service) points to the original location of vpn.sh. Once installed, you should not move nor delete the script!
The server and client keys are stored in the volume of the wireguard container on the server. If you want to delete them all, you can simply destroy the container volume:
# Remove the wireguard server, volume, and ALL of the wireguard keys:
make destroy
To recreate the wireguard server, and issue NEW keys to all clients, simply reinstall:
## Since the wireguard volume does not exist anymore, it will be recreated, creating new keys:
make install
The container image (linuxserver/docker-wireguard) that this config is based upon does not officially support IPv6, however, this configuration has been modified to make it work.
There are a few requirements in order to get IPv6 to work:
- The host platform that you run your wireguard server on must natively support IPv6.
- You must configure the Docker daemon to enable IPv6.
For example, if you are using DigitalOcean to run your Docker server, consult the DigitalOcean documentation for enabling IPv6 (hint: enable IPv6 before you create the droplet).
You also must edit the Docker daemon configuration file to enable IPv6, because as of Docker 25 it is still not enabled in the default configuration. Consult the Docker documentation for details.
On your Docker server, as root, edit the file
/etc/docker/daemon.json
. This file does not exist by default, so if
it doesn't exist, you must create it. Enter the following into the
(new) file:
{
"experimental": true,
"ip6tables": true
}
Restart Docker, (or just reboot your server):
sudo systemctl restart docker
You must edit the .env_{CONTEXT}
file (created after make config
),
and change the following variables for IPv6:
-
WIREGUARD_IPV6_ENABLE=true
- this is the setting that controls whether or not you wish to enable IPv6 at all. By default, it is set tofalse
, disabling the feature entirely. -
WIREGUARD_SUBNET_IPV6
- this is the IPv6 subnet to use for your peers (analagous to the theWIREGUARD_SUBNET
setting used for IPv4). The subnet you choose should be in the dedicated private range starting withfd
. This setting should NOT be in CIDR notation, instead it should simply end in a single digit0
to indicate the start of the range and each new client will increment this digit by one. You can generate a random subnet on this page (or just use the one provided in the default config, if it doesn't conflict for you). -
WIREGUARD_ALLOWEDIPS
- this is the list of IP ranges that are allowed to be trafficked on the VPN. It can contain both IPv4 and IPv6 ranges. By default, the value is0.0.0.0/0,::0/0
meaning ALL ipv4 and ALL ipv6 address are allowed. Make sure the ranges you pick are set in CIDR notation, separated by commas to specify multiple ranges. -
WIREGAURD_PUBLIC_PEER_PORTS
- if you want to make your private services public, you can add the port mapping to the list inWIREGAURD_PUBLIC_PEER_PORTS
. It accepts both IPv4 and IPv6 addresses. Because of this, each port mapping uses the-
character rather than the traditional:
character (since:
is used in IPv6 addresses). For example, if you wanted to open port 443 on both IPv4 and IPv6, you could use the following example:WIREGAURD_PUBLIC_PEER_PORTS=10.13.17.2-443-443-tcp,fd5c:d2af:a2c6:7d61::2-443-443-tcp
-
WIREGUARD_IPV6_DOCKER_SUBNET
- this is the subnet used for the Docker container networking interfacing with the host. It should NOT be the same subnet asWIREGUARD_SUBNET_IPV6
. Choose a unique subnet by generating another random subnet (or just use the default one provided).
Check the comments in .env-dist for more details.
Configuring the vpn.sh script should be straight forward,
you just copy the information directly from the values provided by
make show-wireguard-peers
. Here is a brief description of the config
as it relates to IPv6:
-
WG_ADDRESS
is a list of the IP addresses to assign to the clientwg0
network interface. By default you will have an IPv4 address only. But if the wireguard server has IPv6 enabled, you will have both listed, eg.WG_ADDRESS=10.13.17.2,fd5c:d2af:a2c6:7d61::2
-
WG_PEER_ALLOWED_IPS
is a list of the allowed network ranges, both IPv4 and IPv6, exactly like theWIREGUARD_ALLOWEDIPS
setting for the server. eg.WG_PEER_ALLOWED_IPS=0.0.0.0/0,::0/0
.