Step-by-step guide to installing and configuring a WireGuard server on Debian 12: packages, key generation, peer configuration, and firewall rules explained.

WireGuard is today one of the most appreciated VPN protocols: fast, secure, and surprisingly simple to configure compared to veterans like OpenVPN. In this guide we install a WireGuard server on Debian 12 (Bookworm) using wg-easy, a web interface that makes client management very easy even without the command line. At the end you will have a working personal VPN, accessible from any device.
What you need
- A working Debian 12 server (VPS, dedicated server, or local machine)
- Root access or a user with sudo privileges
- A static public IP or a domain pointing to the server
- Ports 51820/UDP (WireGuard) and 51821/TCP (wg-easy web interface) open in the firewall
If you have a VPS, verify that the provider's firewall (not just the system one) allows these ports.
Step 1: update the system
Before installing anything, bring the system up to the latest version:
sudo apt update && sudo apt upgrade -y
Reboot if there are kernel updates:
sudo reboot
Step 2: install Docker
wg-easy runs inside a Docker container, so we need to install it first:
sudo apt install -y docker.io docker-compose
Verify that Docker is active:
sudo systemctl enable --now docker
sudo docker --version
Step 3: install WireGuard and qrencode
Even though wg-easy manages everything via Docker, it's useful to have the native WireGuard tools for debugging:
sudo apt install -y wireguard wireguard-tools qrencode
Step 4: generate the password hash for wg-easy
wg-easy requires a password for the web interface. For security it doesn't save it in plaintext but in bcrypt hash format. Generate the hash with this command (replace yourpassword with the password you want to use):
docker run --rm -it ghcr.io/wg-easy/wg-easy wgpwcp yourpassword
The command will return something like:
$2b$12$abc123...xyz
Copy this value: you'll need it in the next step.
Step 5: create the directory and docker-compose.yml file
mkdir -p ~/wireguard && cd ~/wireguard
nano docker-compose.yml
Paste this configuration, replacing the values between <angle brackets>:
version: "3.8"
services:
wg-easy:
image: ghcr.io/wg-easy/wg-easy
container_name: wg-easy
environment:
- WG_HOST=<server-ip-or-domain>
- PASSWORD_HASH=<hash-generated-in-step-4>
- WG_DEFAULT_DNS=1.1.1.1,8.8.8.8
- WG_ALLOWED_IPS=0.0.0.0/0,::/0
volumes:
- ~/.wg-easy:/etc/wireguard
ports:
- "51820:51820/udp"
- "51821:51821/tcp"
cap_add:
- NET_ADMIN
- SYS_MODULE
sysctls:
- net.ipv4.conf.all.src_valid_mark=1
- net.ipv4.ip_forward=1
restart: unless-stopped
For WG_HOST use the server's public IP address or your domain (e.g., vpn.mydomain.com). For PASSWORD_HASH paste the hash generated earlier — note: if the hash contains $, you must enclose the value in single quotes in the YAML.
Step 6: start wg-easy
sudo docker compose up -d
Verify that the container is running:
sudo docker ps
You should see wg-easy in the list with status Up.
Step 7: access the web interface
Open your browser and go to:
http://<server-ip>:51821
Enter the password you chose in step 4 (not the hash, the original password).
Step 8: add your clients
From the web interface:
- Click "+ New"
- Assign a name to the client (e.g., "iPhone Francesco", "Work Laptop")
- Click "Create"
The server automatically generates the key pair and configuration. You have two ways to configure the client:
- QR code: scan it with the WireGuard app on iOS or Android
- .conf file: download it and import it into the WireGuard client on PC (Windows, macOS, Linux)
Step 9: configure the client
Smartphone (iOS / Android):
- Install the WireGuard app from the App Store or Google Play
- Tap + and choose "Scan QR code"
- Point the camera at the QR code shown by wg-easy
PC (Windows / macOS / Linux):
- Download WireGuard from wireguard.com
- Import the
.conffile downloaded from the web interface - Activate the tunnel
Step 10: verify the connection
Once connected, visit My IP to verify that the IP address shown is that of your VPN server, not your real IP. If it is, the VPN is working correctly.
Security: things to do after installation
- Don't expose port 51821 to the internet: consider putting it behind a reverse proxy with authentication (Nginx + HTTP Basic Auth) or accessing it only through the VPN itself
- Update regularly:
sudo docker compose pull && sudo docker compose up -d - Back up your keys: the
~/.wg-easydirectory contains the complete configuration; back it up in a safe place - Host firewall: configure
ufwto restrict access to only the necessary ports
Frequently asked questions
How many clients can I add? There is no technical limit imposed by wg-easy. The practical limit is the server's bandwidth: every client browsing through the VPN uses the server's bandwidth.
What happens if the server restarts?
The container has restart: unless-stopped, so it automatically restarts with Docker. Configurations persist in the volume mounted at ~/.wg-easy.
Can I use wg-easy with a domain instead of an IP?
Yes, and it's actually recommended if your IP is dynamic. Configure a DNS A record pointing to the server and use the domain in WG_HOST. If the IP changes, only update the DNS.
← All articles
