How to set up your personal WireGuard VPN server | INTROSERV
EUR
european

EUR

usa

USD

English En
Ex. VAT Ex. VAT 0%

How to set up a WireGuard VPN server with wg-easy

wg-easy is a Docker application that runs a WireGuard VPN server together with a web panel. In the panel you create clients, download their configuration files or scan a QR code with a phone, and see which clients are connected. This guide shows how to install the current version, wg-easy v15, on a Linux server with Docker Compose and connect the first device.

Info

wg-easy v15 differs from older versions. The admin password is no longer passed in the PASSWORD variable: a container started with PASSWORD or PASSWORD_HASH does not start. The login and password are now set in the browser on first launch.

Requirements

A VPS with a public IP address and root or sudo access is enough. wg-easy is lightweight: 1 vCPU and 1 GB of RAM are sufficient for a personal VPN. The commands in this guide were checked on Ubuntu 24.04 LTS. Because wg-easy runs in Docker, they work the same way on Ubuntu 22.04, Debian 12, AlmaLinux 9 and Rocky Linux 9.

Tip

If you do not want to install anything manually, order a VPS with wg-easy already deployed from the INTROSERV App marketplace and go straight to the first launch.

Install Docker

Connect to the server via SSH and install Docker Engine with the Compose plugin using the official script:

curl -fsSL https://get.docker.com | sudo sh

Check that Docker and Compose are installed:

sudo docker --version sudo docker compose version

Download the docker-compose.yml file

wg-easy is installed with the official docker-compose.yml from the project repository. Create a folder for it and download the file:

sudo mkdir -p /etc/docker/containers/wg-easy sudo curl -o /etc/docker/containers/wg-easy/docker-compose.yml https://raw.githubusercontent.com/wg-easy/wg-easy/master/docker-compose.yml

The main lines of the file are the image and the ports:

image: ghcr.io/wg-easy/wg-easy:15 ports: - "51820:51820/udp" - "51821:51821/tcp"

Port 51820/udp is used by WireGuard itself, and port 51821/tcp by the web panel. The tag 15 means that updates stay within version 15. The configuration and clients are stored in a Docker volume, so they are kept when the container is recreated.

Start wg-easy

Go to the folder with the file and start the container:

cd /etc/docker/containers/wg-easy sudo docker compose up -d

Check that the container is running:

sudo docker compose ps

The STATUS column should show Up, and the PORTS column should show ports 51820/udp and 51821/tcp.

Open the port in the firewall

Clients connect to the server over UDP port 51820. If UFW is enabled on the server, allow this port:

sudo ufw allow 51820/udp

On AlmaLinux and Rocky Linux with firewalld, use:

sudo firewall-cmd --permanent --add-port=51820/udp sudo firewall-cmd --reload

Open the web panel

wg-easy v15 does not allow logging in to the panel over plain HTTP. The simplest safe way is to open the panel through an SSH tunnel. On your computer, run:

ssh -L 51821:localhost:51821 USER@SERVER_IP

Keep this SSH session open and go to http://localhost:51821 in your browser.

Warning

You can also allow access over plain HTTP: in docker-compose.yml uncomment the environment block, set INSECURE=true and run sudo docker compose up -d again. In this case the panel password is sent without encryption, so use this option only for testing. For permanent access by domain name, put the panel behind a reverse proxy with HTTPS.

Complete the first launch

On first launch, wg-easy opens a setup wizard. After the welcome screen, create an administrator account: enter a username and password, then confirm the password.

When the wizard asks whether you have an existing setup, choose No. This creates a new configuration.

On the next screen, specify the Host and Port that clients will use to connect. In Host, enter the public IP address or domain name of the server, not localhost, even if you opened the panel through the SSH tunnel. Leave Port as 51820. The Suggest button fills in the address that wg-easy detects automatically.

Warning

The address from Host goes into the configuration of every client. If you enter a wrong address, the clients will not be able to connect.

After the wizard finishes, log in with the username and password you created.

Create a client

On the main page of the panel, click New Client, enter a name for the device, for example laptop or phone, and confirm. The client appears in the list. Next to it there are buttons for showing the QR code and downloading the configuration file.

Create a separate client for each device. Then you can disable or delete access for one device without affecting the others.

Connect a device

Install the official WireGuard app on your device. It is available for Windows, macOS, Android and iOS on the official WireGuard download page.

On a phone, open the WireGuard app, choose to add a tunnel by QR code and scan the code from the panel.

On a computer, download the client configuration file in the panel and import it in the WireGuard app with Import tunnel(s) from file. Then click Activate.

On Linux, install wireguard-tools and openresolv. Without openresolv, the wg-quick command fails on the DNS line of the configuration file. On Ubuntu and Debian:

sudo apt install wireguard-tools openresolv sudo wg-quick up ./CLIENT_NAME.conf

To disconnect on Linux, run sudo wg-quick down ./CLIENT_NAME.conf.

Check the connection

When the tunnel is active, check which IP address the internet sees:

curl -4 ifconfig.me

The command should return the IP address of your server. You can also open any IP check website in the browser. In the wg-easy panel, the connected client shows recent activity and traffic.

Manage clients

All clients are managed on the main page of the panel. Each client can be temporarily disabled with the switch next to it: the device stays in the list but cannot connect until you enable it again. To remove access completely, delete the client. Its configuration file and QR code stop working immediately. If a device is lost or a configuration file might have been copied, delete that client and create a new one.

If something does not work

If the panel does not open, check that the container is running with sudo docker compose ps and look at the log:

sudo docker logs wg-easy

If the panel opens but you cannot log in and see a message about an insecure connection, you opened it over plain HTTP. Use the SSH tunnel from the section above.

If the client cannot connect, check that UDP port 51820 is open in the server firewall and in the firewall of your provider panel, if there is one. Also open the client configuration file and check the Endpoint line: it must contain the public address of the server. If it contains a wrong address, the Host was entered incorrectly in the setup wizard.

If the tunnel is active but there is no internet on the device, check the server log with sudo docker logs wg-easy and make sure that the container was started from the official docker-compose.yml without changes in the sysctls section.

On Linux, if wg-quick fails with an error about resolvconf, install openresolv as described in the section about connecting a device.

Update wg-easy

To install a newer build of version 15, download the new image and recreate the container:

cd /etc/docker/containers/wg-easy sudo docker compose pull sudo docker compose up -d

Clients and settings are kept, because they are stored in the Docker volume.

Stop and remove wg-easy

To stop the VPN server, run in the folder with docker-compose.yml:

sudo docker compose down

The configuration remains in the volume, and sudo docker compose up -d starts the server again with the same clients.

To remove wg-easy completely, together with all clients and keys, add the -v option:

sudo docker compose down -v

Warning

After sudo docker compose down -v, all client configurations stop working. To use the VPN again, you will need to complete the first launch and create the clients again.

VAT

  • Other

    Ex. VAT

    0%
  • austria

    Austria

    20%
  • Belgium

    Belgium

    21%
  • Bulgaria

    Bulgaria

    20%
  • Croatia

    Croatia

    25%
  • Cyprus

    Cyprus

    19%
  • Czech Republic

    Czech Republic

    21%
  • Denmark

    Denmark

    25%
  • Estonia

    Estonia

    22%
  • France

    France

    20%
  • Finland

    Finland

    24%
  • Germany

    Germany

    19%
  • Greece

    Greece

    24%
  • Hungary

    Hungary

    27%
  • Ireland

    Ireland

    23%
  • Italy

    Italy

    22%
  • Latvia

    Latvia

    21%
  • Lithuania

    Lithuania

    21%
  • Luxembourg

    Luxembourg

    17%
  • Malta

    Malta

    18%
  • Netherlands

    Netherlands

    21%
  • Poland

    Poland

    23%
  • Portugal

    Portugal

    23%
  • Romania

    Romania

    19%
  • Slovakia

    Slovakia

    20%
  • Slovenia

    Slovenia

    22%
  • Spain

    Spain

    21%
  • Sweden

    Sweden

    25%
  • USA

    USA

    0%
european
states
  • germany
  • Español
  • Italiano
  • Poland
  • Русский
  • Slovenski
  • Türkçe
  • ukraine
  • kingdom
  • French
  • Hrvatska
  • Other
  • Austria
  • Belgium
  • Bulgaria
  • Croatia
  • Cyprus
  • Czech Republic
  • Denmark
  • Estonia
  • Finland
  • France
  • Germany
  • Greece
  • Hungary
  • Ireland
  • Italy
  • Latvia
  • Lithuania
  • Luxembourg
  • Malta
  • Netherlands
  • Poland
  • Portugal
  • Romania
  • Slovakia
  • Slovenia
  • Spain
  • Sweden
  • USA