Skip to main content
Cybersecurity & Hardening

Self-Hosted WireGuard VPN with WG-Easy: A Practical Setup Guide

WireGuard plus WG-Easy gives you a self-hosted VPN with a clean web UI in under 30 minutes. Where it fits, where it doesn't, and the deployment patterns I run for managed clients.

Published Updated 5 min read

The pitch for self-hosted VPNs gets longer every year: cheaper than commercial VPNs, no shared exit IPs that get burned by spam blocklists, and you actually own the infrastructure your team depends on. The pushback was always the setup. WireGuard configs are short, but they’re text files with public/private keys you have to manage by hand, and “by hand” doesn’t scale to a team of five.

WG-Easy is the wrapper that fixes that. It runs WireGuard in a Docker container and gives you a web UI for managing peers (adding, removing, downloading config files, generating QR codes for mobile). For a freelancer or small team, it’s the cleanest way to run a self-hosted VPN that I know.

Why WireGuard is the protocol I default to

Three things about WireGuard, in order of how much I care about them:

  • The codebase is tiny. WireGuard is around 4,000 lines of code. OpenVPN is around 100,000. Smaller code means fewer bugs, fewer attack surfaces, and faster auditing. The Linux kernel ships WireGuard since 5.6, which says something about how the kernel maintainers feel about the code quality.
  • Modern cryptography by default. ChaCha20 for symmetric encryption, Curve25519 for key exchange, BLAKE2s for hashing, Poly1305 for authentication. There are no choices to make at handshake time, which means there are no insecure choices to make.
  • Sub-second handshakes. A WireGuard tunnel comes up almost instantly. OpenVPN can take 5-10 seconds to reconnect after a network change. On a laptop that constantly switches between Wi-Fi and hotspot, this is the difference between a VPN that’s “always on” and one users disable in frustration.

What WG-Easy adds

WireGuard’s tooling is precise but not friendly. You write a config file like this for the server:

[Interface]
PrivateKey = ...
Address = 10.8.0.1/24
ListenPort = 51820

[Peer]
PublicKey = ...
AllowedIPs = 10.8.0.2/32

And another one for each client. Then you run wg-quick up and hope. This works for one user. It does not work for a team of ten where people get added and removed every quarter.

WG-Easy turns that into a web UI:

  • Add a peer with a name and a click. The server config gets updated, the client config gets generated, and you download a .conf file or scan a QR code.
  • Remove a peer with a click. The server config gets updated, that peer is gone.
  • See connection status (last handshake, bytes transferred) per peer in the UI.
  • Optional traffic stats with charts.

It’s all the WireGuard you’d run by hand, with the bookkeeping done for you.

Deployment patterns I use

Three configurations I run for clients, in order of complexity:

Single-server, freelancer / small office. A 5€/month VPS, Docker installed, WG-Easy in one container behind a reverse proxy that handles TLS. WireGuard port (51820/UDP) is the only port public. Admin UI is behind HTTP basic auth or accessed via SSH tunnel. 30-minute setup.

Multi-region, single-team. A WG-Easy server in each region (EU, US, AU). Each user gets a config per region. The “VPN region” picker is just “which config did you load”. Cheap and resilient: if one region goes down, the team falls back to another.

Hub-and-spoke for cloud access. A WG-Easy server inside a cloud VPC, with the VPN’s allowed-IPs pointed at the VPC’s CIDR range. Users on the VPN can reach internal cloud resources directly without needing those resources to be public. Cleaner than a bastion host, simpler than a full Zero Trust setup.

For mesh-shaped scenarios (peers needing to reach each other without bouncing through a central server), I reach for Netbird instead. WG-Easy doesn’t do mesh; that’s not what it’s built for.

What WG-Easy doesn’t do

It’s a focused tool. The things it doesn’t try to be:

  • Not an SSO provider. Peers are username/password equivalents. If you need user identity tied to your IdP, WG-Easy isn’t the answer; pair it with a separate auth layer or use something like Netbird (which has SSO built in).
  • Not a mesh. Hub-and-spoke only. All traffic between peers routes through the server.
  • Not a network-policy engine. Once a peer is on the VPN, the firewall rules apply. You can’t write per-peer ACLs in WG-Easy itself.
  • Not free of operational care. You still patch the host, rotate the VPS, monitor the WireGuard tunnel for irregularities. WG-Easy makes the configuration easy; it doesn’t make running a server easy.

Closing the loop

For most freelancers and small teams, WG-Easy is the right answer to “I want my own VPN, today”. Open-source, audited protocol, friendly UI, deployable on any VPS in under an hour. Sponsor the maintainer on GitHub if you run it in production; the project has been stable for years because someone keeps showing up to maintain it.

If you want the production-grade deployment with the Compose file I actually ship, the firewall rules, and the bind-port detail that catches most people the first time, my WireGuard Easy front-door deployment post is the long version of this one.

If running a VPN in production sounds like one more thing to keep alive, the Cloud Infrastructure Audit & Hardening engagement covers the deployment, monitoring, and patching as part of the managed setup. For more on the security side, the cybersecurity & hardening category has the rest, and the Zero Trust security overview is the conceptual primer this post builds on.

Watch on YouTube

Video walkthrough

Prefer the screen-recording version of this guide? Watch it on YouTube. The card opens in a new tab so the player only loads when you ask for it.

Frequently Asked Questions

Want this handled, not just understood?

Reading the playbook is one thing. Running it on production at 2am is another. If you'd rather have me run it for you, the door is open.

Apply for Access