🔐 Effortlessly Secure Your Network: Master WireGuard VPN with WG-Easy

I’m Insaf Nilam, a full-stack developer passionate about crafting clean, efficient, and future-ready software. I love solving complex problems, exploring new tech stacks, and sharing my learnings through blogs. When I’m not coding, I’m probably tweaking deployments, experimenting with microservices, or geeking out over cloud architecture.
WireGuard is a lightweight, high-performance VPN that has quickly become a favorite among developers and sysadmins. While we've previously covered how to set up WireGuard using the command line, setting it up can sometimes feel intimidating.
That’s where WG-Easy comes in — a minimal web UI that makes managing WireGuard simple, efficient, and beginner-friendly.
In this guide, you’ll learn how to:
✅ Install WG-Easy on a VPS (with or without Docker)
✅ Run it automatically with systemd (production-ready)
✅ Secure it with Nginx + Let’s Encrypt SSL
✅ Access it from your own custom domain
By the end, you’ll have a secure, always-on VPN you can manage right from your browser. 🌍
1. ⚙️ Prepare Your VPS
Before starting, make sure your VPS has:
Docker (optional, simplifies installation).
Node.js v22+ (if running without Docker).
Nginx (for reverse proxy + domain setup).
Update your server first:
sudo apt update && sudo apt upgrade -y
2. 📥 Install WG-Easy from Source (Without Docker)
Prefer not to use Docker? No problem — you can run WG-Easy directly.
🔹 Clone the WG-Easy Repository
git clone https://github.com/wg-easy/wg-easy.git
sudo mv wg-easy /opt/wg-easy
cd /opt/wg-easy/src
🔹 Create an Environment File
nano .env
Add:
PORT=51821
HOST=0.0.0.0
INSECURE=false
Later, we’ll restrict
HOSTto127.0.0.1for extra security when using Nginx.
🔹 Install Dependencies
npm install -g pnpm
pnpm install
pnpm approve-builds
pnpm run build
🔹 Add a Start Script
Edit package.json:
"scripts": {
"start": "node --env-file=.env .output/server/index.mjs"
}
Now run:
pnpm build
pnpm start
👉 Open in your browser: http://<your_server_ip>:51821
3. 🚧 Fixing Permission Issues
WG-Easy needs access to WireGuard configs at /etc/wireguard.
If you see “Permission denied”, run:
sudo mkdir -p /etc/wireguard
sudo chown -R $USER:$USER /etc/wireguard
✅ Now restart WG-Easy and it should work.
Stop services before continuing:
ss -tuln | grep 51821
sudo lsof -i :51821
sudo kill <PID>
4. 🌀 PM2 for Node.js Management (Optional)
If you’re running multiple Node.js apps, PM2 is a great choice:
npm install -g dotenv-cli pm2
pm2 start "dotenv -e .env node .output/server/index.mjs" --name wg-easy
pm2 save
pm2 startup
Check logs & status:
pm2 list
pm2 logs wg-easy
pm2 restart wg-easy
⚡ For a single VPS setup, skip PM2 and go straight to systemd (lighter + faster).
Stop PM2 before continuing:
pm2 stop wg-easy
pm2 delete wg-easy
5. 🖥️ Systemd Setup (Recommended)
Systemd ensures WG-Easy starts automatically on reboot.
Find your Node.js path:
which node
Create the service:
sudo vim /etc/systemd/system/wg-easy.service
Add:
[Unit]
Description=wg-easy - WireGuard Web UI
After=network.target
[Service]
ExecStart=<node path> /opt/wg-easy/src/.output/server/index.mjs
WorkingDirectory=/opt/wg-easy
Restart=always
User=root
Group=root
EnvironmentFile=/opt/wg-easy/src/.env
[Install]
WantedBy=multi-user.target
Enable + start:
sudo systemctl daemon-reload
sudo systemctl enable wg-easy
sudo systemctl start wg-easy
sudo systemctl status wg-easy
✅ WG-Easy will now run automatically at boot.
6. 🔥 Configure Firewall
sudo ufw allow 51820/udp # WireGuard
sudo ufw allow 51821/tcp # WG-Easy Web UI
sudo ufw status
7. 🌐 Access WG-Easy via Your Domain
Set up an Nginx reverse proxy:
server {
listen 80;
server_name wg.example.com;
location / {
proxy_pass http://127.0.0.1:51821;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
Enable and reload Nginx:
sudo ln -s /etc/nginx/sites-available/wg.example.com /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl restart nginx
👉 Now access via: http://wg.example.com
8. 🔒 Secure with Let’s Encrypt SSL
Install Certbot:
sudo apt install certbot python3-certbot-nginx -y
Run:
sudo certbot --nginx -d wg.example.com
Now WG-Easy is available securely:
👉 https://wg.example.com
9. ⚡ Optimize for Efficiency
Systemd → lightweight, stable, recommended for most.
PM2 → useful if running multiple Node.js apps or want clustering.
For 95% of setups → systemd is best.
10. 🐳 Running WG-Easy with Docker (Optional)
Prefer Docker? Run:
docker run --detach \
--name wg-easy \
--env PORT=51821 \
--env INSECURE=false \
--env HOST=0.0.0.0 \
--volume ~/.wg-easy:/etc/wireguard \
--publish 51820:51820/udp \
--publish 51821:51821/tcp \
--cap-add NET_ADMIN \
--cap-add SYS_MODULE \
--sysctl 'net.ipv4.conf.all.src_valid_mark=1' \
--sysctl 'net.ipv4.ip_forward=1' \
--restart unless-stopped \
ghcr.io/wg-easy/wg-easy
For domain-only access, update .env:
PORT=51821
HOST=127.0.0.1
INSECURE=false
Restart WG-Easy, and it’s accessible only via HTTPS.
sudo systemctl daemon-reexec
sudo systemctl restart wg-easy
✅ Final Steps
Once you visit https://wg.example.com, WG-Easy will prompt you to set up your username + password.
From there, you can easily add, remove, or manage WireGuard clients. 🎉
🚀 Summary
Install dependencies (Node.js or Docker, Nginx).
Clone and build WG-Easy.
Use systemd for production.
Configure firewall + reverse proxy.
Add SSL with Let’s Encrypt.
Manage VPN via your browser securely.
You now have a self-hosted WireGuard VPN with WG-Easy, running efficiently on your VPS. 🎉




