Quick Setup Overview
- Provision a VPS with Ubuntu 22.04+ on DigitalOcean, Linode, or Hetzner ($5-10/mo)
- Install WireGuard:
sudo apt update && sudo apt install wireguard - Generate server keys:
wg genkey | tee server_privatekey | wg pubkey > server_publickey - Create
/etc/wireguard/wg0.confwith your server private key and listen port 51820 - Enable IP forwarding:
echo "net.ipv4.ip_forward=1" | sudo tee -a /etc/sysctl.conf - Add iptables NAT rules for masquerading in the PostUp/PostDown hooks
- Start the interface:
sudo wg-quick up wg0 && sudo systemctl enable wg-quick@wg0 - Generate client keys and add peer sections to the server config
- Create client config files with the server endpoint and allowed IPs
-
Test the connection and verify with
curl ifconfig.methrough the tunnel - Client Setup (Linux/Mac)
Step 1 - Generate Client Keys
On your client device (not VPS):
umask 077
wg genkey | tee client1_privatekey | wg pubkey > client1_publickey
Step 2 - Add Client to Server
Back on VPS, add client to wg0.conf:
cat >> /etc/wireguard/wg0.conf << EOF
[Peer]
PublicKey = $(cat /etc/wireguard/client1_publickey)
AllowedIPs = 10.0.0.2/32
EOF
Reload:
wg-quick down wg0 && wg-quick up wg0
Verify client is listed:
wg show
Expected - [Peer] section with client public key and 10.0.0.2
Step 3 - Create Client Config
On client machine, create /etc/wireguard/wg0.conf:
cat > /etc/wireguard/wg0.conf << EOF
[Interface]
PrivateKey = <CLIENT_PRIVATE_KEY>
Address = 10.0.0.2/32
DNS = 1.1.1.1, 8.8.8.8
[Peer]
PublicKey = <SERVER_PUBLIC_KEY>
Endpoint = your.vps.ip:51820
AllowedIPs = 0.0.0.0/0, ::/0
PersistentKeepalive = 25
EOF
Key fields:
PrivateKey: Client’s private keyAddress = 10.0.0.2/32: Client’s VPN IPDNS: DNS servers to use (critical for DNS leak prevention, see below)AllowedIPs = 0.0.0.0/0: Route ALL traffic through VPNPersistentKeepalive = 25: Keep connection alive every 25 seconds (important for mobile)
Step 4 - Connect on Linux/Mac
Install WireGuard (if not already)
Ubuntu - sudo apt install wireguard
Mac - brew install wireguard-tools
Create client config (copy content from Step 3)
sudo nano /etc/wireguard/wg0.conf
Paste the [Interface] and [Peer] blocks from above
Connect
sudo wg-quick up wg0
Verify connection
sudo wg show
Test (should show VPS IP, not your actual IP)
curl icanhazip.com
- Client Setup (Windows)
Step 1 - Download WireGuard
Go to wireguard.com/install, download Windows installer.
Step 2 - Create Configuration File
Create a file client1.conf with content:
[Interface]
PrivateKey = <CLIENT_PRIVATE_KEY>
Address = 10.0.0.2/32
DNS = 1.1.1.1, 8.8.8.8
[Peer]
PublicKey = <SERVER_PUBLIC_KEY>
Endpoint = your.vps.ip:51820
AllowedIPs = 0.0.0.0/0, ::/0
PersistentKeepalive = 25
Step 3 - Import in WireGuard App
- Open WireGuard application
- “Add Tunnel” → “Import tunnel(s) from file”
- Select
client1.conf - Click “Activate”
Status will show “Active” when connected.
- Mobile Setup (Android/iOS)
Android
- Install WireGuard app from Google Play
- Generate QR code from server: ```bash On server, generate QR for mobile device wg-quick up wg0 # If not already running Use website to convert config to QR: https://www.neilpatel.com/blog/qr-code-generator
Or use qrencode tool: apt install qrencode -y cat /path/to/client_config.conf | qrencode -t ansiutf8
3. In WireGuard app, "Create from scratch" or scan QR code
4. Configure with same settings as Linux client
5. Tap toggle to activate
iOS
Same as Android, but app from Apple App Store.
---
6. DNS Leak Prevention (Critical)
A DNS leak exposes your browsing even if traffic is encrypted.
Problem:
Your ISP normally handles DNS (domain → IP lookups) With VPN, some systems still query ISP’s DNS ISP sees your browsing, VPN doesn’t
- You visit example.com through VPN
- Traffic encrypted
- But DNS query for “example.com” goes to ISP (leaked)
- ISP sees you visited example.com ```
Solution - Force VPN-specific DNS servers.
Method 1 - Configure in WireGuard Config (Recommended)
Already done in step 3 above:
DNS = 1.1.1.1, 8.8.8.8
This tells WireGuard to use Cloudflare (1.1.1.1) and Google (8.8.8.8) DNS instead of ISP.
Verify no leak:
After connecting VPN, run DNS test
nslookup google.com
Output should show:
Server: 1.1.1.1
Not - Your ISP's nameserver (e.g., 192.168.1.1)
Online test - dnsleaktest.com (after connecting VPN, should show Cloudflare/Google, not ISP)
Method 2 - System-Wide (Linux)
If WireGuard DNS isn’t working:
Check if resolvectl available
resolvectl status
If not using VPN DNS, manually set:
resolvectl dns wg0 1.1.1.1 8.8.8.8
Method 3 - pfSense/Router Level
If VPN server is router:
- Set DNS upstream to 1.1.1.1, 8.8.8.8
- All devices using VPN inherit clean DNS
- Kill Switch (Prevent Leaks When VPN Drops)
Kill switch stops all traffic if VPN disconnects (prevents accidental unencrypted traffic).
Linux Kill Switch
Add to client’s wg0.conf:
[Interface]
PostUp = iptables -I OUTPUT ! -o %i -m mark ! --mark $(wg show %i fwmark) -m addrtype ! --dst-type LOCAL -j REJECT; ip6tables -I OUTPUT ! -o %i -m mark ! --mark $(wg show %i fwmark) -m addrtype ! --dst-type LOCAL -j REJECT
PostDown = iptables -D OUTPUT ! -o %i -m mark ! --mark $(wg show %i fwmark) -m addrtype ! --dst-type LOCAL -j REJECT; ip6tables -D OUTPUT ! -o %i -m mark ! --mark $(wg show %i fwmark) -m addrtype ! --dst-type LOCAL -j REJECT
Simpler approach using ufw:
Allow only wg0 interface
ufw default deny outgoing
ufw allow out on wg0
ufw allow out to any port 51820 # Allow VPN server IP
When disconnected, no traffic flows (kill switch active)
Windows Kill Switch
WireGuard app has built-in kill switch:
- Right-click system tray icon
- Settings
- “Route all traffic through WireGuard”
- This is default (enabled)
macOS Kill Switch
In WireGuard app:
- Preferences
- “Activate at login” (keeps VPN connected)
- For automatic kill switch, third-party tools needed
- Multi-Client Setup
To add more clients (up to 255):
Generate keys for client 2
umask 077
wg genkey | tee client2_privatekey | wg pubkey > client2_publickey
Add to server config
cat >> /etc/wireguard/wg0.conf << EOF
[Peer]
PublicKey = $(cat client2_publickey)
AllowedIPs = 10.0.0.3/32
EOF
Reload
wg-quick down wg0 && wg-quick up wg0
Verify
wg show
Expected - 2 peers listed
Create client config with AllowedIPs = 10.0.0.3/32 and connect.
Client Management Script
For managing many clients:
#!/bin/bash
add-wireguard-client.sh
CLIENT_NAME=$1
VPS_IP=$2
Generate keys
umask 077
wg genkey | tee ${CLIENT_NAME}_privatekey | wg pubkey > ${CLIENT_NAME}_publickey
Get server private key
SERVER_PUBKEY=$(cat /etc/wireguard/publickey)
Find next available IP in 10.0.0.0/24 range
NEXT_IP=$(wg show wg0 | grep "allowed ips:" | tail -1 | grep -oE '[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+' | sed 's/\([0-9]*\)$/\1/' | awk -F. '{print $1"."$2"."$3"."+($4+1)}')
Add peer to server config
echo "" >> /etc/wireguard/wg0.conf
echo "[Peer]" >> /etc/wireguard/wg0.conf
echo "PublicKey = $(cat ${CLIENT_NAME}_publickey)" >> /etc/wireguard/wg0.conf
echo "AllowedIPs = ${NEXT_IP}/32" >> /etc/wireguard/wg0.conf
Reload WireGuard
wg-quick down wg0 && wg-quick up wg0
Create client config
cat > ${CLIENT_NAME}.conf << EOF
[Interface]
PrivateKey = $(cat ${CLIENT_NAME}_privatekey)
Address = ${NEXT_IP}/32
DNS = 1.1.1.1, 8.8.8.8
[Peer]
PublicKey = ${SERVER_PUBKEY}
Endpoint = ${VPS_IP}:51820
AllowedIPs = 0.0.0.0/0, ::/0
PersistentKeepalive = 25
EOF
echo "Client config saved to ${CLIENT_NAME}.conf"
Usage:
chmod +x add-wireguard-client.sh
./add-wireguard-client.sh client2 your.vps.ip
- Server Monitoring
Monitor VPN usage:
Real-time traffic
wg show wg0
Shows - received/sent bytes per peer
Example output:
interface: wg0
public key: gI6E...
private key: (hidden)
listening port: 51820
#
peer: ABC123...
endpoint: 192.168.1.100:12345
allowed ips: 10.0.0.2/32
latest handshake: 2 minutes, 15 seconds ago
transfer: 1.25 MB received, 840 MB sent
persistent keepalive: every 25 seconds
Check server logs:
journalctl -u wg-quick@wg0 -f
Shows status changes, errors
Mar 21 08:30:10 vps systemd[1]: Started WireGuard via wg-quick(8) for wg0.
Mar 21 08:35:15 vps kernel: [wg0] peer ABC123 made first handshake
- Troubleshooting
Connection Hangs
Check server is listening
netstat -ulpn | grep 51820
Expected - udp 0 0 0.0.0.0:51820 0.0.0.0:* LISTEN
Check firewall allows port
ufw status | grep 51820
Expected - 51820/udp ALLOW
Client Can’t Reach Server
From client, test connectivity
ping your.vps.ip
Should work (simple ICMP)
Test UDP connectivity to port 51820
On server - nc -u -l 51820
On client - echo "test" | nc -u your.vps.ip 51820
Should see "test" on server
DNS Still Leaking
Force DNS via terminal (Linux)
sudo resolvectl dns wg0 1.1.1.1 8.8.8.8
Verify
cat /etc/resolv.conf
Should show - nameserver 1.1.1.1, nameserver 8.8.8.8
Slow Speed
Test speed
iperf3 -s # On server
iperf3 -c your.vps.ip # On client
WireGuard typical speeds:
Gigabit connection: 600-800 Mbps through VPN (expected, not max)
Slow connection - Check server CPU (may be maxed)
Can’t Access Local Network
If you want to reach local devices through VPN (not internet):
In client config, change AllowedIPs:
Instead of - AllowedIPs = 0.0.0.0/0
Use - AllowedIPs = 192.168.1.0/24, 10.0.0.0/24
This routes only local networks through VPN
Other traffic goes through normal internet
- Maintenance
Regular Tasks
Check logs monthly:
journalctl -u wg-quick@wg0 --since "30 days ago" | grep -i error
Remove inactive clients:
wg show wg0 | grep -B1 "latest handshake: [3-9][0-9]\+ days"
Edit wg0.conf to remove their [Peer] block
wg-quick down wg0 && wg-quick up wg0
Update Ubuntu regularly:
apt update && apt upgrade -y
systemctl restart wg-quick@wg0
Backup Configuration
Backup VPN config
cp /etc/wireguard/wg0.conf ~/wg0.conf.backup
Store safely (encrypted cloud storage, password manager, etc.)
Cost Analysis
Self-hosted WireGuard vs commercial VPN:
Self-hosted:
- VPS: $2.50-5/month
- Electricity/maintenance: Included in VPS cost
- Dedicated IP: Yes
- Setup time: 30 minutes
- Annual cost: $30-60
Commercial VPN:
- $5-15/month
- Shared infrastructure
- Setup time: 2 minutes
- Annual cost: $60-180
Break-even - 3-6 months of usage.
Long-term savings - Self-hosted is 50-70% cheaper.
Security Considerations
What WireGuard Protects
- Traffic encryption (ISP can’t see content)
- IP privacy (websites see VPN server IP, not yours)
- DNS privacy (if configured correctly)
What It Doesn’t Protect
- Malware (still need antivirus)
- Phishing (still need caution)
- Browser fingerprinting (websites still identify you via browser)
- Account login credentials (use strong passwords)
VPS Security
After setup, harden:
Disable root login
sed -i 's/PermitRootLogin yes/PermitRootLogin no/' /etc/ssh/sshd_config
Use SSH keys only (no passwords)
Generate - ssh-keygen -t ed25519
Upload public key to ~/.ssh/authorized_keys
Restart SSH
systemctl restart ssh
Enable UFW firewall (done above)
Automatic security updates
apt install unattended-upgrades
Frequently Asked Questions
How long does it take to set up wireguard vpn on vps?
For a straightforward setup, expect 30 minutes to 2 hours depending on your familiarity with the tools involved. Complex configurations with custom requirements may take longer. Having your credentials and environment ready before starting saves significant time.
What are the most common mistakes to avoid?
The most frequent issues are skipping prerequisite steps, using outdated package versions, and not reading error messages carefully. Follow the steps in order, verify each one works before moving on, and check the official documentation if something behaves unexpectedly.
Do I need prior experience to follow this guide?
Basic familiarity with the relevant tools and command line is helpful but not strictly required. Each step is explained with context. If you get stuck, the official documentation for each tool covers fundamentals that may fill in knowledge gaps.
Is this approach secure enough for production?
The patterns shown here follow standard practices, but production deployments need additional hardening. Add rate limiting, input validation, proper secret management, and monitoring before going live. Consider a security review if your application handles sensitive user data.
Where can I get help if I run into issues?
Start with the official documentation for each tool mentioned. Stack Overflow and GitHub Issues are good next steps for specific error messages. Community forums and Discord servers for the relevant tools often have active members who can help with setup problems.
Related Articles
- How to Use WireGuard for Self-Hosted VPN in 2026
- Set Up a Personal VPN with WireGuard
- How to Set Up WireGuard on VPS for Personal
- OpenWrt VPN Router Setup with WireGuard
- Best VPN for Linux Desktop: A Developer Guide
- AI Coding Assistant Session Data Lifecycle Built by theluckystrike. More at zovo.one