Stop trusting sketchy public Wi-Fi and overpriced commercial VPN providers. If you have a Virtual Private Server (VPS), you are ten minutes away from having your own blazing-fast, private VPN using the modern WireGuard protocol.
While WireGuard is notoriously difficult to configure manually, we are going to use Docker and a fantastic tool called wg-easy. This approach gives you a clean installation, easy updates, and a beautiful web dashboard to manage your devices with QR codes.
Why Use Docker for This?
You could install WireGuard directly onto your server’s operating system, but Docker is better for a few reasons:
- Cleanliness: It keeps all the VPN dependencies isolated in a container. Your main server OS stays clean.
- Portability: Moving servers? Just copy one folder, run one command, and your VPN is back up.
- Ease of Use: The
wg-easycontainer bundles WireGuard with a web UI, saving you from messing with complex config files manually.
Prerequisites
- A VPS running Linux (Ubuntu 22.04/24.04 recommended).
- Access to the terminal via SSH.
- Your VPS Public IP address.
Step 1: Install Docker
First, ensure your server is updated, and Docker is installed. Run these commands one by one:
# Update package list sudo apt update && sudo apt upgrade -y # Install Docker using their official convenience script curl -fsSL https://get.docker.com | sh # Verify it's running sudo systemctl status docker
Step 2: Generate Your Secure Password Hash
This is the most critical step.
Recent security updates to wg-easy forbid putting plain-text passwords in configuration files. You must generate a secure “bcrypt hash” of your desired password.
Run this temporary command. Replace YOUR_DESIRED_PASSWORD with the actual password you want to use for the Web UI login.
docker run --rm -it ghcr.io/wg-easy/wg-easy wgpw 'YOUR_DESIRED_PASSWORD'
The output will look something like this. Copy it to a notepad temporarily: PASSWORD_HASH='$2b$12$7K1/....longstring....'
Step 3: Create the Configuration File
We will use Docker Compose to define our VPN service. This makes it easy to manage.
Create a folder and open a new configuration file:
mkdir ~/wireguard cd ~/wireguard nano docker-compose.yml
Paste in the following configuration.
IMPORTANT CONFIGURATION RULES:
- Replace
YOUR_VPS_IPwith your server’s actual IP. - Replace the
PASSWORD_HASHvalue with the one you generated in Step 2. - CRITICAL: You must change every single
$sign in your hash to a double$$. If you don’t, Docker will break your password.
services:
wg-easy:
image: ghcr.io/wg-easy/wg-easy
container_name: wg-easy
environment:
# REPLACE WITH YOUR VPS PUBLIC IP
- WG_HOST=YOUR_VPS_IP
# Paste your hash below. ENSURE YOU USE DOUBLE $$ SIGNS!
# Example: $$2b$$12$$coPqCsPtcFO.Ab99xylBNOW4...
- PASSWORD_HASH=PASTE_YOUR_HASH_HERE_WITH_DOUBLE_DOLLAR_SIGNS
# Optional: Use Cloudflare DNS for speed and privacy
- WG_DEFAULT_DNS=1.1.1.1, 1.0.0.1
volumes:
- .:/etc/wireguard
ports:
- "51820:51820/udp" # The VPN tunnel port
- "51821:51821/tcp" # The Web UI Dashboard port
restart: unless-stopped
cap_add:
- NET_ADMIN
- SYS_MODULE
sysctls:
- net.ipv4.conf.all.src_valid_mark=1
- net.ipv4.ip_forward=1
Save the file by pressing CTRL+X, then Y, then Enter.
Step 4: Start the VPN and Open the Firewall
Start the Docker container in the background:
docker compose up -d
Configure your firewall (UFW) to allow the necessary traffic. Do not skip the SSH allowance or you will lock yourself out!
ufw allow 22/tcp # Allow SSH ufw allow 51820/udp # Allow VPN traffic ufw allow 51821/tcp # Allow Web UI access ufw enable # Turn firewall on
Step 5: Connect Your Devices
- Open your web browser and navigate to:
http://YOUR_VPS_IP:51821(Note: Make sure you use http, not https for now). - Log in using the original plain-text password you used in Step 2 to generate the hash.
- Click “New Client” and name it (e.g., “iPhone”).
- Click the QR Code icon.
- Open the official WireGuard App on your phone, tap the + sign, scan the QR code, and activate the tunnel.
You are now connected securely through your own private server!
Troubleshooting Common Errors
If your container fails to start, check the logs using docker compose logs -f.
Error 1: “DO NOT USE PASSWORD ENVIRONMENT VARIABLE”
The Cause: You are using an older configuration format. The Fix: In your docker-compose.yml, ensure the environment variable is named PASSWORD_HASH, not just PASSWORD.
Error 2: “Variable is not set. Defaulting to a blank string.”
The Cause: Docker thinks the $ signs in your password hash are trying to reference variables. The Fix: You didn’t escape the dollar signs. Edit your docker-compose.yml. Everywhere your hash has a $, change it to $$.
- Wrong:
$2b$12$... - Right:
$$2b$$12$$...
After fixing any errors in the YAML file, always apply the changes by running:
docker compose up -d --force-recreate
🔒 Bonus: How to Make Your Dashboard 100% Invisible
By default, Docker exposes your login page to the whole internet. Even with a strong password, this isn’t ideal.
Since you have a VPN, you can do something clever: Hide the dashboard so it only exists inside the VPN tunnel.
Step 1: Edit your config Open your docker-compose.yml file again.
Step 2: Remove the public port Find the ports section. You need to comment out or remove the line that exposes port 51821.
YAML
ports:
- "51820:51820/udp" # Keep the VPN port open!
# - "51821:51821/tcp" # <--- Add a # to disable public access
Step 3: Update the container Apply the change:
Bash
docker compose up -d --force-recreate
Step 4: Access it securely Now, you cannot access the dashboard via your Public IP anymore. Instead:
- Connect to your WireGuard VPN on your device.
- Open your browser and go to:
http://10.8.0.1:51821(Note:10.8.0.1is the default internal IP for the VPN container).
Now you have military-grade security: A dashboard that is completely invisible to the outside world!