How to Deploy a WireGuard VPN Server on a Budget VPS

How to Deploy a WireGuard VPN Server on a Budget VPS

We earn commissions when you shop through the links on this page, at no additional cost to you. Learn more.

WireGuard is hands-down the most elegant piece of networking software I have ever worked with. It is fast, uses modern cryptography, and the entire kernel module is under 4,000 lines of code — compare that to OpenVPN's sprawling mess and you will immediately understand why the homelab community switched years ago. In this tutorial I will walk you through deploying a fully functional WireGuard VPN server on a budget VPS, from zero to tunneling traffic in about 30 minutes.

I run this exact setup on a DigitalOcean Droplet — the $6/month 1 vCPU / 1 GB RAM instance is more than powerful enough to serve a dozen peers simultaneously. You can do the same on RackNerd, Hetzner, or any other provider that gives you a public IPv4 address and root access.

Why WireGuard Over Other VPN Solutions?

I have run OpenVPN for years and I tried Algo before landing on WireGuard. The reason I stay with WireGuard is simple: roaming works flawlessly. When my laptop switches from home Wi-Fi to a coffee shop hotspot, the tunnel reconnects in milliseconds without me touching anything. OpenVPN would often need a manual restart. WireGuard also benchmarks at 3–4× the throughput of OpenVPN on the same hardware, which matters when you are routing all traffic through a $6 VPS.

The one honest downside: WireGuard is stateless by design. There is no built-in concept of "who is connected right now." If you need that kind of session visibility, you will want to layer something on top — but for personal use, it simply does not matter.

Choosing and Preparing Your VPS

Any VPS with at least 512 MB RAM and a public IP works fine. I specifically recommend DigitalOcean Droplets because their networking stack plays nicely with WireGuard's UDP traffic and their firewall rules are easy to manage. Get dependable uptime with our 99.99% SLA, simple security tools, and predictable monthly pricing with DigitalOcean's virtual machines, called Droplets.

Spin up a fresh Ubuntu 24.04 LTS instance. Once you have SSH access, run a full system update before touching anything else:

apt update && apt upgrade -y
apt install -y wireguard wireguard-tools ufw

On Ubuntu 24.04, WireGuard ships in the standard repositories — no kernel headers or DKMS compilation needed. It is one of the cleanest installs in Linux networking today.

Generating Keys

WireGuard uses Curve25519 public/private key pairs. You need to generate a key pair for the server and one for each client (peer) you want to connect. I generate them all on the server and then distribute the client keys securely.

# Generate server keys
wg genkey | tee /etc/wireguard/server_private.key | wg pubkey > /etc/wireguard/server_public.key

# Generate a key pair for your first client (e.g., your laptop)
wg genkey | tee /etc/wireguard/peer1_private.key | wg pubkey > /etc/wireguard/peer1_public.key

# Lock down permissions on the private keys
chmod 600 /etc/wireguard/server_private.key /etc/wireguard/peer1_private.key

# Print the keys so you can copy them
echo "Server private:"; cat /etc/wireguard/server_private.key
echo "Server public:"; cat /etc/wireguard/server_public.key
echo "Peer1 private:"; cat /etc/wireguard/peer1_private.key
echo "Peer1 public:"; cat /etc/wireguard/peer1_public.key
Watch out: Never share your private key with anyone, and never paste it into a chat, ticket, or web UI. If a private key is ever exposed, delete the key pair immediately and generate a new one. Treat it exactly like an SSH private key.

Configuring the Server Interface

The server configuration lives at /etc/wireguard/wg0.conf. I use the 10.8.0.0/24 subnet for my VPN — it rarely conflicts with anything on a home network. Replace the placeholder values with your actual keys.

cat > /etc/wireguard/wg0.conf << 'EOF'
[Interface]
Address = 10.8.0.1/24
ListenPort = 51820
PrivateKey = PASTE_SERVER_PRIVATE_KEY_HERE

# Enable IP forwarding and NAT so peers can reach the internet
PostUp = sysctl -w net.ipv4.ip_forward=1
PostUp = iptables -A FORWARD -i wg0 -j ACCEPT
PostUp = iptables -A FORWARD -o wg0 -j ACCEPT
PostUp = iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
PostDown = iptables -D FORWARD -i wg0 -j ACCEPT
PostDown = iptables -D FORWARD -o wg0 -j ACCEPT
PostDown = iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE

# Peer 1 — Laptop
[Peer]
PublicKey = PASTE_PEER1_PUBLIC_KEY_HERE
AllowedIPs = 10.8.0.2/32
EOF

chmod 600 /etc/wireguard/wg0.conf
Tip: On DigitalOcean and some other providers, the primary network interface might be named ens3 or ens160 rather than eth0. Run ip route get 1.1.1.1 and check the dev field to confirm your interface name before saving the config.

Make IP forwarding persistent across reboots by editing /etc/sysctl.conf and uncommenting (or adding) net.ipv4.ip_forward=1. The PostUp lines in the config handle it dynamically, but the sysctl file makes it permanent.

Firewall Rules with UFW

I always use UFW on budget VPS instances — it is simple and hard to get catastrophically wrong. Allow WireGuard's UDP port and make sure SSH stays open before you enable the firewall.

# Allow SSH (do this first or you will lock yourself out)
ufw allow 22/tcp

# Allow WireGuard
ufw allow 51820/udp

# Enable UFW
ufw enable

# Verify
ufw status verbose

One thing that catches people out: UFW and iptables share the same netfilter backend. When you enable UFW it sets a default FORWARD policy of DROP, which will silently break WireGuard routing. Fix it by editing /etc/default/ufw and setting DEFAULT_FORWARD_POLICY="ACCEPT", then run ufw reload.

Starting WireGuard and Enabling at Boot

# Bring the interface up
wg-quick up wg0

# Enable at boot
systemctl enable wg-quick@wg0

# Check status
wg show

The output of wg show should list your interface address, the listening port (51820), and your peer with its allowed IPs. If you see that, the server side is done.

Creating the Client Configuration

Each client needs its own .conf file. I create this file on the server, copy it to the client securely (over the existing SSH session), then delete it from the server. On the client this file goes into /etc/wireguard/wg0.conf on Linux, or you can import it into the official WireGuard apps on macOS, iOS, and Android.

cat > /tmp/peer1.conf << 'EOF'
[Interface]
Address = 10.8.0.2/24
PrivateKey = PASTE_PEER1_PRIVATE_KEY_HERE
DNS = 1.1.1.1

[Peer]
PublicKey = PASTE_SERVER_PUBLIC_KEY_HERE
Endpoint = YOUR_VPS_PUBLIC_IP:51820
AllowedIPs = 0.0.0.0/0
PersistentKeepalive = 25
EOF

The AllowedIPs = 0.0.0.0/0 line routes all traffic through the VPN — that is a full tunnel, which is what most people want. If you only want to access private resources on the VPN subnet (split tunnel), change it to 10.8.0.0/24 instead.

PersistentKeepalive = 25 is important if your client is behind NAT (which most home routers are). It sends a keepalive packet every 25 seconds so the NAT table entry stays alive. Without it, the connection can silently drop after a few minutes of idle time.

Adding More Peers Later

One of WireGuard's nicest features is that you can add peers to a running interface without restarting anything. Generate a new key pair, then:

# Add a new peer on-the-fly (no restart required)
wg set wg0 peer PEER2_PUBLIC_KEY allowed-ips 10.8.0.3/32

# Make it persistent by appending to the config file
wg-quick save wg0

The wg-quick save wg0 command writes the current live state back to /etc/wireguard/wg0.conf, including any peers you added dynamically. This is the workflow I follow every time I add a new device.

Testing the Connection

On the client, bring up the interface and ping the server's VPN address:

wg-quick up wg0
ping 10.8.0.1

# Confirm all traffic is going through the tunnel
curl https://ifconfig.me

If curl https://ifconfig.me returns your VPS's public IP rather than your home IP, the full tunnel is working correctly. Run wg show on the server and you will see the peer's last handshake time updating in real time.

Tip: If the handshake never completes, the most common culprit is a cloud provider firewall (sometimes called "security groups") blocking UDP port 51820 at the network level — separate from UFW. On DigitalOcean this is handled in the Droplet's Firewall settings in the web console. Make sure UDP 51820 is allowed there as well.

Performance and Real-World Throughput

On a DigitalOcean $6 Droplet (shared vCPU, 1 GB RAM), I consistently see 250–400 Mbps throughput through the WireGuard tunnel when the client has a fast upstream connection. That is more than enough for everything except bulk file transfers. If you are pushing 1 Gbps of traffic, you will want a dedicated vCPU instance, but for everyday browsing, streaming, and remote access to homelab services, the budget tier is perfectly adequate.

CPU usage on the server sits below 5% at idle and spikes to around 20–25% during a large file transfer. WireGuard's use of ChaCha20-Poly1305 is highly efficient on CPUs without AES hardware acceleration — which is exactly what you get on cheap virtual machines.

Next Steps

With WireGuard running, you now have a private encrypted tunnel between any of your devices and your VPS. The logical next step is to combine this with a self-hosted DNS resolver like AdGuard Home (running at 10.8.0.1:53) so that ad-blocking applies to every device connected to the VPN. You can also use the tunnel to securely expose homelab services without opening ports on your home router — point your clients at the VPS, and let WireGuard handle the routing.

Start spending more time on your projects and less time managing your infrastructure. Create your DigitalOcean account today. A $6 Droplet is genuinely all you need for a personal WireGuard server, and the setup you just completed will serve you reliably for years.

Discussion