How to Set Up WireGuard Easy on Docker

by

Faveren Caleb

How to install Wireguard easy on Docker

WireGuard Easy on Docker is a containerised WireGuard VPN server with a built-in web interface for managing clients covered in the homelab hub post. This post covers only the installation.

Prerequisites

You need Docker installed, and your user added to the Docker group. Verify both:

docker info
docker ps

You also need a static LAN IP on your Docker host set via a DHCP reservation in your router, a public IP or Dynamic DNS hostname pointing to your home network (use a free DDNS service like DuckDNS if your public IP changes), and UDP port 51820 forwarded on your router to your Docker host without this, remote clients cannot reach the VPN server.

Check whether port 51820 is already in use:

sudo lsof -i udp:51820

Generate a Password Hash

WireGuard Easy requires a hashed password rather than plaintext. Generate one before running the container:

docker run --rm -it ghcr.io/wg-easy/wg-easy wgpw 'your-secure-password'

The output will look like:

PASSWORD_HASH='$2a$12$abc123...'

Copy the full hash value. In Docker Compose, you can paste it as-is. In a docker run command, escape every $ by doubling it ($$).

Method 1: docker run

docker run -d \
  --name wg-easy \
  -e LANG=en \
  -e WG_HOST=vpn.yourdomain.com \
  -e PASSWORD_HASH='$$2a$$12$$abc123...' \
  -e PORT=51821 \
  -e WG_PORT=51820 \
  -v ~/.wg-easy:/etc/wireguard \
  -p 51820:51820/udp \
  -p 51821:51821/tcp \
  --cap-add=NET_ADMIN \
  --cap-add=SYS_MODULE \
  --sysctl="net.ipv4.ip_forward=1" \
  --sysctl="net.ipv4.conf.all.src_valid_mark=1" \
  --restart unless-stopped \
  ghcr.io/wg-easy/wg-easy

Replace WG_HOST with your public IP or DDNS hostname and PASSWORD_HASH with your generated hash. WG_HOST is the address remote clients use to reach your VPN server. Port 51820/udp is the WireGuard VPN port; UDP is required. Port 51821/tcp exposes the web UI. NET_ADMIN and SYS_MODULE Capabilities are required for network configuration and kernel module loading. The sysctl flag net.ipv4.ip_forward=1 enables traffic forwarding for VPN clients. The volume mount at ~/.wg-easy:/etc/wireguard the client configs and server keys across container updates.

Verify it’s running:

docker ps | grep wg-easy
docker logs wg-easy

Method 2: Docker Compose

Create a project directory:

mkdir -p ~/wireguard && cd ~/wireguard

Create docker-compose.yml:

services:
  wg-easy:
    image: ghcr.io/wg-easy/wg-easy:latest
    container_name: wg-easy
    environment:
      - LANG=en
      - WG_HOST=vpn.yourdomain.com
      - PASSWORD_HASH=$2a$12$abc123...
      - PORT=51821
      - WG_PORT=51820
      - WG_DEFAULT_DNS=1.1.1.1
      - WG_PERSISTENT_KEEPALIVE=25
    volumes:
      - ./wg-data:/etc/wireguard
    ports:
      - "51820:51820/udp"
      - "51821:51821/tcp"
    cap_add:
      - NET_ADMIN
      - SYS_MODULE
    sysctls:
      - net.ipv4.ip_forward=1
      - net.ipv4.conf.all.src_valid_mark=1
    restart: unless-stopped

Replace WG_HOST and PASSWORD_HASH With your values in Compose, $ characters do not need escaping. WG_DEFAULT_DNS sets the DNS server pushed to clients; point this at your Pi-hole IP if you want remote ad-blocking. WG_PERSISTENT_KEEPALIVE sends a keepalive packet every 25 seconds to maintain connections through NAT.

Start it:

docker compose up -d

Verify:

docker compose ps
docker compose logs

Open the Firewall

Allow UDP port 51820 through your server’s firewall:

# UFW
sudo ufw allow 51820/udp
sudo ufw reload

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

Initial Setup

Open a browser and navigate to http://<YOUR_SERVER_IP>:51821. Log in with the password you used to generate the hash, not the hash itself. You’ll land on the WireGuard Easy dashboard showing an empty client list with a + New Client button.

Click + New Client, give the device a name, and click Create. The client appears in the list with a QR code icon for mobile devices and a download icon for desktop config files. Install the WireGuard app on your device, scan the QR code or import the config file, and toggle the tunnel on.

Troubleshooting

If the web UI is unreachable, check that the container is running with docker ps and that your server firewall allows TCP port 51821. If clients connect but have no internet access, IP forwarding is likely disabled. Verify with sysctl net.ipv4.ip_forward and confirm it returns 1. If clients can’t connect at all, UDP port 51820 is not reaching the container. Recheck your router’s port forwarding rule and confirm the protocol is set to UDP, not TCP. If the password is rejected, regenerate the hash and confirm you’re entering the original password, not the hash string.

The Takeaway

WireGuard Easy on Docker is now running on your Docker host with the VPN port exposed and the web UI available on your local network. Client configs and server keys are stored in the mounted volume, so the container is fully replaceable without losing your setup.

Leave a Comment