Running your own WireGuard VPN server gives you a private, self-controlled network tunnel: traffic routes through your own cloud server, you control the logs (or disable them entirely), and you can cover unlimited devices for one flat monthly cost.
I've been running this setup for about a year. The initial setup takes around 15 minutes. After that, maintenance is essentially just occasional system updates.
Here's the complete walkthrough.
I use Tencent Cloud Lighthouse for the VPN server. They have data centers in North America, Europe, Singapore, Tokyo — pick the region that suits where you want your exit IP.
Key Takeaways
- WireGuard's 4,000-line codebase makes it easier to audit than OpenVPN's 70,000+ lines
- IP forwarding (
net.ipv4.ip_forward=1) must be enabled or the VPN passes no traffic- The wg-easy web UI makes adding new peer configurations a 2-minute task
- Lighthouse's global data centers let you choose your exit IP region
- Mobile clients connect via QR code import — no manual config copying needed
A self-hosted VPN server is worth considering if you want:
The main requirement is willingness to manage a server. For WireGuard, that means roughly 15 minutes of initial setup and occasional system updates afterward. The day-to-day maintenance is minimal.
| WireGuard | OpenVPN | |
|---|---|---|
| Codebase size | ~4,000 lines | ~70,000 lines |
| Connection speed | Near-instant | 3–10 seconds |
| Performance overhead | Very low | Moderate |
| Kernel-level integration | Yes (Linux 5.6+) | No |
| Configuration complexity | Simple | Medium-high |
| Protocol | UDP only | TCP + UDP |
WireGuard's compact codebase (~4,000 lines vs OpenVPN's ~70,000) makes it easier to audit and has a smaller attack surface. The Linux kernel team included WireGuard in the mainline kernel in 2020. For a self-hosted setup, WireGuard is the simpler and faster option.
| Requirement | Details |
|---|---|
| Cloud server | Tencent Cloud Lighthouse — Ubuntu 22.04 |
| UDP port 51820 | WireGuard's default port — must be open in firewall |
| Client devices | Works on Linux, macOS, Windows, iOS, Android |
| 15 minutes | Genuinely, that's about it |
Cost: The Starter plan (~$5–6/month) handles a personal VPN for several devices easily. See current promotions for new-user discounts.
The region you pick determines where your traffic appears to originate from. That's kind of the whole point.
After the instance is created, open the Firewall tab and add one rule:
| Port | Protocol | Purpose |
|---|---|---|
| 51820 | UDP | WireGuard tunnel |
| 22 | TCP | SSH management |
⚠️ WireGuard is UDP only. Make absolutely sure the firewall rule says UDP, not TCP.
SSH in:
ssh ubuntu@YOUR_SERVER_IP
Install WireGuard — it's in Ubuntu 22.04's default repos:
sudo apt update
sudo apt install -y wireguard wireguard-tools
Generate the server's key pair. WireGuard uses Curve25519 asymmetric keys — no passwords, no certificates, just a pair of keys:
# Generate private key
wg genkey | sudo tee /etc/wireguard/server_private.key
# Derive the matching public key
sudo cat /etc/wireguard/server_private.key | wg pubkey | sudo tee /etc/wireguard/server_public.key
# Lock down the private key
sudo chmod 600 /etc/wireguard/server_private.key
# Print both so you can note them
echo "=== SERVER PRIVATE KEY ===" && sudo cat /etc/wireguard/server_private.key
echo "=== SERVER PUBLIC KEY ===" && sudo cat /etc/wireguard/server_public.key
Copy the public key somewhere — you'll need it in every client config you create.
sudo nano /etc/wireguard/wg0.conf
[Interface]
# This server's VPN IP — clients will be 10.0.0.2, 10.0.0.3, etc.
Address = 10.0.0.1/24
# WireGuard listens here
ListenPort = 51820
# Paste your server private key here
PrivateKey = YOUR_SERVER_PRIVATE_KEY
# NAT rules: route client traffic out through eth0 (the server's network interface)
# If your interface isn't eth0, check with: ip link show
PostUp = iptables -A FORWARD -i wg0 -j ACCEPT; iptables -A FORWARD -o wg0 -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
PostDown = iptables -D FORWARD -i wg0 -j ACCEPT; iptables -D FORWARD -o wg0 -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE
To check your interface name:
ip link show
# Look for the main interface — usually eth0, ens3, or similar
This is the step that makes the server actually route your traffic to the internet, rather than just accepting tunnel connections. Without it your VPN connects but nothing loads.
echo "net.ipv4.ip_forward = 1" | sudo tee -a /etc/sysctl.conf
echo "net.ipv6.conf.all.forwarding = 1" | sudo tee -a /etc/sysctl.conf
sudo sysctl -p
Verify:
cat /proc/sys/net/ipv4/ip_forward
# Must output: 1
If it says 0, the forwarding isn't active. Re-run sudo sysctl -p.
# Bring the interface up
sudo wg-quick up wg0
# Check the interface status
sudo wg show
# You should see interface wg0, listening port 51820, and your public key
Enable auto-start on reboot:
sudo systemctl enable wg-quick@wg0
sudo systemctl status wg-quick@wg0
The server side is done. Now we need to configure clients.
Each device that connects to the VPN is a "peer". You generate a key pair for each device, then register the device's public key on the server.
For each device, generate a key pair (you can do this on the server):
# Replace "laptop" with a descriptive name for each device
wg genkey | tee /tmp/client_laptop_private.key
cat /tmp/client_laptop_private.key | wg pubkey | tee /tmp/client_laptop_public.key
echo "Private:" && cat /tmp/client_laptop_private.key
echo "Public:" && cat /tmp/client_laptop_public.key
Add the device's public key to the server config:
sudo nano /etc/wireguard/wg0.conf
Append at the bottom:
[Peer]
# My Laptop
PublicKey = CLIENT_LAPTOP_PUBLIC_KEY
AllowedIPs = 10.0.0.2/32
Apply without a full restart:
sudo wg addpeer $(cat /tmp/client_laptop_public.key) allowed-ips 10.0.0.2/32
For each additional device, repeat with the next IP (10.0.0.3, 10.0.0.4, etc.).
Create a client config file (call it wg-laptop.conf):
[Interface]
Address = 10.0.0.2/24
DNS = 1.1.1.1, 8.8.8.8
PrivateKey = CLIENT_LAPTOP_PRIVATE_KEY
[Peer]
PublicKey = SERVER_PUBLIC_KEY
AllowedIPs = 0.0.0.0/0, ::/0
Endpoint = YOUR_SERVER_IP:51820
PersistentKeepalive = 25
AllowedIPs = 0.0.0.0/0 means all traffic goes through the VPN (full tunnel). If you only want VPN traffic routed through the server, use 10.0.0.0/24 instead.
sudo apt install -y wireguard
sudo cp wg-laptop.conf /etc/wireguard/wg0.conf
sudo wg-quick up wg0
# Test: your IP should now show the server's IP
curl ifconfig.me
brew install wireguard-tools
# Or use the WireGuard app from the App Store — import the .conf file
Download WireGuard from wireguard.com/install, then:
Add Tunnel → Import tunnel(s) from file → select your .conf file → Activate
This is the cleanest way to get mobile devices connected. On the server:
sudo apt install -y qrencode
qrencode -t ansiutf8 < /tmp/wg-laptop.conf
A QR code appears in your terminal. Open the WireGuard app, tap + → Create from QR code, scan it. Done — no typing config files on mobile.
If you're going to add multiple family members or teammates, managing WireGuard via config files gets tedious. wg-easy gives you a clean web dashboard.
# Install Docker first
curl -fsSL https://get.docker.com | sudo sh
sudo usermod -aG docker $USER && newgrp docker
# Run wg-easy
docker run -d \
--name=wg-easy \
-e LANG=en \
-e WG_HOST=YOUR_SERVER_IP \
-e PASSWORD_HASH='your_bcrypt_password_hash' \
-v ~/.wg-easy:/etc/wireguard \
-p 51820:51820/udp \
-p 51821:51821/tcp \
--cap-add=NET_ADMIN \
--cap-add=SYS_MODULE \
--sysctl="net.ipv4.conf.all.src_valid_mark=1" \
--sysctl="net.ipv4.ip_forward=1" \
--restart unless-stopped \
ghcr.io/wg-easy/wg-easy
Open port 51821 in Lighthouse firewall, then visit http://YOUR_SERVER_IP:51821. From there you can create new clients, download their configs or QR codes, and see who's connected — all from a browser.
Disable SSH password auth — key-based only:
sudo sed -i 's/PasswordAuthentication yes/PasswordAuthentication no/' /etc/ssh/sshd_config
sudo systemctl reload sshd
Add a pre-shared key (PSK) for each client — this adds a layer of symmetric encryption on top of WireGuard's asymmetric key exchange:
wg genpsk | sudo tee /etc/wireguard/psk_laptop.key
# Add to server [Peer] section: PresharedKey = <psk value>
# Add the same to client [Peer] section
Keep WireGuard updated:
sudo apt update && sudo apt upgrade wireguard
I set everything up perfectly the first time, or so I thought. WireGuard connected. Handshake completed. But I couldn't browse anything.
The problem was IP forwarding — I had forgotten to enable it. The VPN tunnel was up, traffic was flowing into the server, but the server wasn't forwarding it anywhere. My browser requests were just… disappearing.
The moment I ran echo "net.ipv4.ip_forward = 1" | sudo tee -a /etc/sysctl.conf && sudo sysctl -p, everything started working immediately.
I've mentioned this already in Part 4, but I'm flagging it again here because it's the most common reason "I followed all the steps and it still doesn't work" happens. Check ip_forward first.
Here's what self-hosting WireGuard looks like in practice:
| Self-hosted WireGuard | |
|---|---|
| Monthly cost | ~$5–6/month (server only) |
| Devices covered | Unlimited |
| Setup time | ~15 minutes (one-time) |
| Maintenance | Occasional system updates |
| Exit IP regions | Any region where Lighthouse has data centers |
| Logging | Fully under your control |
| Reliability | Depends on your server's uptime SLA |
What works well: The connection is fast, handshakes complete in under a second, and adding a new device takes about 2 minutes. The wg-easy web UI (covered above) makes managing multiple peers straightforward.
Worth knowing: A self-hosted server gives you a single exit IP in one region. If your use case requires switching between many countries quickly, that's a different kind of setup. For most personal use cases — securing traffic on public networks, remote access to home resources, or routing traffic through a specific region — one server handles it well.
One genuine advantage of cloud-based servers for this: Tencent Cloud Lighthouse has data centers across multiple regions, so you can choose exactly where your exit IP is located.
| Issue | Likely Cause | Fix |
|---|---|---|
| Connection refused | Service not running or wrong port | Check systemctl status SERVICE and verify firewall rules |
| Permission denied | Wrong file ownership or permissions | Check file ownership with ls -la and use chown/chmod to fix |
| 502 Bad Gateway | Backend service not running | Restart the backend service; check logs with journalctl -u SERVICE |
| SSL certificate error | Certificate expired or domain mismatch | Run sudo certbot renew and verify domain DNS points to server IP |
| Service not starting | Config error or missing dependency | Check logs with journalctl -u SERVICE -n 50 for specific error |
| Out of disk space | Logs or data accumulation | Run df -h to identify usage; clean logs or attach CBS storage |
| High memory usage | Too many processes or memory leak | Check with htop; consider upgrading instance plan if consistently high |
| Firewall blocking traffic | Port not open in UFW or Lighthouse console | Open port in Lighthouse console firewall AND sudo ufw allow PORT |
How many devices can connect to my WireGuard VPN?
No software limit. Each device gets its own peer config. Personal use with 10–20 devices works fine on the smallest Lighthouse plan.
Is WireGuard faster than OpenVPN?
Generally yes. WireGuard uses modern cryptography and runs in the Linux kernel, resulting in lower latency for most use cases.
Do I need a domain name for WireGuard?
No — clients connect to your server IP directly.
How do I add my phone as a VPN client?
Install the WireGuard app (iOS/Android), then import your client config via QR code generated during setup.
What happens to my internet traffic when connected?
All traffic routes through your Lighthouse server and exits from its IP, encrypted between your device and the server.
Start your own private VPN today:
👉 Tencent Cloud Lighthouse — Global data center regions
👉 Check current launch promotions
👉 Explore all active deals and offers