An easier WireGuard setup for Ubuntu and Debian
wg-easy adds a browser interface to WireGuard: create a device, download its configuration, or display a QR code. This tutorial builds a personal IPv4 VPN on a fresh Ubuntu 24.04 LTS or Debian 12/13 VPS. Your Windows, Mac, iPhone, or Android device connects to the Linux server; the server does not need to run your device’s operating system.
- Use an x86_64 or ARM64 VPS with a public IPv4 address, sudo access, and a kernel that supports WireGuard.
- Confirm that the plan permits VPN use and has enough transfer allowance for your devices.
- Keep your working SSH session open when changing firewall rules. Start with a separate VPS if the existing server already runs production applications.
1. Install Docker Engine and the Compose plugin
Use Docker’s official repository instructions for your distribution, including the docker-compose-plugin package. Use a current Docker Engine release; this localhost-binding approach requires version 28 or newer because older releases have a documented same-network exposure issue. These commands use regular, rootful Docker through sudo.
sudo apt update
sudo apt install nano
sudo docker version
sudo docker compose version
sudo install -d -m 0755 /opt/wg-easy
sudo install -d -m 0700 /opt/wg-easy/data
cd /opt/wg-easy
sudo nano compose.yaml2. Add the wg-easy Docker Compose configuration
Paste the following into compose.yaml. The :15 image tag follows supported v15 updates; do not substitute :latest or copy older PASSWORD and WG_HOST examples. v15 creates the administrator and VPN endpoint through its setup screen.
services:
vpn:
image: ghcr.io/wg-easy/wg-easy:15
restart: unless-stopped
environment:
INSECURE: "true"
DISABLE_IPV6: "true"
ports:
- "51820:51820/udp"
- "127.0.0.1:51821:51821/tcp"
volumes:
- ./data:/etc/wireguard
- /lib/modules:/lib/modules:ro
cap_add:
- NET_ADMIN
- SYS_MODULE
sysctls:
net.ipv4.ip_forward: "1"
net.ipv4.conf.all.src_valid_mark: "1"INSECURE permits HTTP for the local admin connection; the SSH tunnel in the next step encrypts its journey across the internet. Never change the admin mapping to a public address with this setting. For public browser administration, follow wg-easy’s HTTPS reverse-proxy documentation instead.
sudo docker compose config --quiet
sudo docker compose up -d
sudo docker compose ps3. Open the VPN port and securely reach the admin panel
| Traffic | Required access |
|---|---|
| UDP 51820 | Allow inbound to the VPS for WireGuard clients. |
| TCP 51821 | Keep closed publicly; use localhost through SSH. |
| Your SSH TCP port | Keep available to your administration IP. |
Apply the rules in your provider firewall and account for your host’s Docker firewall rules. Docker-published ports can bypass ordinary UFW rules, so UFW alone is not proof that the admin panel is private.
ssh -N -o ExitOnForwardFailure=yes -L 127.0.0.1:51821:127.0.0.1:51821 USER@PUBLIC_IPV4Keep that terminal open and visit http://127.0.0.1:51821 on the same computer. Verify the SSH host fingerprint on first connection. Create a strong administrator password, choose a new installation, and enter the VPS public IPv4 as Host with port 51820. The VPN endpoint must be the public address, never 127.0.0.1, a Docker address, or a URL beginning with http://.
4. Connect Windows, macOS, iPhone, and Android
Create a separate client profile for each device, named clearly—for example, Work laptop or Personal phone. Reusing one profile across simultaneous devices can cause connection problems and makes revocation harder.
| Device | Import method |
|---|---|
| Windows or macOS | Install the official WireGuard app, download the client .conf file, and import it as a tunnel. |
| iPhone, iPad, or Android | Install the official WireGuard app, add a tunnel, and scan the client QR code shown on your computer. |
Treat configuration files and QR codes as credentials: they contain private keys. Transfer them privately and revoke the profile if exposed. For full IPv4 routing, confirm the client AllowedIPs includes 0.0.0.0/0; separately address IPv6 as explained above.
5. Verify the connection and fix common problems
- Activate the client and confirm a recent handshake and increasing transfer counters in wg-easy.
- Compare your public IPv4 before and after connection; with full IPv4 routing, the connected result should match your VPS egress address.
- Check DNS resolution and IPv6 separately. Repeat after switching between Wi-Fi and cellular, then test what happens when the VPN disconnects.
- From outside the VPS, verify that its public address on TCP 51821 does not open the admin page.
| Symptom | Check first |
|---|---|
| No handshake | Public endpoint, UDP firewall rule, client keys, and whether the local network blocks UDP. |
| Handshake but no browsing | Client routes, configured DNS, forwarding, and Docker/host firewall conflicts. |
| Admin page unavailable | SSH tunnel still running, container status, and whether another app uses local port 51821. |
| Container restarts repeatedly | Container logs, kernel WireGuard support, and capability restrictions on the VPS. |
cd /opt/wg-easy
sudo docker compose logs --tail=80 vpn
sudo docker compose exec vpn wg showKeep your self-hosted VPN maintained
Before updates, review release notes and schedule a short interruption. Run docker compose down, back up compose.yaml and the data directory to protected storage, then start the service again. The backup contains VPN credentials. Never publish it or use docker compose down --volumes as an update shortcut.
cd /opt/wg-easy
sudo docker compose pull
sudo docker compose up -d
sudo docker compose psRetest a client, remove unused profiles, and keep the host and Docker patched. A personal VPN changes where traffic exits; it does not eliminate trust in the VPS operator or make browsing anonymous.
Common questions
Do I need a domain name for wg-easy?
No. A reachable public IPv4 address works as the WireGuard endpoint. A domain becomes useful if you later deploy an HTTPS administration interface.
Can I close the SSH tunnel after setup?
Yes. The tunnel is only for the admin interface. WireGuard clients continue connecting directly to the VPS over UDP 51820.
Does wg-easy include a VPN kill switch?
Do not assume one is enabled. Routing and fail-closed behavior depend on the client operating system and profile. Configure and test client controls, including IPv6 handling, separately.
Official documentation
Documentation reviewed October 18, 2026. Check the linked project documentation before installing or upgrading; commands below have not been run on your VPS.
- wg-easy: supported image tags
- wg-easy: Compose example
- wg-easy: optional settings and IPv6 behavior
- wg-easy: initial setup
- wg-easy: local HTTP access requirements
- Docker: port publishing and localhost binding
- Docker: Ubuntu installation and firewall limitations
- Docker: Debian installation
- OpenSSH: local port forwarding
- WireGuard: official client downloads