DEV Community

selfhosting.sh
selfhosting.sh

Posted on • Originally published at selfhosting.sh

wg-easy vs WireGuard: GUI vs Command Line

Quick Verdict

wg-easy is the better choice for most self-hosters running a WireGuard VPN server. It uses the exact same WireGuard protocol underneath but wraps it in a clean web UI for managing clients. You can create, disable, and revoke VPN clients with a click instead of editing config files. Choose raw WireGuard only if you need kernel-mode performance on constrained hardware, want to integrate WireGuard into a custom automation pipeline, or simply prefer the command line.

Overview

This isn't a comparison between two different VPN protocols — wg-easy is WireGuard, with a web interface on top.

WireGuard is the underlying VPN protocol and kernel module. You configure it via config files (/etc/wireguard/wg0.conf), generate keys with wg genkey, and manage peers by editing those files. It's fast, secure, and minimal — but all management is manual.

wg-easy is a Docker container that runs WireGuard and adds a web-based management interface. You create and manage VPN clients through a browser. Each client gets a downloadable config file and a QR code for mobile setup. Under the hood, it generates the same WireGuard configs and manages the same WireGuard interfaces.

Feature Comparison

Feature WireGuard (raw) wg-easy
VPN protocol WireGuard WireGuard (same)
Client management Edit config files manually Web UI (create/disable/revoke)
QR codes for mobile Generate with qrencode Built-in
Client config download Copy from server manually One-click download
Client traffic stats wg show command Web UI dashboard
Password protection N/A Web UI password
Client disable/enable Remove/add peer in config Toggle in UI
DNS configuration Manual in client config Configurable via env var
Multi-server support Multiple wg interfaces Single instance per container
Custom routing rules Full iptables control Basic (via env vars)
Kernel module support Yes (best performance) Yes (uses host kernel module)
Installation method Package manager / kernel module Docker only
Resource overhead ~5 MB RAM (kernel module only) ~30-50 MB RAM (Node.js UI + WireGuard)
Automation / scripting Full CLI control (wg commands) REST API available
Runs without Docker Yes No (Docker required)

Installation Complexity

WireGuard (raw): Install the wireguard-tools package, generate server and client key pairs, write /etc/wireguard/wg0.conf, configure iptables for NAT, enable IP forwarding, start the interface with wg-quick up wg0. Adding each client requires generating a new key pair, adding a [Peer] section to the server config, creating a client config file, and restarting. The LinuxServer.io Docker image simplifies this somewhat but is still config-file driven.

wg-easy: Create a docker-compose.yml with the wg-easy image, set your public hostname and admin password, run docker compose up -d. Adding a client takes 10 seconds through the web UI. See our wg-easy Docker guide.

Winner: wg-easy, by a wide margin. The web UI eliminates the most tedious part of running a WireGuard VPN — client management.

Performance and Resource Usage

Performance is identical for VPN traffic. wg-easy uses the host's WireGuard kernel module for the actual tunneling — the web UI is just a management layer that doesn't touch the data path.

Resource WireGuard wg-easy
RAM (idle) ~5 MB ~30-50 MB
CPU (tunneling) Kernel-level Kernel-level (same)
Disk ~1 MB (configs) ~100 MB (Node.js + deps)
Throughput Maximum (kernel) Maximum (same kernel module)

The extra ~25-45 MB of RAM for wg-easy's Node.js management server is negligible on any modern server.

Community and Support

Metric WireGuard wg-easy
License GPLv2 Custom (AGPL-like, check repo)
GitHub stars N/A (kernel tree) 18,000+
Docker pulls Millions (LSIO image) 12M+
Maintainer Jason Donenfeld / Linux kernel Community (wg-easy org)
Documentation Man pages, WireGuard.com README + environment vars
Active development Stable (protocol is "done") Active (regular releases)

Use Cases

Choose WireGuard (Raw) If...

  • You're running on a router, embedded device, or system without Docker
  • You need multiple WireGuard interfaces for complex routing
  • You want to integrate WireGuard into Ansible/Terraform/scripts
  • You prefer command-line tools and don't want a web UI
  • You need kernel-mode only with absolute minimum overhead

Choose wg-easy If...

  • You want to manage VPN clients without touching config files
  • You need QR codes for quick mobile client setup
  • You want to see client connection status and bandwidth at a glance
  • You're already running Docker for other services
  • You want non-technical family members to connect easily
  • You want to disable/enable clients without editing configs

Final Verdict

wg-easy is the obvious choice for most self-hosters. It removes the only real pain point of running WireGuard — client management — while preserving 100% of WireGuard's performance. The 30 MB of extra RAM is a worthwhile trade for not having to SSH into your server every time someone needs a new VPN config.

If you're running WireGuard on a router, in a scripted infrastructure-as-code setup, or on a device without Docker — use raw WireGuard. For everyone else, wg-easy is WireGuard made practical.

FAQ

Is wg-easy as secure as raw WireGuard?

Yes for the VPN tunnel itself — it uses the same WireGuard protocol. The web UI adds an additional attack surface (HTTP server on port 51821), so keep it behind a firewall or reverse proxy with authentication.

Can I migrate from raw WireGuard to wg-easy?

Not directly. wg-easy manages its own key generation and config format. You'll need to create new client configs through the wg-easy UI. Existing WireGuard keys can't be imported.

Does wg-easy support multiple WireGuard interfaces?

No. Each wg-easy container manages a single WireGuard interface (wg0). If you need multiple interfaces, use raw WireGuard.

Can I access wg-easy's management remotely?

Yes, but restrict access. Either put port 51821 behind a reverse proxy with authentication, access it over a VPN, or bind it only to localhost. Never expose the admin UI to the public internet without protection.

Related

Top comments (0)