Running your own WireGuard server on a cheap Linux VPS gives you a private, encrypted tunnel you fully control, for the cost of a few dollars a month. It’s not a replacement for a commercial VPN’s IP pool or streaming unblocking, but for securing your own traffic on public Wi-Fi or accessing your home network remotely, it’s a genuinely solid option. Here’s the full setup on Ubuntu.

What you need before starting

A VPS running Ubuntu 22.04 or 24.04 (any budget provider works: the cheapest tier is enough for personal WireGuard use), root or sudo access over SSH, and about fifteen minutes. The same steps work with minor adjustments on Debian.

Want to compare all VPNs side by side? Check our full VPN comparison table with scores across 18 criteria.

Step 1: Update the system and install WireGuard

SSH into your VPS, then run:

sudo apt update && sudo apt upgrade -y
sudo apt install wireguard qrencode -y

qrencode isn’t required for WireGuard itself, but it lets you generate a QR code for scanning the client config directly into the mobile app later, which saves you from manually copying keys onto a phone.

Step 2: Generate the server’s key pair

cd /etc/wireguard
umask 077
wg genkey | tee server_private.key | wg pubkey > server_public.key

umask 077 matters here: it makes sure the key files aren’t readable by other users on the system. Keep both files; you’ll reference the private key in the server config and hand out the public key to nothing (it stays server-side).

Step 3: Create the server configuration

Create /etc/wireguard/wg0.conf:

[Interface]
PrivateKey = <paste server_private.key contents here>
Address = 10.8.0.1/24
ListenPort = 51820
SaveConfig = false

PostUp = iptables -A FORWARD -i wg0 -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
PostDown = iptables -D FORWARD -i wg0 -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE

Replace eth0 with your VPS’s actual public network interface name if it differs (check with ip a). The PostUp/PostDown lines are what let traffic from connected clients route out through the server’s public IP, without them you’d have a working tunnel that goes nowhere.

Step 4: Enable IP forwarding

WireGuard needs the kernel to forward packets between interfaces:

echo "net.ipv4.ip_forward=1" | sudo tee -a /etc/sysctl.conf
sudo sysctl -p

Skip this step and clients will connect but won’t be able to reach the internet through the tunnel, one of the most common WireGuard setup failures.

Step 5: Open the firewall port

If you’re using UFW:

sudo ufw allow 51820/udp
sudo ufw allow OpenSSH
sudo ufw enable

Also check your VPS provider’s dashboard for a separate cloud firewall or security group setting; some providers block ports at the network level regardless of what UFW allows on the instance itself, and that’s an easy step to miss if a connection quietly fails later.

Step 6: Generate a client key pair and add the peer

On the server, generate a key pair for your first client device:

wg genkey | tee client1_private.key | wg pubkey > client1_public.key

Add the client as a peer at the bottom of /etc/wireguard/wg0.conf:

[Peer]
PublicKey = <paste client1_public.key contents here>
AllowedIPs = 10.8.0.2/32

Step 7: Start the server

sudo systemctl enable --now wg-quick@wg0
sudo systemctl status wg-quick@wg0

Confirm it’s active and running before moving on. If it fails to start, re-check the interface name in Step 3 and the config file syntax, a single misplaced line is the usual cause.

Step 8: Build the client configuration

On your device (or a text file you’ll transfer securely), create a config using the client’s private key from Step 6:

[Interface]
PrivateKey = <client1_private.key contents>
Address = 10.8.0.2/32
DNS = 1.1.1.1

[Peer]
PublicKey = <server_public.key contents>
Endpoint = <your VPS public IP>:51820
AllowedIPs = 0.0.0.0/0
PersistentKeepalive = 25

AllowedIPs = 0.0.0.0/0 routes all client traffic through the tunnel, standard full-VPN behavior. If you only want to reach your home or VPS network without routing all internet traffic through it, narrow this to just that subnet instead.

For mobile, generate a QR code from this config and scan it directly into the WireGuard app:

qrencode -t ansiutf8 < client1.conf

Step 9: Test the connection

Activate the tunnel on the client, then check your public IP (a quick search for “what’s my IP” or a curl ifconfig.me from the client) to confirm it now shows your VPS’s address, not your original one. Also test DNS resolution isn’t leaking outside the tunnel.

Adding more devices

Repeat Steps 6 through 8 for each additional device, using a new 10.8.0.x address for each one (.3, .4, and so on) and a fresh key pair per device. Never reuse a private key across devices, if one device is compromised, a shared key compromises all of them.

Hardening the setup

A default WireGuard install is reasonably secure on its own, the protocol itself has a small, well-audited codebase, but a few extra steps close off common attack paths on the VPS hosting it:

Change the default SSH port and disable password auth. WireGuard protects the tunnel; it doesn’t protect the SSH service you used to set it up. Switch to key-based SSH login and consider moving off port 22 to cut down on automated scanning noise.

Install fail2ban. sudo apt install fail2ban gives you automatic, temporary IP bans against repeated failed login attempts on SSH, a cheap layer of protection on a public-facing VPS.

Keep the system patched. Run sudo apt update && sudo apt upgrade -y on a regular schedule, or enable unattended-upgrades for security patches. A self-hosted server is only as secure as its slowest-patched dependency.

Restrict AllowedIPs per peer where you can. If a device only needs to reach your home network rather than the full internet, scope its AllowedIPs to that subnet instead of 0.0.0.0/0. Narrower access limits what a compromised device could reach through the tunnel.

Common problems and fixes

Handshake fails, no connection at all. Almost always a firewall issue, either UFW on the VPS itself or a separate cloud security group blocking UDP 51820. Double-check both, they’re configured in different places and it’s easy to fix one and forget the other.

Connects, but no internet access through the tunnel. This is the IP forwarding step from earlier in this guide. Confirm net.ipv4.ip_forward is set to 1 and that the PostUp/PostDown NAT rules reference your actual public interface name, not a placeholder left over from copying the config.

Works on Wi-Fi, fails on mobile data. Some mobile carriers block or throttle non-standard UDP ports. If this happens consistently, changing ListenPort in the server config to a common port like 443 (and updating the client config to match) often resolves it, since carrier-level filtering is far less likely to touch a port that also carries ordinary HTTPS traffic.

What self-hosting doesn’t give you

This setup encrypts and routes your traffic through a server you control, which is genuinely valuable for securing hotel or airport Wi-Fi and for reaching your home network remotely. What it doesn’t give you is a large IP pool for streaming unblocking, since you’re always exiting from the same single VPS IP, or the plausible deniability of sharing an IP address with thousands of other users the way a commercial VPN’s shared servers provide. A single dedicated IP is also easier for services to flag and blacklist over time than a commercial provider’s frequently rotated pool.

If your goal is streaming access, geographic flexibility, or blending in with a large user base rather than controlling your own infrastructure, a commercial VPN is the better tool for that specific job; a self-hosted WireGuard server and a commercial VPN solve different problems and pair well together rather than competing.

Our Verdict

Self-hosting WireGuard on a cheap Ubuntu VPS takes about fifteen minutes and gives you a real, private tunnel under your own control for a few dollars a month. It's excellent for securing public Wi-Fi traffic and reaching your home network remotely. It's the wrong tool if you need streaming unblocking or a large rotating IP pool, that's a job for a commercial VPN with proper server infrastructure and audited no-logs practices instead.

For a similar self-hosted setup on cheaper hardware, see Set Up a WireGuard VPN Server on Raspberry Pi With PiVPN. For running WireGuard on your home router instead of a VPS, read How to Set Up a VPN on an OpenWrt Router. And if you’re deciding between protocols first, see VPN Protocols Explained 2026: WireGuard, OpenVPN, IKEv2 Compared.