diff --git a/edge/advanced/migrate/from-14-to-15/index.html b/edge/advanced/migrate/from-14-to-15/index.html index 56eb2ab6..7cbad116 100644 --- a/edge/advanced/migrate/from-14-to-15/index.html +++ b/edge/advanced/migrate/from-14-to-15/index.html @@ -881,6 +881,15 @@ + + +
This guide will help you migrate from v14
to version v15
of wg-easy
.
wg-easy
project. Therefore the configuration files and the way you interact with the project have changed.wg-easy
project, therefore the configuration files and the way you interact with the project have changed.v15
.INSECURE
environment variable to true
in the new container.INSECURE
environment variable to true
in the new container.Before you start the migration, make sure to backup your existing configuration files.
-Go into the Web Ui and click the Backup button, this should download a wg0.json
file.
Before you start the migration, make sure to back up your existing configuration files.
+Go into the Web UI and click the Backup button, this should download a wg0.json
file.
Or download the wg0.json
file from your container volume to your pc.
You will need this file for the migration
+You will also need to back up the old environment variables you set for the container, as they will not be automatically migrated.
Follow the instructions in the Getting Started or Basic Installation guide to start the new container.
In the setup wizard, select that you already have a configuration file and upload the wg0.json
file you downloaded in the backup step.
v15 does not use the same environment variables as v14, most of them have been moved to the Admin Panel in the Web UI.
You have now successfully migrated to v15
of wg-easy
.
wg-easy
","text":"\u00a0This Documentation is Versioned
Make sure to select the correct version of this documentation! It should match the version of the image you are using. The default version corresponds to the :latest
image tag - the most recent stable release.
This documentation provides you not only with the basic setup and configuration of wg-easy
but also with advanced configuration, elaborate usage scenarios, detailed examples, hints and more.
wg-easy
is the easiest way to run WireGuard VPN + Web-based Admin UI.
If you're new to wg-easy, make sure to read the Getting Started chapter first. If you want to look at examples for Docker Run and Compose, we have an Examples page.
"},{"location":"#contributing","title":"Contributing","text":"We are always happy to welcome new contributors. For guidelines and entrypoints please have a look at the Contributing section.
"},{"location":"#migration","title":"Migration","text":"If you are migrating from an older version of wg-easy
, please read the Migration chapter.
Here are some frequently asked questions or errors about wg-easy
. If you have a question that is not answered here, please feel free to open a discussion on GitHub.
This error indicates that the WireGuard interface wg0
does not exist. This can happen if the WireGuard kernel module is not loaded or if the interface was not created properly.
To resolve this issue, you can try the following steps:
Load the WireGuard kernel module: If the WireGuard kernel module is not loaded, you can load it manually by running:
sudo modprobe wireguard\n
Load the WireGuard kernel module on boot: If you want to ensure that the WireGuard kernel module is loaded automatically on boot, you can add it to the /etc/modules
file:
echo \"wireguard\" | sudo tee -a /etc/modules\n
This error indicates that the nat
table in iptables
does not exist. This can happen if the iptables
kernel module is not loaded or if the nat
table is not supported by your kernel.
To resolve this issue, you can try the following steps:
Load the nat
kernel module: If the nat
kernel module is not loaded, you can load it manually by running:
sudo modprobe iptable_nat\n
Load the nat
kernel module on boot: If you want to ensure that the nat
kernel module is loaded automatically on boot, you can add it to the /etc/modules
file:
echo \"iptable_nat\" | sudo tee -a /etc/modules\n
This error indicates that the nat
table in ip6tables
does not exist. This can happen if the ip6tables
kernel module is not loaded or if the nat
table is not supported by your kernel.
To resolve this issue, you can try the following steps:
Load the nat
kernel module: If the nat
kernel module is not loaded, you can load it manually by running:
sudo modprobe ip6table_nat\n
Load the nat
kernel module on boot: If you want to ensure that the nat
kernel module is loaded automatically on boot, you can add it to the /etc/modules
file:
echo \"ip6table_nat\" | sudo tee -a /etc/modules\n
This error indicates that the filter
table in iptables
cannot be initialized due to permission issues. This can happen if you are not running the command with sufficient privileges.
To resolve this issue, you can try the following steps:
Load the filter
kernel module: If the filter
kernel module is not loaded, you can load it manually by running:
sudo modprobe iptable_filter\n
Load the filter
kernel module on boot: If you want to ensure that the filter
kernel module is loaded automatically on boot, you can add it to the /etc/modules
file:
echo \"iptable_filter\" | sudo tee -a /etc/modules\n
This error indicates that the filter
table in ip6tables
cannot be initialized due to permission issues. This can happen if you are not running the command with sufficient privileges.
To resolve this issue, you can try the following steps:
Load the filter
kernel module: If the filter
kernel module is not loaded, you can load it manually by running:
sudo modprobe ip6table_filter\n
Load the filter
kernel module on boot: If you want to ensure that the filter
kernel module is loaded automatically on boot, you can add it to the /etc/modules
file:
echo \"ip6table_filter\" | sudo tee -a /etc/modules\n
This page explains how to get started with wg-easy
. The guide uses Docker Compose as a reference. In our examples, we mount the named volume etc_wireguard
to /etc/wireguard
inside the container.
Before you can get started with deploying your own VPN, there are some requirements to be met:
There are a few requirements for a suitable host system:
About the Container Runtime
On the host, you need to have a suitable container runtime (like Docker or Podman) installed. We assume Docker Compose is installed. We have aligned file names and configuration conventions with the latest Docker Compose specification. If you're using podman, make sure to read the related documentation.
"},{"location":"getting-started/#deploying-the-actual-image","title":"Deploying the Actual Image","text":""},{"location":"getting-started/#tagging-convention","title":"Tagging Convention","text":"To understand which tags you should use, read this section carefully. Our CI will automatically build, test and push new images to the following container registry:
ghcr.io/wg-easy/wg-easy
)All workflows are using the tagging convention listed below. It is subsequently applied to all images.
tag Type Example Description15
latest minor for that major tag ghcr.io/wg-easy/wg-easy:15
latest features for specific major versions, no breaking changes, recommended latest
latest tag ghcr.io/wg-easy/wg-easy:latest
or ghcr.io/wg-easy/wg-easy
points to latest release, can include breaking changes 15.0
latest patch for that minor tag ghcr.io/wg-easy/wg-easy:15.0
latest patches for specific minor version 15.0.0
specific tag ghcr.io/wg-easy/wg-easy:15.0.0
specific release, no updates edge
push to master
ghcr.io/wg-easy/wg-easy:edge
mostly unstable, gets frequent package and code updates development
pull requests ghcr.io/wg-easy/wg-easy:development
used for development, testing code from PRs When publishing a tag we follow the Semantic Versioning specification. The latest
tag is always pointing to the latest stable release. If you want to avoid breaking changes, use the major version tag (e.g. 15
).
Use the Correct Commands For Stopping and Starting wg-easy
Use sudo docker compose up / down
, not sudo docker compose start / stop
. Otherwise, the container is not properly destroyed and you may experience problems during startup because of inconsistent state.
That's it! It really is that easy.
"},{"location":"advanced/api/","title":"API","text":"Breaking Changes
This API is not yet stable and may change in the future. The API is currently in development and is subject to change without notice. The API is not yet documented, but we will add documentation as the API stabilizes.
You can use the API to interact with the application programmatically. The API is available at /api
and supports both GET and POST requests. The API is designed to be simple and easy to use, with a focus on providing a consistent interface for all endpoints.
There is no documentation for the API yet, but this will be added as the underlying library supports it.
"},{"location":"advanced/api/#authentication","title":"Authentication","text":"To use the API, you need to authenticate using Basic Authentication. The username and password are the same as the ones you use to log in to the web application. If you use 2FA, the API will not work. You need to disable 2FA in the web application to use the API.
"},{"location":"advanced/api/#authentication-example","title":"Authentication Example","text":"import requests\nfrom requests.auth import HTTPBasicAuth\n\nurl = \"https://example.com:51821/api/client\"\nresponse = requests.get(url, auth=HTTPBasicAuth('username', 'password'))\nif response.status_code == 200:\n data = response.json()\n print(data)\nelse:\n print(f\"Error: {response.status_code}\")\n
"},{"location":"advanced/api/#endpoints","title":"Endpoints","text":"The Endpoints are not yet documented. But as file-based routing is used, you can find the endpoints in the src/server/api
folder. The method is defined in the file name.
src/server/api/client.get.ts
/api/client
GET src/server/api/setup/2.post.ts
/api/setup/2
POST"},{"location":"advanced/config/optional-config/","title":"Optional Configuration","text":"You can set these environment variables to configure the container. They are not required, but can be useful in some cases.
Env Default Example DescriptionPORT
51821
6789
TCP port for Web UI. HOST
0.0.0.0
localhost
IP address web UI binds to. INSECURE
false
true
If access over http is allowed"},{"location":"advanced/config/unattended-setup/","title":"Unattended Setup","text":"If you want to run the setup without any user interaction, e.g. with a tool like Ansible, you can use these environment variables to configure the setup.
These will only be used during the first start of the container. After that, the setup will be disabled.
Env Example Description GroupINIT_ENABLED
true
Enables the below env vars 0 INIT_USERNAME
admin
Sets admin username 1 INIT_PASSWORD
Se!ureP%ssw
Sets admin password 1 INIT_HOST
vpn.example.com
Host clients will connect to 1 INIT_PORT
51820
Port clients will connect to and wireguard will listen on 1 INIT_DNS
1.1.1.1,8.8.8.8
Sets global dns setting 2 INIT_IPV4_CIDR
10.8.0.0/24
Sets IPv4 cidr 3 INIT_IPV6_CIDR
2001:0DB8::/32
Sets IPv6 cidr 3 \u00a0Variables have to be used together
If variables are in the same group, you have to set all of them. For example, if you set INIT_IPV4_CIDR
, you also have to set INIT_IPV6_CIDR
.
If you want to skip the setup process, you have to configure group 1
Security
The initial username and password is not checked for complexity. Make sure to set a long enough username and password. Otherwise, the user won't be able to log in.
It's recommended to remove the variables after the setup is done to prevent the password from being exposed.
"},{"location":"advanced/metrics/prometheus/","title":"Prometheus","text":"To monitor the WireGuard server, you can use Prometheus and Grafana. The container exposes a /metrics/prometheus
endpoint that can be scraped by Prometheus.
To enable Prometheus metrics, go to Admin Panel > General and enable Prometheus.
You can optionally set a Bearer Password for the metrics endpoints. This is useful if you want to expose the metrics endpoint to the internet.
"},{"location":"advanced/metrics/prometheus/#configure-prometheus","title":"Configure Prometheus","text":"You need to add a scrape config to your Prometheus configuration file. Here is an example:
scrape_configs:\n - job_name: 'wg-easy'\n scrape_interval: 30s\n metrics_path: /metrics/prometheus\n static_configs:\n - targets:\n - 'localhost:51821'\n authorization:\n type: Bearer\n credentials: 'SuperSecurePassword'\n
"},{"location":"advanced/metrics/prometheus/#grafana-dashboard","title":"Grafana Dashboard","text":"You can use the following Grafana dashboard to visualize the metrics:
21733
Unofficial
The Grafana dashboard is not official and is not maintained by the wg-easy
team. If you have any issues with the dashboard, please contact the author of the dashboard. See #1299 for more information.
If you want to migrate from an older version of wg-easy
to the new version, you can find the migration guides listed below.
v14
.This guide will help you migrate from v14
to version v15
of wg-easy
.
wg-easy
project. Therefore the configuration files and the way you interact with the project have changed.v15
.INSECURE
environment variable to true
in the new container.Before you start the migration, make sure to backup your existing configuration files.
Go into the Web Ui and click the Backup button, this should download a wg0.json
file.
Or download the wg0.json
file from your container volume to your pc.
You will need this file for the migration
"},{"location":"advanced/migrate/from-14-to-15/#remove-old-container","title":"Remove old container","text":"If you are using docker run
docker stop wg-easy\n
If you are using docker-compose
docker-compose down\n
"},{"location":"advanced/migrate/from-14-to-15/#start-new-container","title":"Start new container","text":"Follow the instructions in the Getting Started or Basic Installation guide to start the new container.
In the setup wizard, select that you already have a configuration file and upload the wg0.json
file you downloaded in the backup step.
You have now successfully migrated to v15
of wg-easy
.
When refactoring, writing or altering files, adhere to these rules:
pnpm lint
to check your scripts! Your contributions are checked by GitHub Actions too, so you will need to do this..vscode/settings.json
file.Make sure to select edge
in the dropdown menu at the top. Navigate to the page you would like to edit and click the edit button in the top right. This allows you to make changes and create a pull-request.
Alternatively you can make the changes locally. For that you'll need to have Docker installed. Run
pnpm docs:serve\n
This serves the documentation on your local machine on port 8080
. Each change will be hot-reloaded onto the page you view, just edit, save and look at the result.
This project is Open Source. That means that you can contribute on enhancements, bug fixing or improving the documentation.
"},{"location":"contributing/issues-and-pull-requests/#opening-an-issue","title":"Opening an Issue","text":"Attention
Before opening an issue, read the README
carefully, study the docs for your version (maybe latest) and your search engine you trust. The issue tracker is not meant to be used for unrelated questions!
When opening an issue, please provide details use case to let the community reproduce your problem.
Attention
Use the issue templates to provide the necessary information. Issues which do not use these templates are not worked on and closed.
By raising issues, I agree to these terms and I understand, that the rules set for the issue tracker will help both maintainers as well as everyone to find a solution.
Maintainers take the time to improve on this project and help by solving issues together. It is therefore expected from others to make an effort and comply with the rules.
"},{"location":"contributing/issues-and-pull-requests/#filing-a-bug-report","title":"Filing a Bug Report","text":"Thank you for participating in this project and reporting a bug. wg-easy
is a community-driven project, and each contribution counts!
Maintainers and moderators are volunteers. We greatly appreciate reports that take the time to provide detailed information via the template, enabling us to help you in the best and quickest way. Ignoring the template provided may seem easier, but discourages receiving any support.
Markdown formatting can be used in almost all text fields (unless stated otherwise in the description).
Be as precise as possible, and if in doubt, it's best to add more information that too few.
When an option is marked with \"not officially supported\" / \"unsupported\", then support is dependent on availability from specific maintainers.
"},{"location":"contributing/issues-and-pull-requests/#pull-requests","title":"Pull Requests","text":"Motivation
You want to add a feature? Feel free to start creating an issue explaining what you want to do and how you're thinking doing it. Other users may have the same need and collaboration may lead to better results.
"},{"location":"contributing/issues-and-pull-requests/#submit-a-pull-request","title":"Submit a Pull-Request","text":"The development workflow is the following:
master
. Please use the pull-request template to provide a minimum of contextual information and make sure to meet the requirements of the checklist.Pull requests are automatically tested against the CI and will be reviewed when tests pass. When your changes are validated, your branch is merged. CI builds the new :edge
image on every push to the master
branch and your changes will be included in the next version release.
It seems like the Docs on how to setup AdGuard Home are not available yet.
Feel free to create a PR and add them here.
"},{"location":"examples/tutorials/auto-updates/","title":"Auto Updates","text":""},{"location":"examples/tutorials/auto-updates/#docker-compose","title":"Docker Compose","text":"With Docker Compose wg-easy
can be updated with a single command:
cd /etc/docker/containers/wg-easy\nsudo docker compose up -d --pull always\n
"},{"location":"examples/tutorials/auto-updates/#watchtower","title":"Watchtower","text":"If you want the updates to be fully automatic you can install Watchtower. This will check for updates every day at 4:00 AM and update the container if a new version is available.
File: /etc/docker/containers/watchtower/docker-compose.yml
services:\n watchtower:\n image: containrrr/watchtower:latest\n volumes:\n - /var/run/docker.sock:/var/run/docker.sock\n env_file:\n - watchtower.env\n restart: unless-stopped\n
File: /etc/docker/containers/watchtower/watchtower.env
WATCHTOWER_CLEANUP=true\nWATCHTOWER_SCHEDULE=0 0 4 * * *\nTZ=Europe/Berlin\n\n# Email\n# WATCHTOWER_NOTIFICATIONS_LEVEL=info\n# WATCHTOWER_NOTIFICATIONS=email\n# WATCHTOWER_NOTIFICATION_EMAIL_FROM=mail@example.com\n# WATCHTOWER_NOTIFICATION_EMAIL_TO=mail@example.com\n# WATCHTOWER_NOTIFICATION_EMAIL_SERVER=smtp.example.com\n# WATCHTOWER_NOTIFICATION_EMAIL_SERVER_USER=mail@example.com\n# WATCHTOWER_NOTIFICATION_EMAIL_SERVER_PASSWORD=\"SuperSecurePassword\"\n# WATCHTOWER_NOTIFICATION_EMAIL_SERVER_PORT=587\n
cd /etc/docker/containers/watchtower\nsudo docker compose up -d\n
"},{"location":"examples/tutorials/auto-updates/#docker-run","title":"Docker Run","text":"sudo docker stop wg-easy\nsudo docker rm wg-easy\nsudo docker pull ghcr.io/wg-easy/wg-easy\n
And then run the docker run -d \\ ...
command from Docker Run again.
To update wg-easy
(and every container that has auto updates enabled), you can run the following command:
sudo podman auto-update\n
"},{"location":"examples/tutorials/basic-installation/","title":"Basic Installation","text":""},{"location":"examples/tutorials/basic-installation/#requirements","title":"Requirements","text":"Follow the Docs here: https://docs.docker.com/engine/install/ and install Docker on your host.
"},{"location":"examples/tutorials/basic-installation/#install-wg-easy","title":"Installwg-easy
","text":"Create a directory for the configuration files (you can choose any directory you like):
sudo mkdir -p /etc/docker/containers/wg-easy\n
Download docker compose file
sudo curl -o /etc/docker/containers/wg-easy/docker-compose.yml https://raw.githubusercontent.com/wg-easy/wg-easy/master/docker-compose.yml\n
Start wg-easy
cd /etc/docker/containers/wg-easy\n sudo docker-compose up -d\n
If you are using a firewall, you need to open the following ports:
These ports can be changed, so if you change them you have to update your firewall rules accordingly.
"},{"location":"examples/tutorials/basic-installation/#setup-reverse-proxy","title":"Setup Reverse Proxy","text":"wg-easy
","text":"To update wg-easy
to the latest version, run:
cd /etc/docker/containers/wg-easy\nsudo docker-compose pull\nsudo docker-compose up -d\n
"},{"location":"examples/tutorials/basic-installation/#auto-update","title":"Auto Update","text":"If you want to enable auto-updates, follow the instructions here: Auto Updates
"},{"location":"examples/tutorials/caddy/","title":"Caddy","text":"Opinionated
This guide is opinionated. If you use other conventions or folder layouts, feel free to change the commands and paths.
We're using Caddy here as reserve proxy to serve wg-easy
on https://wg-easy.example.com via TLS.
caddy
","text":".\n\u251c\u2500\u2500 compose.yml\n\u2514\u2500\u2500 Caddyfile\n\n1 directory, 2 files\n
# compose.yml\n\nservices:\n caddy:\n container_name: caddy\n image: caddy:2.10.0-alpine\n # publish everything you deem necessary\n ports:\n - '80:80/tcp'\n - '443:443/tcp'\n - '443:443/udp'\n networks:\n - caddy\n restart: unless-stopped\n volumes:\n - './Caddyfile:/etc/caddy/Caddyfile:ro'\n - config:/config\n - data:/data\n\nnetworks:\n caddy:\n name: caddy\n\nvolumes:\n config:\n data:\n
# Caddyfile\n\n{\n # setup your email address\n email mail@example.com\n}\n\nwg-easy.example.com {\n # since the container will share the network with wg-easy\n # we can use the proper container name\n reverse_proxy wg-easy:80\n tls internal\n}\n
...and start it with:
sudo docker-compose up -d\n
"},{"location":"examples/tutorials/caddy/#adapt-the-docker-composition-of-wg-easy","title":"Adapt the docker composition of wg-easy
","text":"services:\n wg-easy:\n # sync container name and port according to Caddyfile\n container_name: wg-easy\n environment:\n - PORT=80\n # no need to publish the HTTP server anymore\n ports:\n - \"51820:51820/udp\"\n # add to caddy network\n networks:\n caddy:\n ...\n\nnetworks:\n caddy:\n external: true\n ...\n
...and restart it with:
sudo docker-compose up -d\n
You can now access wg-easy
at https://wg-easy.example.com and start the setup.
To setup the IPv6 Network, simply run once:
docker network create \\\n -d bridge --ipv6 \\\n -d default \\\n --subnet 10.42.42.0/24 \\\n --subnet fdcc:ad94:bacf:61a3::/64 wg \\\n
To automatically install & run wg-easy
, simply run:
docker run -d \\\n --net wg \\\n -e INSECURE=true \\\n --name wg-easy \\\n --ip6 fdcc:ad94:bacf:61a3::2a \\\n --ip 10.42.42.42 \\\n -v ~/.wg-easy:/etc/wireguard \\\n -v /lib/modules:/lib/modules:ro \\\n -p 51820:51820/udp \\\n -p 51821:51821/tcp \\\n --cap-add NET_ADMIN \\\n --cap-add SYS_MODULE \\\n --sysctl net.ipv4.ip_forward=1 \\\n --sysctl net.ipv4.conf.all.src_valid_mark=1 \\\n --sysctl net.ipv6.conf.all.disable_ipv6=0 \\\n --sysctl net.ipv6.conf.all.forwarding=1 \\\n --sysctl net.ipv6.conf.default.forwarding=1 \\\n --restart unless-stopped \\\n ghcr.io/wg-easy/wg-easy:15\n
The Web UI will now be available at http://0.0.0.0:51821.
"},{"location":"examples/tutorials/dockerless/","title":"Without Docker","text":"This is currently not yet supported.
"},{"location":"examples/tutorials/podman-nft/","title":"Podman + nftables","text":"This guide will show you how to run wg-easy
with rootful Podman and nftables.
Create a Folder for the configuration files:
sudo mkdir -p /etc/containers/systemd/wg-easy\nsudo mkdir -p /etc/containers/volumes/wg-easy\n
Create a file /etc/containers/systemd/wg-easy/wg-easy.container
with the following content:
[Container]\nContainerName=wg-easy\nImage=ghcr.io/wg-easy/wg-easy:15\nAutoUpdate=registry\n\nVolume=/etc/containers/volumes/wg-easy:/etc/wireguard:Z\nNetwork=wg-easy.network\nPublishPort=51820:51820/udp\nPublishPort=51821:51821/tcp\n\n# this is used to allow access over HTTP\n# remove this when using a reverse proxy\nEnvironment=INSECURE=true\n\nAddCapability=NET_ADMIN\nAddCapability=SYS_MODULE\nAddCapability=NET_RAW\nSysctl=net.ipv4.ip_forward=1\nSysctl=net.ipv4.conf.all.src_valid_mark=1\nSysctl=net.ipv6.conf.all.disable_ipv6=0\nSysctl=net.ipv6.conf.all.forwarding=1\nSysctl=net.ipv6.conf.default.forwarding=1\n\n[Install]\n# this is used to start the container on boot\nWantedBy=default.target\n
Create a file /etc/containers/systemd/wg-easy/wg-easy.network
with the following content:
[Network]\nNetworkName=wg-easy\nIPv6=true\n
"},{"location":"examples/tutorials/podman-nft/#load-kernel-modules","title":"Load Kernel Modules","text":"You will need to load the following kernel modules
wireguard\nnft_masq\n
Create a file /etc/modules-load.d/wg-easy.conf
with the following content:
wireguard\nnft_masq\n
"},{"location":"examples/tutorials/podman-nft/#start-the-container","title":"Start the Container","text":"sudo systemctl daemon-reload\nsudo systemctl start wg-easy\n
"},{"location":"examples/tutorials/podman-nft/#edit-hooks","title":"Edit Hooks","text":"In the Admin Panel of your WireGuard server, go to the Hooks
tab and add the following hook:
PostUp
nft add table inet wg_table; nft add chain inet wg_table prerouting { type nat hook prerouting priority 100 \\; }; nft add chain inet wg_table postrouting { type nat hook postrouting priority 100 \\; }; nft add rule inet wg_table postrouting ip saddr {{ipv4Cidr}} oifname {{device}} masquerade; nft add rule inet wg_table postrouting ip6 saddr {{ipv6Cidr}} oifname {{device}} masquerade; nft add chain inet wg_table input { type filter hook input priority 0 \\; policy accept \\; }; nft add rule inet wg_table input udp dport {{port}} accept; nft add rule inet wg_table input tcp dport {{uiPort}} accept; nft add chain inet wg_table forward { type filter hook forward priority 0 \\; policy accept \\; }; nft add rule inet wg_table forward iifname \"wg0\" accept; nft add rule inet wg_table forward oifname \"wg0\" accept;\n
PostDown
nft delete table inet wg_table\n
If you don't have iptables loaded on your server, you could see many errors in the logs or in the UI. You can ignore them.
"},{"location":"examples/tutorials/podman-nft/#restart-the-container","title":"Restart the Container","text":"Restart the container to apply the new hooks:
sudo systemctl restart wg-easy\n
"},{"location":"examples/tutorials/reverse-proxyless/","title":"No Reverse Proxy","text":"Insecure
This is insecure. You should use a reverse proxy to secure the connection.
Only use this method if you know what you are doing.
If you only allow access to the web UI from your local network, you can skip the reverse proxy setup. This is not recommended, but it is possible.
"},{"location":"examples/tutorials/reverse-proxyless/#setup","title":"Setup","text":"Edit the docker-compose.yml
file and uncomment environment
and INSECURE
Set INSECURE
to true
to allow access to the web UI over a non-secure connection.
The docker-compose.yml
file should look something like this:
environment:\n - INSECURE=true\n
Save the file and restart wg-easy
.
Make sure that the Web UI is not accessible from outside your local network.
Opinionated
This guide is opinionated. If you use other conventions or folder layouts, feel free to change the commands and paths.
"},{"location":"examples/tutorials/traefik/#create-docker-compose-project","title":"Create docker compose project","text":"sudo mkdir -p /etc/docker/containers/traefik\ncd /etc/docker/containers/traefik\n
"},{"location":"examples/tutorials/traefik/#create-docker-compose-file","title":"Create docker compose file","text":"File: /etc/docker/containers/traefik/docker-compose.yml
services:\n traefik:\n image: traefik:3.3\n container_name: traefik\n restart: unless-stopped\n ports:\n - '80:80'\n - '443:443/tcp'\n - '443:443/udp'\n volumes:\n - /var/run/docker.sock:/var/run/docker.sock\n - /etc/docker/volumes/traefik/traefik.yml:/traefik.yml:ro\n - /etc/docker/volumes/traefik/traefik_dynamic.yml:/traefik_dynamic.yml:ro\n - /etc/docker/volumes/traefik/acme.json:/acme.json\n networks:\n - traefik\n\nnetworks:\n traefik:\n external: true\n
"},{"location":"examples/tutorials/traefik/#create-traefikyml","title":"Create traefik.yml","text":"File: /etc/docker/volumes/traefik/traefik.yml
log:\n level: INFO\n\nentryPoints:\n web:\n address: ':80/tcp'\n http:\n redirections:\n entryPoint:\n to: websecure\n scheme: https\n websecure:\n address: ':443/tcp'\n http:\n middlewares:\n - compress@file\n - hsts@file\n tls:\n certResolver: letsencrypt\n http3: {}\n\napi:\n dashboard: true\n\ncertificatesResolvers:\n letsencrypt:\n acme:\n email: $mail@example.com$\n storage: acme.json\n httpChallenge:\n entryPoint: web\n\nproviders:\n docker:\n watch: true\n network: traefik\n exposedByDefault: false\n file:\n filename: traefik_dynamic.yml\n\nserversTransport:\n insecureSkipVerify: true\n
"},{"location":"examples/tutorials/traefik/#create-traefik_dynamicyml","title":"Create traefik_dynamic.yml","text":"File: /etc/docker/volumes/traefik/traefik_dynamic.yml
http:\n middlewares:\n services:\n basicAuth:\n users:\n - '$username$:$password$'\n compress:\n compress: {}\n hsts:\n headers:\n stsSeconds: 2592000\n routers:\n api:\n rule: Host(`traefik.$example.com$`)\n entrypoints:\n - websecure\n middlewares:\n - services\n service: api@internal\n\ntls:\n options:\n default:\n cipherSuites:\n - TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256\n - TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384\n - TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256\n sniStrict: true\n
"},{"location":"examples/tutorials/traefik/#create-acmejson","title":"Create acme.json","text":"sudo touch /etc/docker/volumes/traefik/acme.json\nsudo chmod 600 /etc/docker/volumes/traefik/acme.json\n
"},{"location":"examples/tutorials/traefik/#create-network","title":"Create network","text":"sudo docker network create traefik\n
"},{"location":"examples/tutorials/traefik/#start-traefik","title":"Start traefik","text":"sudo docker-compose up -d\n
You can no access the Traefik dashboard at https://traefik.$example.com$
with the credentials you set in traefik_dynamic.yml
.
wg-easy
","text":"To add labels to your wg-easy
service, you can add the following to your docker-compose.yml
file:
File: /etc/docker/containers/wg-easy/docker-compose.yml
services:\n wg-easy:\n ...\n container_name: wg-easy\n networks:\n ...\n traefik: {}\n labels:\n - \"traefik.enable=true\"\n - \"traefik.http.routers.wg-easy.rule=Host(`wg-easy.$example.com$`)\"\n - \"traefik.http.routers.wg-easy.entrypoints=websecure\"\n - \"traefik.http.routers.wg-easy.service=wg-easy\"\n - \"traefik.http.services.wg-easy.loadbalancer.server.port=51821\"\n ...\n\nnetworks:\n ...\n traefik:\n external: true\n
"},{"location":"examples/tutorials/traefik/#restart-wg-easy","title":"Restart wg-easy
","text":"cd /etc/docker/containers/wg-easy\nsudo docker-compose up -d\n
You can now access wg-easy
at https://wg-easy.$example.com$
and start the setup.
The user can enable 2FA from the Account page. The Account page is accessible from the dropdown menu in the top right corner of the application.
"},{"location":"guides/2fa/#enable-totp","title":"Enable TOTP","text":"A QR code will be displayed. Scan the QR code with your TOTP application (e.g., Google Authenticator, Authy, etc.) to add the account.
To verify that the TOTP key is working, the user must enter the TOTP code generated by the TOTP application.
To disable TOTP, the user must enter the current password.
TODO
"},{"location":"guides/cli/","title":"CLI","text":"If you want to use the CLI, you can run it with
"},{"location":"guides/cli/#docker-compose","title":"Docker Compose","text":"cd /etc/docker/containers/wg-easy\ndocker compose exec -it wg-easy cli\n
"},{"location":"guides/cli/#docker-run","title":"Docker Run","text":"docker run --rm -it \\\n -v ~/.wg-easy:/etc/wireguard \\\n ghcr.io/wg-easy/wg-easy:15 \\\n cli\n
"},{"location":"guides/cli/#reset-password","title":"Reset Password","text":"If you want to reset the password for the admin user, you can run the following command:
"},{"location":"guides/cli/#by-prompt","title":"By Prompt","text":"cd /etc/docker/containers/wg-easy\ndocker compose exec -it wg-easy cli db:admin:reset\n
You are asked to provide the new password
"},{"location":"guides/cli/#by-argument","title":"By Argument","text":"cd /etc/docker/containers/wg-easy\ndocker compose exec -it wg-easy cli db:admin:reset --password <new_password>\n
This will reset the password for the admin user to the new password you provided. If you include special characters in the password, make sure to escape them properly.
"},{"location":"guides/clients/","title":"Edit Client","text":""},{"location":"guides/clients/#general","title":"General","text":"Which IPs will be routed through the VPN.
This will not prevent the user from modifying it locally and accessing IP ranges that they should not be able to access.
Use firewall rules to prevent access to IP ranges that the user should not be able to access.
"},{"location":"guides/clients/#server-allowed-ips","title":"Server Allowed IPs","text":"Which IPs will be routed to the client.
"},{"location":"guides/clients/#dns","title":"DNS","text":"The DNS server that the client will use.
"},{"location":"guides/clients/#advanced","title":"Advanced","text":"This can only be used for clients that use wg-quick
. Setting this will throw a error when importing the config on other clients.
If you have the config from the previous version, you can import it by clicking \"Yes\". This currently expects a config from v14.
If this is the first time you are using this, you can click \"No\" to create a new config.
"},{"location":"guides/setup/#no-host-setup","title":"No - Host Setup","text":"[::1]
or [2001:db8::1]
.Select the wg0.json
file from the previous version. Read Migrate from v14 to v15 for more information.
wg-easy
","text":"\u00a0This Documentation is Versioned
Make sure to select the correct version of this documentation! It should match the version of the image you are using. The default version corresponds to the :latest
image tag - the most recent stable release.
This documentation provides you not only with the basic setup and configuration of wg-easy
but also with advanced configuration, elaborate usage scenarios, detailed examples, hints and more.
wg-easy
is the easiest way to run WireGuard VPN + Web-based Admin UI.
If you're new to wg-easy, make sure to read the Getting Started chapter first. If you want to look at examples for Docker Run and Compose, we have an Examples page.
"},{"location":"#contributing","title":"Contributing","text":"We are always happy to welcome new contributors. For guidelines and entrypoints please have a look at the Contributing section.
"},{"location":"#migration","title":"Migration","text":"If you are migrating from an older version of wg-easy
, please read the Migration chapter.
Here are some frequently asked questions or errors about wg-easy
. If you have a question that is not answered here, please feel free to open a discussion on GitHub.
This error indicates that the WireGuard interface wg0
does not exist. This can happen if the WireGuard kernel module is not loaded or if the interface was not created properly.
To resolve this issue, you can try the following steps:
Load the WireGuard kernel module: If the WireGuard kernel module is not loaded, you can load it manually by running:
sudo modprobe wireguard\n
Load the WireGuard kernel module on boot: If you want to ensure that the WireGuard kernel module is loaded automatically on boot, you can add it to the /etc/modules
file:
echo \"wireguard\" | sudo tee -a /etc/modules\n
This error indicates that the nat
table in iptables
does not exist. This can happen if the iptables
kernel module is not loaded or if the nat
table is not supported by your kernel.
To resolve this issue, you can try the following steps:
Load the nat
kernel module: If the nat
kernel module is not loaded, you can load it manually by running:
sudo modprobe iptable_nat\n
Load the nat
kernel module on boot: If you want to ensure that the nat
kernel module is loaded automatically on boot, you can add it to the /etc/modules
file:
echo \"iptable_nat\" | sudo tee -a /etc/modules\n
This error indicates that the nat
table in ip6tables
does not exist. This can happen if the ip6tables
kernel module is not loaded or if the nat
table is not supported by your kernel.
To resolve this issue, you can try the following steps:
Load the nat
kernel module: If the nat
kernel module is not loaded, you can load it manually by running:
sudo modprobe ip6table_nat\n
Load the nat
kernel module on boot: If you want to ensure that the nat
kernel module is loaded automatically on boot, you can add it to the /etc/modules
file:
echo \"ip6table_nat\" | sudo tee -a /etc/modules\n
This error indicates that the filter
table in iptables
cannot be initialized due to permission issues. This can happen if you are not running the command with sufficient privileges.
To resolve this issue, you can try the following steps:
Load the filter
kernel module: If the filter
kernel module is not loaded, you can load it manually by running:
sudo modprobe iptable_filter\n
Load the filter
kernel module on boot: If you want to ensure that the filter
kernel module is loaded automatically on boot, you can add it to the /etc/modules
file:
echo \"iptable_filter\" | sudo tee -a /etc/modules\n
This error indicates that the filter
table in ip6tables
cannot be initialized due to permission issues. This can happen if you are not running the command with sufficient privileges.
To resolve this issue, you can try the following steps:
Load the filter
kernel module: If the filter
kernel module is not loaded, you can load it manually by running:
sudo modprobe ip6table_filter\n
Load the filter
kernel module on boot: If you want to ensure that the filter
kernel module is loaded automatically on boot, you can add it to the /etc/modules
file:
echo \"ip6table_filter\" | sudo tee -a /etc/modules\n
This page explains how to get started with wg-easy
. The guide uses Docker Compose as a reference. In our examples, we mount the named volume etc_wireguard
to /etc/wireguard
inside the container.
Before you can get started with deploying your own VPN, there are some requirements to be met:
There are a few requirements for a suitable host system:
About the Container Runtime
On the host, you need to have a suitable container runtime (like Docker or Podman) installed. We assume Docker Compose is installed. We have aligned file names and configuration conventions with the latest Docker Compose specification. If you're using podman, make sure to read the related documentation.
"},{"location":"getting-started/#deploying-the-actual-image","title":"Deploying the Actual Image","text":""},{"location":"getting-started/#tagging-convention","title":"Tagging Convention","text":"To understand which tags you should use, read this section carefully. Our CI will automatically build, test and push new images to the following container registry:
ghcr.io/wg-easy/wg-easy
)All workflows are using the tagging convention listed below. It is subsequently applied to all images.
tag Type Example Description15
latest minor for that major tag ghcr.io/wg-easy/wg-easy:15
latest features for specific major versions, no breaking changes, recommended latest
latest tag ghcr.io/wg-easy/wg-easy:latest
or ghcr.io/wg-easy/wg-easy
points to latest release, can include breaking changes 15.0
latest patch for that minor tag ghcr.io/wg-easy/wg-easy:15.0
latest patches for specific minor version 15.0.0
specific tag ghcr.io/wg-easy/wg-easy:15.0.0
specific release, no updates edge
push to master
ghcr.io/wg-easy/wg-easy:edge
mostly unstable, gets frequent package and code updates development
pull requests ghcr.io/wg-easy/wg-easy:development
used for development, testing code from PRs When publishing a tag we follow the Semantic Versioning specification. The latest
tag is always pointing to the latest stable release. If you want to avoid breaking changes, use the major version tag (e.g. 15
).
Use the Correct Commands For Stopping and Starting wg-easy
Use sudo docker compose up / down
, not sudo docker compose start / stop
. Otherwise, the container is not properly destroyed and you may experience problems during startup because of inconsistent state.
That's it! It really is that easy.
"},{"location":"advanced/api/","title":"API","text":"Breaking Changes
This API is not yet stable and may change in the future. The API is currently in development and is subject to change without notice. The API is not yet documented, but we will add documentation as the API stabilizes.
You can use the API to interact with the application programmatically. The API is available at /api
and supports both GET and POST requests. The API is designed to be simple and easy to use, with a focus on providing a consistent interface for all endpoints.
There is no documentation for the API yet, but this will be added as the underlying library supports it.
"},{"location":"advanced/api/#authentication","title":"Authentication","text":"To use the API, you need to authenticate using Basic Authentication. The username and password are the same as the ones you use to log in to the web application. If you use 2FA, the API will not work. You need to disable 2FA in the web application to use the API.
"},{"location":"advanced/api/#authentication-example","title":"Authentication Example","text":"import requests\nfrom requests.auth import HTTPBasicAuth\n\nurl = \"https://example.com:51821/api/client\"\nresponse = requests.get(url, auth=HTTPBasicAuth('username', 'password'))\nif response.status_code == 200:\n data = response.json()\n print(data)\nelse:\n print(f\"Error: {response.status_code}\")\n
"},{"location":"advanced/api/#endpoints","title":"Endpoints","text":"The Endpoints are not yet documented. But as file-based routing is used, you can find the endpoints in the src/server/api
folder. The method is defined in the file name.
src/server/api/client.get.ts
/api/client
GET src/server/api/setup/2.post.ts
/api/setup/2
POST"},{"location":"advanced/config/optional-config/","title":"Optional Configuration","text":"You can set these environment variables to configure the container. They are not required, but can be useful in some cases.
Env Default Example DescriptionPORT
51821
6789
TCP port for Web UI. HOST
0.0.0.0
localhost
IP address web UI binds to. INSECURE
false
true
If access over http is allowed"},{"location":"advanced/config/unattended-setup/","title":"Unattended Setup","text":"If you want to run the setup without any user interaction, e.g. with a tool like Ansible, you can use these environment variables to configure the setup.
These will only be used during the first start of the container. After that, the setup will be disabled.
Env Example Description GroupINIT_ENABLED
true
Enables the below env vars 0 INIT_USERNAME
admin
Sets admin username 1 INIT_PASSWORD
Se!ureP%ssw
Sets admin password 1 INIT_HOST
vpn.example.com
Host clients will connect to 1 INIT_PORT
51820
Port clients will connect to and wireguard will listen on 1 INIT_DNS
1.1.1.1,8.8.8.8
Sets global dns setting 2 INIT_IPV4_CIDR
10.8.0.0/24
Sets IPv4 cidr 3 INIT_IPV6_CIDR
2001:0DB8::/32
Sets IPv6 cidr 3 \u00a0Variables have to be used together
If variables are in the same group, you have to set all of them. For example, if you set INIT_IPV4_CIDR
, you also have to set INIT_IPV6_CIDR
.
If you want to skip the setup process, you have to configure group 1
Security
The initial username and password is not checked for complexity. Make sure to set a long enough username and password. Otherwise, the user won't be able to log in.
It's recommended to remove the variables after the setup is done to prevent the password from being exposed.
"},{"location":"advanced/metrics/prometheus/","title":"Prometheus","text":"To monitor the WireGuard server, you can use Prometheus and Grafana. The container exposes a /metrics/prometheus
endpoint that can be scraped by Prometheus.
To enable Prometheus metrics, go to Admin Panel > General and enable Prometheus.
You can optionally set a Bearer Password for the metrics endpoints. This is useful if you want to expose the metrics endpoint to the internet.
"},{"location":"advanced/metrics/prometheus/#configure-prometheus","title":"Configure Prometheus","text":"You need to add a scrape config to your Prometheus configuration file. Here is an example:
scrape_configs:\n - job_name: 'wg-easy'\n scrape_interval: 30s\n metrics_path: /metrics/prometheus\n static_configs:\n - targets:\n - 'localhost:51821'\n authorization:\n type: Bearer\n credentials: 'SuperSecurePassword'\n
"},{"location":"advanced/metrics/prometheus/#grafana-dashboard","title":"Grafana Dashboard","text":"You can use the following Grafana dashboard to visualize the metrics:
21733
Unofficial
The Grafana dashboard is not official and is not maintained by the wg-easy
team. If you have any issues with the dashboard, please contact the author of the dashboard. See #1299 for more information.
If you want to migrate from an older version of wg-easy
to the new version, you can find the migration guides listed below.
v14
.This guide will help you migrate from v14
to version v15
of wg-easy
.
wg-easy
project, therefore the configuration files and the way you interact with the project have changed.v15
.INSECURE
environment variable to true
in the new container.Before you start the migration, make sure to back up your existing configuration files.
Go into the Web UI and click the Backup button, this should download a wg0.json
file.
Or download the wg0.json
file from your container volume to your pc.
You will need this file for the migration
You will also need to back up the old environment variables you set for the container, as they will not be automatically migrated.
"},{"location":"advanced/migrate/from-14-to-15/#remove-old-container","title":"Remove old container","text":"If you are using docker run
docker stop wg-easy\n
If you are using docker-compose
docker-compose down\n
"},{"location":"advanced/migrate/from-14-to-15/#start-new-container","title":"Start new container","text":"Follow the instructions in the Getting Started or Basic Installation guide to start the new container.
In the setup wizard, select that you already have a configuration file and upload the wg0.json
file you downloaded in the backup step.
v15 does not use the same environment variables as v14, most of them have been moved to the Admin Panel in the Web UI.
"},{"location":"advanced/migrate/from-14-to-15/#done","title":"Done","text":"You have now successfully migrated to v15
of wg-easy
.
When refactoring, writing or altering files, adhere to these rules:
pnpm lint
to check your scripts! Your contributions are checked by GitHub Actions too, so you will need to do this..vscode/settings.json
file.Make sure to select edge
in the dropdown menu at the top. Navigate to the page you would like to edit and click the edit button in the top right. This allows you to make changes and create a pull-request.
Alternatively you can make the changes locally. For that you'll need to have Docker installed. Run
pnpm docs:serve\n
This serves the documentation on your local machine on port 8080
. Each change will be hot-reloaded onto the page you view, just edit, save and look at the result.
This project is Open Source. That means that you can contribute on enhancements, bug fixing or improving the documentation.
"},{"location":"contributing/issues-and-pull-requests/#opening-an-issue","title":"Opening an Issue","text":"Attention
Before opening an issue, read the README
carefully, study the docs for your version (maybe latest) and your search engine you trust. The issue tracker is not meant to be used for unrelated questions!
When opening an issue, please provide details use case to let the community reproduce your problem.
Attention
Use the issue templates to provide the necessary information. Issues which do not use these templates are not worked on and closed.
By raising issues, I agree to these terms and I understand, that the rules set for the issue tracker will help both maintainers as well as everyone to find a solution.
Maintainers take the time to improve on this project and help by solving issues together. It is therefore expected from others to make an effort and comply with the rules.
"},{"location":"contributing/issues-and-pull-requests/#filing-a-bug-report","title":"Filing a Bug Report","text":"Thank you for participating in this project and reporting a bug. wg-easy
is a community-driven project, and each contribution counts!
Maintainers and moderators are volunteers. We greatly appreciate reports that take the time to provide detailed information via the template, enabling us to help you in the best and quickest way. Ignoring the template provided may seem easier, but discourages receiving any support.
Markdown formatting can be used in almost all text fields (unless stated otherwise in the description).
Be as precise as possible, and if in doubt, it's best to add more information that too few.
When an option is marked with \"not officially supported\" / \"unsupported\", then support is dependent on availability from specific maintainers.
"},{"location":"contributing/issues-and-pull-requests/#pull-requests","title":"Pull Requests","text":"Motivation
You want to add a feature? Feel free to start creating an issue explaining what you want to do and how you're thinking doing it. Other users may have the same need and collaboration may lead to better results.
"},{"location":"contributing/issues-and-pull-requests/#submit-a-pull-request","title":"Submit a Pull-Request","text":"The development workflow is the following:
master
. Please use the pull-request template to provide a minimum of contextual information and make sure to meet the requirements of the checklist.Pull requests are automatically tested against the CI and will be reviewed when tests pass. When your changes are validated, your branch is merged. CI builds the new :edge
image on every push to the master
branch and your changes will be included in the next version release.
It seems like the Docs on how to setup AdGuard Home are not available yet.
Feel free to create a PR and add them here.
"},{"location":"examples/tutorials/auto-updates/","title":"Auto Updates","text":""},{"location":"examples/tutorials/auto-updates/#docker-compose","title":"Docker Compose","text":"With Docker Compose wg-easy
can be updated with a single command:
cd /etc/docker/containers/wg-easy\nsudo docker compose up -d --pull always\n
"},{"location":"examples/tutorials/auto-updates/#watchtower","title":"Watchtower","text":"If you want the updates to be fully automatic you can install Watchtower. This will check for updates every day at 4:00 AM and update the container if a new version is available.
File: /etc/docker/containers/watchtower/docker-compose.yml
services:\n watchtower:\n image: containrrr/watchtower:latest\n volumes:\n - /var/run/docker.sock:/var/run/docker.sock\n env_file:\n - watchtower.env\n restart: unless-stopped\n
File: /etc/docker/containers/watchtower/watchtower.env
WATCHTOWER_CLEANUP=true\nWATCHTOWER_SCHEDULE=0 0 4 * * *\nTZ=Europe/Berlin\n\n# Email\n# WATCHTOWER_NOTIFICATIONS_LEVEL=info\n# WATCHTOWER_NOTIFICATIONS=email\n# WATCHTOWER_NOTIFICATION_EMAIL_FROM=mail@example.com\n# WATCHTOWER_NOTIFICATION_EMAIL_TO=mail@example.com\n# WATCHTOWER_NOTIFICATION_EMAIL_SERVER=smtp.example.com\n# WATCHTOWER_NOTIFICATION_EMAIL_SERVER_USER=mail@example.com\n# WATCHTOWER_NOTIFICATION_EMAIL_SERVER_PASSWORD=\"SuperSecurePassword\"\n# WATCHTOWER_NOTIFICATION_EMAIL_SERVER_PORT=587\n
cd /etc/docker/containers/watchtower\nsudo docker compose up -d\n
"},{"location":"examples/tutorials/auto-updates/#docker-run","title":"Docker Run","text":"sudo docker stop wg-easy\nsudo docker rm wg-easy\nsudo docker pull ghcr.io/wg-easy/wg-easy\n
And then run the docker run -d \\ ...
command from Docker Run again.
To update wg-easy
(and every container that has auto updates enabled), you can run the following command:
sudo podman auto-update\n
"},{"location":"examples/tutorials/basic-installation/","title":"Basic Installation","text":""},{"location":"examples/tutorials/basic-installation/#requirements","title":"Requirements","text":"Follow the Docs here: https://docs.docker.com/engine/install/ and install Docker on your host.
"},{"location":"examples/tutorials/basic-installation/#install-wg-easy","title":"Installwg-easy
","text":"Create a directory for the configuration files (you can choose any directory you like):
sudo mkdir -p /etc/docker/containers/wg-easy\n
Download docker compose file
sudo curl -o /etc/docker/containers/wg-easy/docker-compose.yml https://raw.githubusercontent.com/wg-easy/wg-easy/master/docker-compose.yml\n
Start wg-easy
cd /etc/docker/containers/wg-easy\n sudo docker-compose up -d\n
If you are using a firewall, you need to open the following ports:
These ports can be changed, so if you change them you have to update your firewall rules accordingly.
"},{"location":"examples/tutorials/basic-installation/#setup-reverse-proxy","title":"Setup Reverse Proxy","text":"wg-easy
","text":"To update wg-easy
to the latest version, run:
cd /etc/docker/containers/wg-easy\nsudo docker-compose pull\nsudo docker-compose up -d\n
"},{"location":"examples/tutorials/basic-installation/#auto-update","title":"Auto Update","text":"If you want to enable auto-updates, follow the instructions here: Auto Updates
"},{"location":"examples/tutorials/caddy/","title":"Caddy","text":"Opinionated
This guide is opinionated. If you use other conventions or folder layouts, feel free to change the commands and paths.
We're using Caddy here as reserve proxy to serve wg-easy
on https://wg-easy.example.com via TLS.
caddy
","text":".\n\u251c\u2500\u2500 compose.yml\n\u2514\u2500\u2500 Caddyfile\n\n1 directory, 2 files\n
# compose.yml\n\nservices:\n caddy:\n container_name: caddy\n image: caddy:2.10.0-alpine\n # publish everything you deem necessary\n ports:\n - '80:80/tcp'\n - '443:443/tcp'\n - '443:443/udp'\n networks:\n - caddy\n restart: unless-stopped\n volumes:\n - './Caddyfile:/etc/caddy/Caddyfile:ro'\n - config:/config\n - data:/data\n\nnetworks:\n caddy:\n name: caddy\n\nvolumes:\n config:\n data:\n
# Caddyfile\n\n{\n # setup your email address\n email mail@example.com\n}\n\nwg-easy.example.com {\n # since the container will share the network with wg-easy\n # we can use the proper container name\n reverse_proxy wg-easy:80\n tls internal\n}\n
...and start it with:
sudo docker-compose up -d\n
"},{"location":"examples/tutorials/caddy/#adapt-the-docker-composition-of-wg-easy","title":"Adapt the docker composition of wg-easy
","text":"services:\n wg-easy:\n # sync container name and port according to Caddyfile\n container_name: wg-easy\n environment:\n - PORT=80\n # no need to publish the HTTP server anymore\n ports:\n - \"51820:51820/udp\"\n # add to caddy network\n networks:\n caddy:\n ...\n\nnetworks:\n caddy:\n external: true\n ...\n
...and restart it with:
sudo docker-compose up -d\n
You can now access wg-easy
at https://wg-easy.example.com and start the setup.
To setup the IPv6 Network, simply run once:
docker network create \\\n -d bridge --ipv6 \\\n -d default \\\n --subnet 10.42.42.0/24 \\\n --subnet fdcc:ad94:bacf:61a3::/64 wg \\\n
To automatically install & run wg-easy
, simply run:
docker run -d \\\n --net wg \\\n -e INSECURE=true \\\n --name wg-easy \\\n --ip6 fdcc:ad94:bacf:61a3::2a \\\n --ip 10.42.42.42 \\\n -v ~/.wg-easy:/etc/wireguard \\\n -v /lib/modules:/lib/modules:ro \\\n -p 51820:51820/udp \\\n -p 51821:51821/tcp \\\n --cap-add NET_ADMIN \\\n --cap-add SYS_MODULE \\\n --sysctl net.ipv4.ip_forward=1 \\\n --sysctl net.ipv4.conf.all.src_valid_mark=1 \\\n --sysctl net.ipv6.conf.all.disable_ipv6=0 \\\n --sysctl net.ipv6.conf.all.forwarding=1 \\\n --sysctl net.ipv6.conf.default.forwarding=1 \\\n --restart unless-stopped \\\n ghcr.io/wg-easy/wg-easy:15\n
The Web UI will now be available at http://0.0.0.0:51821.
"},{"location":"examples/tutorials/dockerless/","title":"Without Docker","text":"This is currently not yet supported.
"},{"location":"examples/tutorials/podman-nft/","title":"Podman + nftables","text":"This guide will show you how to run wg-easy
with rootful Podman and nftables.
Create a Folder for the configuration files:
sudo mkdir -p /etc/containers/systemd/wg-easy\nsudo mkdir -p /etc/containers/volumes/wg-easy\n
Create a file /etc/containers/systemd/wg-easy/wg-easy.container
with the following content:
[Container]\nContainerName=wg-easy\nImage=ghcr.io/wg-easy/wg-easy:15\nAutoUpdate=registry\n\nVolume=/etc/containers/volumes/wg-easy:/etc/wireguard:Z\nNetwork=wg-easy.network\nPublishPort=51820:51820/udp\nPublishPort=51821:51821/tcp\n\n# this is used to allow access over HTTP\n# remove this when using a reverse proxy\nEnvironment=INSECURE=true\n\nAddCapability=NET_ADMIN\nAddCapability=SYS_MODULE\nAddCapability=NET_RAW\nSysctl=net.ipv4.ip_forward=1\nSysctl=net.ipv4.conf.all.src_valid_mark=1\nSysctl=net.ipv6.conf.all.disable_ipv6=0\nSysctl=net.ipv6.conf.all.forwarding=1\nSysctl=net.ipv6.conf.default.forwarding=1\n\n[Install]\n# this is used to start the container on boot\nWantedBy=default.target\n
Create a file /etc/containers/systemd/wg-easy/wg-easy.network
with the following content:
[Network]\nNetworkName=wg-easy\nIPv6=true\n
"},{"location":"examples/tutorials/podman-nft/#load-kernel-modules","title":"Load Kernel Modules","text":"You will need to load the following kernel modules
wireguard\nnft_masq\n
Create a file /etc/modules-load.d/wg-easy.conf
with the following content:
wireguard\nnft_masq\n
"},{"location":"examples/tutorials/podman-nft/#start-the-container","title":"Start the Container","text":"sudo systemctl daemon-reload\nsudo systemctl start wg-easy\n
"},{"location":"examples/tutorials/podman-nft/#edit-hooks","title":"Edit Hooks","text":"In the Admin Panel of your WireGuard server, go to the Hooks
tab and add the following hook:
PostUp
nft add table inet wg_table; nft add chain inet wg_table prerouting { type nat hook prerouting priority 100 \\; }; nft add chain inet wg_table postrouting { type nat hook postrouting priority 100 \\; }; nft add rule inet wg_table postrouting ip saddr {{ipv4Cidr}} oifname {{device}} masquerade; nft add rule inet wg_table postrouting ip6 saddr {{ipv6Cidr}} oifname {{device}} masquerade; nft add chain inet wg_table input { type filter hook input priority 0 \\; policy accept \\; }; nft add rule inet wg_table input udp dport {{port}} accept; nft add rule inet wg_table input tcp dport {{uiPort}} accept; nft add chain inet wg_table forward { type filter hook forward priority 0 \\; policy accept \\; }; nft add rule inet wg_table forward iifname \"wg0\" accept; nft add rule inet wg_table forward oifname \"wg0\" accept;\n
PostDown
nft delete table inet wg_table\n
If you don't have iptables loaded on your server, you could see many errors in the logs or in the UI. You can ignore them.
"},{"location":"examples/tutorials/podman-nft/#restart-the-container","title":"Restart the Container","text":"Restart the container to apply the new hooks:
sudo systemctl restart wg-easy\n
"},{"location":"examples/tutorials/reverse-proxyless/","title":"No Reverse Proxy","text":"Insecure
This is insecure. You should use a reverse proxy to secure the connection.
Only use this method if you know what you are doing.
If you only allow access to the web UI from your local network, you can skip the reverse proxy setup. This is not recommended, but it is possible.
"},{"location":"examples/tutorials/reverse-proxyless/#setup","title":"Setup","text":"Edit the docker-compose.yml
file and uncomment environment
and INSECURE
Set INSECURE
to true
to allow access to the web UI over a non-secure connection.
The docker-compose.yml
file should look something like this:
environment:\n - INSECURE=true\n
Save the file and restart wg-easy
.
Make sure that the Web UI is not accessible from outside your local network.
Opinionated
This guide is opinionated. If you use other conventions or folder layouts, feel free to change the commands and paths.
"},{"location":"examples/tutorials/traefik/#create-docker-compose-project","title":"Create docker compose project","text":"sudo mkdir -p /etc/docker/containers/traefik\ncd /etc/docker/containers/traefik\n
"},{"location":"examples/tutorials/traefik/#create-docker-compose-file","title":"Create docker compose file","text":"File: /etc/docker/containers/traefik/docker-compose.yml
services:\n traefik:\n image: traefik:3.3\n container_name: traefik\n restart: unless-stopped\n ports:\n - '80:80'\n - '443:443/tcp'\n - '443:443/udp'\n volumes:\n - /var/run/docker.sock:/var/run/docker.sock\n - /etc/docker/volumes/traefik/traefik.yml:/traefik.yml:ro\n - /etc/docker/volumes/traefik/traefik_dynamic.yml:/traefik_dynamic.yml:ro\n - /etc/docker/volumes/traefik/acme.json:/acme.json\n networks:\n - traefik\n\nnetworks:\n traefik:\n external: true\n
"},{"location":"examples/tutorials/traefik/#create-traefikyml","title":"Create traefik.yml","text":"File: /etc/docker/volumes/traefik/traefik.yml
log:\n level: INFO\n\nentryPoints:\n web:\n address: ':80/tcp'\n http:\n redirections:\n entryPoint:\n to: websecure\n scheme: https\n websecure:\n address: ':443/tcp'\n http:\n middlewares:\n - compress@file\n - hsts@file\n tls:\n certResolver: letsencrypt\n http3: {}\n\napi:\n dashboard: true\n\ncertificatesResolvers:\n letsencrypt:\n acme:\n email: $mail@example.com$\n storage: acme.json\n httpChallenge:\n entryPoint: web\n\nproviders:\n docker:\n watch: true\n network: traefik\n exposedByDefault: false\n file:\n filename: traefik_dynamic.yml\n\nserversTransport:\n insecureSkipVerify: true\n
"},{"location":"examples/tutorials/traefik/#create-traefik_dynamicyml","title":"Create traefik_dynamic.yml","text":"File: /etc/docker/volumes/traefik/traefik_dynamic.yml
http:\n middlewares:\n services:\n basicAuth:\n users:\n - '$username$:$password$'\n compress:\n compress: {}\n hsts:\n headers:\n stsSeconds: 2592000\n routers:\n api:\n rule: Host(`traefik.$example.com$`)\n entrypoints:\n - websecure\n middlewares:\n - services\n service: api@internal\n\ntls:\n options:\n default:\n cipherSuites:\n - TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256\n - TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384\n - TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256\n sniStrict: true\n
"},{"location":"examples/tutorials/traefik/#create-acmejson","title":"Create acme.json","text":"sudo touch /etc/docker/volumes/traefik/acme.json\nsudo chmod 600 /etc/docker/volumes/traefik/acme.json\n
"},{"location":"examples/tutorials/traefik/#create-network","title":"Create network","text":"sudo docker network create traefik\n
"},{"location":"examples/tutorials/traefik/#start-traefik","title":"Start traefik","text":"sudo docker-compose up -d\n
You can no access the Traefik dashboard at https://traefik.$example.com$
with the credentials you set in traefik_dynamic.yml
.
wg-easy
","text":"To add labels to your wg-easy
service, you can add the following to your docker-compose.yml
file:
File: /etc/docker/containers/wg-easy/docker-compose.yml
services:\n wg-easy:\n ...\n container_name: wg-easy\n networks:\n ...\n traefik: {}\n labels:\n - \"traefik.enable=true\"\n - \"traefik.http.routers.wg-easy.rule=Host(`wg-easy.$example.com$`)\"\n - \"traefik.http.routers.wg-easy.entrypoints=websecure\"\n - \"traefik.http.routers.wg-easy.service=wg-easy\"\n - \"traefik.http.services.wg-easy.loadbalancer.server.port=51821\"\n ...\n\nnetworks:\n ...\n traefik:\n external: true\n
"},{"location":"examples/tutorials/traefik/#restart-wg-easy","title":"Restart wg-easy
","text":"cd /etc/docker/containers/wg-easy\nsudo docker-compose up -d\n
You can now access wg-easy
at https://wg-easy.$example.com$
and start the setup.
The user can enable 2FA from the Account page. The Account page is accessible from the dropdown menu in the top right corner of the application.
"},{"location":"guides/2fa/#enable-totp","title":"Enable TOTP","text":"A QR code will be displayed. Scan the QR code with your TOTP application (e.g., Google Authenticator, Authy, etc.) to add the account.
To verify that the TOTP key is working, the user must enter the TOTP code generated by the TOTP application.
To disable TOTP, the user must enter the current password.
TODO
"},{"location":"guides/cli/","title":"CLI","text":"If you want to use the CLI, you can run it with
"},{"location":"guides/cli/#docker-compose","title":"Docker Compose","text":"cd /etc/docker/containers/wg-easy\ndocker compose exec -it wg-easy cli\n
"},{"location":"guides/cli/#docker-run","title":"Docker Run","text":"docker run --rm -it \\\n -v ~/.wg-easy:/etc/wireguard \\\n ghcr.io/wg-easy/wg-easy:15 \\\n cli\n
"},{"location":"guides/cli/#reset-password","title":"Reset Password","text":"If you want to reset the password for the admin user, you can run the following command:
"},{"location":"guides/cli/#by-prompt","title":"By Prompt","text":"cd /etc/docker/containers/wg-easy\ndocker compose exec -it wg-easy cli db:admin:reset\n
You are asked to provide the new password
"},{"location":"guides/cli/#by-argument","title":"By Argument","text":"cd /etc/docker/containers/wg-easy\ndocker compose exec -it wg-easy cli db:admin:reset --password <new_password>\n
This will reset the password for the admin user to the new password you provided. If you include special characters in the password, make sure to escape them properly.
"},{"location":"guides/clients/","title":"Edit Client","text":""},{"location":"guides/clients/#general","title":"General","text":"Which IPs will be routed through the VPN.
This will not prevent the user from modifying it locally and accessing IP ranges that they should not be able to access.
Use firewall rules to prevent access to IP ranges that the user should not be able to access.
"},{"location":"guides/clients/#server-allowed-ips","title":"Server Allowed IPs","text":"Which IPs will be routed to the client.
"},{"location":"guides/clients/#dns","title":"DNS","text":"The DNS server that the client will use.
"},{"location":"guides/clients/#advanced","title":"Advanced","text":"This can only be used for clients that use wg-quick
. Setting this will throw a error when importing the config on other clients.
If you have the config from the previous version, you can import it by clicking \"Yes\". This currently expects a config from v14.
If this is the first time you are using this, you can click \"No\" to create a new config.
"},{"location":"guides/setup/#no-host-setup","title":"No - Host Setup","text":"[::1]
or [2001:db8::1]
.Select the wg0.json
file from the previous version. Read Migrate from v14 to v15 for more information.