Skip to main content

Command Palette

Search for a command to run...

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

Updated
4 min read
🔐 Effortlessly Secure Your Network: Master WireGuard VPN with WG-Easy
M

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 HOST to 127.0.0.1 for 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

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

  1. Install dependencies (Node.js or Docker, Nginx).

  2. Clone and build WG-Easy.

  3. Use systemd for production.

  4. Configure firewall + reverse proxy.

  5. Add SSL with Let’s Encrypt.

  6. Manage VPN via your browser securely.

You now have a self-hosted WireGuard VPN with WG-Easy, running efficiently on your VPS. 🎉

The Ultimate Self-Hosted Privacy & Security Guide

Part 2 of 4

In this series, I’ll guide you to build a self-hosted privacy and security stack—setting up WireGuard VPN, managing it with WG-Easy, adding Pi-hole, Unbound, and Nginx for network-wide ad-blocking, with tips for security and reliability.

Up next

🔒 Network-Wide Ad-Blocking Mastery: Pi-hole, Unbound, WireGuard & Nginx in Action

Ever wished you could block ads, trackers, and malicious domains across your entire network—without installing a single browser extension?That’s exactly what Pi-hole does. Pi-hole works as a DNS sinkh

More from this blog

I

Insaf’s Dev Journal

28 posts