The wg-easy project provides a web interface for managing WireGuard VPN servers. Version 15 introduces a first-boot setup wizard while maintaining kernel-level packet routing controls. This guide covers deployment using Docker Compose with explicit IPv4-only configuration to avoid boot loops and routing errors on servers without IPv6 support.
Prerequisites
The following items are required:
- Linux server with Docker Engine and Docker Compose installed
- Kernel module support for WireGuard
- Port 51820/udp open in firewall
- Root or sudo access to create directories and manage containers
Configuration Parameters
The wg-easy v15 container requires specific environment variables, Linux capabilities, and kernel parameters to function correctly in an IPv4 environment.
Environment Variables
The INSECURE variable controls HTTPS cookie security for the web interface. Set to true when accessing the UI directly over HTTP during initial setup. Set to false when the container sits behind an SSL reverse proxy like Nginx Proxy Manager.
Linux Capabilities
Two capabilities must be granted to the container:
- NET_ADMIN allows the container to manage network interfaces, configure iptables rules, and modify host routing tables
- SYS_MODULE allows the container to load and manage WireGuard kernel modules
Kernel Parameters
Two sysctl settings are required for proper packet routing:
- net.ipv4.ip_forward=1 enables IPv4 packet forwarding so traffic can route between WireGuard clients and external networks
- net.ipv4.conf.all.src_valid_mark=1 is required by WireGuard policy routing to track interface packet marks
Create Environment File
Create a deployment directory and environment file to isolate configuration from the Compose definition:
mkdir -p /opt/containers/wg-easy
cd /opt/containers/wg-easyCreate a .env file with the following content:
# Storage Configuration
ROOT=/opt/containers
# Web UI Access
UI_PORT=51821
# Internal Network Addressing (IPv4 Only)
STATIC_IPV4=10.0.0.42Create Docker Compose Configuration
Create a docker-compose.yml file in the same directory. This configuration explicitly removes all IPv6 sysctls, subnets, and address assignments:
version: "3.8"
networks:
cloudflare:
external: true
wg:
driver: bridge
ipam:
config:
- subnet: 10.0.0.0/24
services:
wg-easy:
image: ghcr.io/wg-easy/wg-easy:15
container_name: wg-easy
environment:
- INSECURE=true
networks:
cloudflare: {}
wg:
ipv4_address: ${STATIC_IPV4}
volumes:
- ${ROOT}/wg-easy/config:/etc/wireguard
- /lib/modules:/lib/modules:ro
ports:
- "51820:51820/udp"
- "${UI_PORT}:51821/tcp"
restart: unless-stopped
cap_add:
- NET_ADMIN
- SYS_MODULE
sysctls:
- net.ipv4.ip_forward=1
- net.ipv4.conf.all.src_valid_mark=1
healthcheck:
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://127.0.0.1:51821"]
interval: 30s
timeout: 15s
retries: 3
start_period: 30sThis configuration assumes an external network named cloudflare already exists. If you are not using Nginx Proxy Manager or another reverse proxy on this network, remove the cloudflare network references.
Deploy Container Stack
Create the persistent configuration directory:
mkdir -p /opt/containers/wg-easy/configStart the container:
docker compose up -dVerify the container is running:
docker psCheck container logs for errors:
docker logs wg-easyComplete Initial Setup
Open a web browser and navigate to http://SERVER_IP:51821. The wg-easy v15 setup wizard will appear.
Configure the following settings:
- Administrative password for web UI access
- Server public IPv4 address or fully qualified domain name
- DNS server for VPN clients (examples: 1.1.1.1, 8.8.8.8, 9.9.9.9)
After completing the wizard, the web interface displays options to create client configurations. Generate a new client profile and download the configuration file or scan the QR code with the WireGuard mobile application.
Firewall Configuration
Ensure port 51820/udp is accessible from client networks. If using UFW, add the following rule:
ufw allow 51820/udpPort 51821/tcp provides access to the web interface. Restrict this port to trusted networks or place wg-easy behind a reverse proxy with authentication.
Troubleshooting Common Issues
Container Fails to Start with IPv6 Errors
If the container enters a restart loop with IPv6-related errors in the logs, verify that all IPv6 sysctl parameters are removed from the docker-compose.yml file. Some base images attempt to enable IPv6 forwarding even when the host kernel has IPv6 disabled.
Clients Connect but Cannot Route Traffic
Verify that net.ipv4.ip_forward is enabled on the host system:
sysctl net.ipv4.ip_forwardThe output should show net.ipv4.ip_forward = 1. If the value is 0, the sysctl setting in the Compose file is not being applied correctly. Check Docker version compatibility with the sysctls directive.
Web Interface Returns Connection Refused
Check that the UI_PORT variable in the .env file matches the external port mapping in the docker-compose.yml ports section. Verify the container is listening on port 51821 internally:
docker exec wg-easy netstat -tuln | grep 51821Placing wg-easy Behind a Reverse Proxy
When deploying wg-easy behind Nginx Proxy Manager or another reverse proxy, change the INSECURE environment variable to false. Configure the reverse proxy to forward requests to the wg-easy container name on port 51821.
The WireGuard VPN port 51820/udp must remain directly exposed on the host. UDP traffic cannot be proxied through standard HTTP reverse proxies.
AI assistance is used on this site for language, formatting, and turning research into a consistent template. It is not used to perform the underlying research or verify technical claims. Every command, configuration, and step in this post is tested by hand before publication.