docker.recipes

WireGuard Easy with UI

beginner

Easy WireGuard VPN setup with web-based management interface and QR code generation.

Overview

WireGuard Easy (wg-easy) is a simplified management interface for WireGuard VPN that eliminates the complexity of traditional VPN server administration. Created to address WireGuard's command-line complexity, wg-easy provides a web-based dashboard for managing VPN clients, generating configuration files, and creating QR codes for mobile device setup. The project transforms WireGuard's powerful but technical foundation into an accessible solution for users who need VPN functionality without extensive networking expertise. This stack combines wg-easy with NGINX to create a production-ready VPN solution with enhanced security and traffic management. NGINX serves as a reverse proxy, providing SSL termination, rate limiting, and additional security layers for the wg-easy web interface. The combination addresses common VPN deployment challenges including certificate management, traffic routing, and client onboarding through QR codes. Organizations benefit from this pairing because NGINX handles the web traffic complexities while wg-easy manages VPN client lifecycle, creating a robust solution that scales from personal use to enterprise deployments. This configuration suits network administrators seeking modern VPN infrastructure, remote teams requiring secure connectivity, and organizations transitioning from legacy VPN solutions to WireGuard's superior performance and security model.

Key Features

  • Interactive web dashboard for WireGuard client management with real-time connection status
  • Automatic QR code generation for instant mobile client configuration
  • One-click client creation and deletion with automatic key pair generation
  • Real-time bandwidth monitoring and connection statistics per client
  • NGINX reverse proxy with SSL/TLS termination and security headers
  • Built-in DNS configuration management for VPN clients
  • Automatic IP address allocation within defined subnets
  • Password-protected web interface with bcrypt hash authentication

Common Use Cases

  • 1Remote work infrastructure for distributed teams needing secure office network access
  • 2Homelab enthusiasts creating personal VPN servers for secure internet browsing
  • 3Small business secure connectivity for employees accessing internal resources
  • 4Development teams requiring secure connections to staging and production environments
  • 5Educational institutions providing VPN access for students and faculty
  • 6Content creators and digital nomads needing geo-location flexibility
  • 7Organizations migrating from expensive commercial VPN solutions to self-hosted alternatives

Prerequisites

  • Server with public IP address and UDP port 51820 accessible from internet
  • Minimum 512MB RAM recommended for concurrent client connections
  • Domain name or static IP for WG_HOST environment variable configuration
  • Basic understanding of VPN networking concepts and subnet configuration
  • SSL certificate files if enabling HTTPS through NGINX reverse proxy
  • Administrative access to router/firewall for port forwarding configuration

For development & testing. Review security settings, change default credentials, and test thoroughly before production use. See Terms

docker-compose.yml

docker-compose.yml
1services:
2 wg-easy:
3 image: ghcr.io/wg-easy/wg-easy:latest
4 environment:
5 WG_HOST: ${WG_HOST}
6 PASSWORD_HASH: ${PASSWORD_HASH}
7 WG_DEFAULT_ADDRESS: ${WG_DEFAULT_ADDRESS}
8 WG_DEFAULT_DNS: ${WG_DEFAULT_DNS}
9 WG_ALLOWED_IPS: ${WG_ALLOWED_IPS}
10 ports:
11 - "51820:51820/udp"
12 - "51821:51821/tcp"
13 volumes:
14 - wg-easy:/etc/wireguard
15 cap_add:
16 - NET_ADMIN
17 - SYS_MODULE
18 sysctls:
19 - net.ipv4.ip_forward=1
20 - net.ipv4.conf.all.src_valid_mark=1
21 networks:
22 - vpn-net
23 restart: unless-stopped
24
25 nginx:
26 image: nginx:alpine
27 ports:
28 - "80:80"
29 - "443:443"
30 volumes:
31 - ./nginx.conf:/etc/nginx/nginx.conf:ro
32 - ./certs:/etc/nginx/certs:ro
33 depends_on:
34 - wg-easy
35 networks:
36 - vpn-net
37 restart: unless-stopped
38
39volumes:
40 wg-easy:
41
42networks:
43 vpn-net:
44 driver: bridge

.env Template

.env
1# WireGuard Host (public IP or domain)
2WG_HOST=vpn.example.com
3
4# Password Hash (generate with: wgpw YOUR_PASSWORD)
5PASSWORD_HASH=
6
7# Client Configuration
8WG_DEFAULT_ADDRESS=10.8.0.x
9WG_DEFAULT_DNS=1.1.1.1
10WG_ALLOWED_IPS=0.0.0.0/0, ::/0

Usage Notes

  1. 1Web UI at http://localhost:51821
  2. 2Generate QR codes for mobile clients
  3. 3Port 51820/UDP must be accessible from internet
  4. 4Use wgpw command to generate password hash

Individual Services(2 services)

Copy individual services to mix and match with your existing compose files.

wg-easy
wg-easy:
  image: ghcr.io/wg-easy/wg-easy:latest
  environment:
    WG_HOST: ${WG_HOST}
    PASSWORD_HASH: ${PASSWORD_HASH}
    WG_DEFAULT_ADDRESS: ${WG_DEFAULT_ADDRESS}
    WG_DEFAULT_DNS: ${WG_DEFAULT_DNS}
    WG_ALLOWED_IPS: ${WG_ALLOWED_IPS}
  ports:
    - 51820:51820/udp
    - 51821:51821/tcp
  volumes:
    - wg-easy:/etc/wireguard
  cap_add:
    - NET_ADMIN
    - SYS_MODULE
  sysctls:
    - net.ipv4.ip_forward=1
    - net.ipv4.conf.all.src_valid_mark=1
  networks:
    - vpn-net
  restart: unless-stopped
nginx
nginx:
  image: nginx:alpine
  ports:
    - "80:80"
    - "443:443"
  volumes:
    - ./nginx.conf:/etc/nginx/nginx.conf:ro
    - ./certs:/etc/nginx/certs:ro
  depends_on:
    - wg-easy
  networks:
    - vpn-net
  restart: unless-stopped

Quick Start

terminal
1# 1. Create the compose file
2cat > docker-compose.yml << 'EOF'
3services:
4 wg-easy:
5 image: ghcr.io/wg-easy/wg-easy:latest
6 environment:
7 WG_HOST: ${WG_HOST}
8 PASSWORD_HASH: ${PASSWORD_HASH}
9 WG_DEFAULT_ADDRESS: ${WG_DEFAULT_ADDRESS}
10 WG_DEFAULT_DNS: ${WG_DEFAULT_DNS}
11 WG_ALLOWED_IPS: ${WG_ALLOWED_IPS}
12 ports:
13 - "51820:51820/udp"
14 - "51821:51821/tcp"
15 volumes:
16 - wg-easy:/etc/wireguard
17 cap_add:
18 - NET_ADMIN
19 - SYS_MODULE
20 sysctls:
21 - net.ipv4.ip_forward=1
22 - net.ipv4.conf.all.src_valid_mark=1
23 networks:
24 - vpn-net
25 restart: unless-stopped
26
27 nginx:
28 image: nginx:alpine
29 ports:
30 - "80:80"
31 - "443:443"
32 volumes:
33 - ./nginx.conf:/etc/nginx/nginx.conf:ro
34 - ./certs:/etc/nginx/certs:ro
35 depends_on:
36 - wg-easy
37 networks:
38 - vpn-net
39 restart: unless-stopped
40
41volumes:
42 wg-easy:
43
44networks:
45 vpn-net:
46 driver: bridge
47EOF
48
49# 2. Create the .env file
50cat > .env << 'EOF'
51# WireGuard Host (public IP or domain)
52WG_HOST=vpn.example.com
53
54# Password Hash (generate with: wgpw YOUR_PASSWORD)
55PASSWORD_HASH=
56
57# Client Configuration
58WG_DEFAULT_ADDRESS=10.8.0.x
59WG_DEFAULT_DNS=1.1.1.1
60WG_ALLOWED_IPS=0.0.0.0/0, ::/0
61EOF
62
63# 3. Start the services
64docker compose up -d
65
66# 4. View logs
67docker compose logs -f

One-Liner

Run this command to download and set up the recipe in one step:

terminal
1curl -fsSL https://docker.recipes/api/recipes/wireguard-easy-stack/run | bash

Troubleshooting

  • wg-easy container fails to start with 'Operation not permitted': Ensure Docker has NET_ADMIN and SYS_MODULE capabilities enabled on host system
  • Clients can connect but cannot access internet: Verify net.ipv4.ip_forward=1 sysctl setting and check server firewall rules for IP masquerading
  • Web interface shows 'Incorrect password' with correct credentials: Regenerate PASSWORD_HASH using bcrypt and ensure no trailing whitespace in environment variable
  • QR codes not generating or displaying blank: Check that WG_HOST environment variable contains externally accessible IP or domain name
  • VPN clients connect but have no internet access: Verify WG_DEFAULT_DNS is set to accessible DNS servers like 1.1.1.1 or 8.8.8.8
  • NGINX proxy returns 502 Bad Gateway: Ensure wg-easy service is running and accessible on port 51821 within Docker network

Community Notes

Loading...
Loading notes...

Download Recipe Kit

Get all files in a ready-to-deploy package

Includes docker-compose.yml, .env template, README, and license

Ad Space