Hosting

Best VPS for a WireGuard VPN Server, and How to Set It Up

What a WireGuard VPN server really needs from a VPS (traffic, location and a clean IP, not a big CPU), how the cheap providers compare, and a tested script that sets up the server and adds each phone with a QR code.

A small VPS running a WireGuard VPN server, with phones connecting to it by QR code

A WireGuard VPN server is light. It runs inside the Linux kernel and is happy on the smallest VPS you can rent. That is why the “best VPS for a VPN” is rarely the one with the most CPU: what decides how good your VPN feels is how much traffic the plan includes, where the server is, and how clean its IP address is.

This guide shows what to look for, compares the cheap providers, and then gives you two tested scripts: one that sets up the WireGuard server, and one that adds a phone or laptop and shows a QR code to scan.

What a VPN server needs from a VPS

NeedWhy it mattersEnough for a personal VPN
Monthly trafficEverything your devices download passes through the server and leaves it again. Video uses 1 to 3 GB an hour.500 GB to 1 TB a month
LocationA server near you is faster. A server in another country gives you that country's IP address.The country you want to appear in
A clean IPv4 addressSome cloud IP ranges get extra captchas or are blocked by streaming sites.A normal IPv4 address (not IPv6 only)
UDP and a firewall you controlWireGuard uses one UDP port. You must be able to open it.UDP 51820 open
CPU and memoryWireGuard is very efficient; a small server reaches hundreds of megabits.1 vCPU, 512 MB to 1 GB RAM
Terms of serviceA private VPN is allowed almost everywhere. A public VPN for app users brings abuse reports (torrents, copyright notices), and some providers suspend for that.Read the acceptable use policy

Cheap VPS options compared

These are the usual choices for a WireGuard server. There are no affiliate links on this page.

ProviderCheapest useful planTraffic includedGood to know
Oracle Cloud Free TierFree: an Arm server with up to 2 cores and 12 GB, or two small AMD servers10 TB a monthFree for good, but servers are often “out of capacity” and the setup has a firewall trap. See our Oracle Cloud free VPS guide.
Hetzner Cloud (CX23)About €4 to €6 a month (prices rose twice in 2026)20 TB in Europe, about 1 TB in the USThe most traffic for the money in Europe. Strict about abuse reports.
DigitalOcean$4 a month, 512 MB500 GBSimple panel, many locations
Vultr$5 a month, 1 GB1 TBMany countries. The $2.50 plan is IPv6 only, which is not enough for a VPN.
Akamai (Linode) Nanode$5 a month, 1 GB1 TBReliable network, simple pricing

Prices as listed in October 2026; check the provider's own page before you buy. For yourself and your family, the free Oracle server or any $4 to $5 plan is plenty. For a VPN app with many users, traffic is the real cost: pick plans with many terabytes included, and put servers in several countries.

Set up the server with one script

  1. Create a VPS with Ubuntu 24.04 (Ubuntu 22.04 and Debian 12 work too).
  2. In the provider's control panel, open UDP port 51820 in its firewall, if it has one.
  3. Log in with SSH, save the script below as wg-setup.sh (for example with nano wg-setup.sh), and run sudo bash wg-setup.sh.
#!/bin/bash
# WireGuard VPN server for Ubuntu 22.04 / 24.04 or Debian 12.
# Run once as root:  sudo bash wg-setup.sh
set -euo pipefail

PORT=51820                # the UDP port phones connect to
NET=10.8.0                # tunnel addresses: the server is .1, devices get .2, .3 ...
DNS="1.1.1.1, 1.0.0.1"    # DNS servers the devices use inside the tunnel

[ "$(id -u)" -eq 0 ] || { echo "Run it as root: sudo bash $0"; exit 1; }
[ -f /etc/wireguard/wg0.conf ] && { echo "/etc/wireguard/wg0.conf already exists. Add devices with wg-add-client.sh"; exit 1; }

apt-get update
apt-get install -y wireguard qrencode iptables curl

# The network card that leads to the internet (eth0, ens3, enp0s6 ...)
WAN=$(ip -4 route show default | awk '{print $5; exit}')
# The public IP, asked from outside: on Oracle, AWS and Google Cloud it is not on the network card
IP=$(curl -4 -fsS https://api.ipify.org) || { echo "Could not read the public IP. Check the internet connection."; exit 1; }

mkdir -p /etc/wireguard/clients
chmod 700 /etc/wireguard
cd /etc/wireguard
umask 077
wg genkey > server.key
wg pubkey < server.key > server.pub

# Rules are inserted at the top (-I), so a REJECT rule further down cannot block them
cat > wg0.conf <<EOF
[Interface]
Address = $NET.1/24
ListenPort = $PORT
PrivateKey = $(cat server.key)
PostUp = iptables -I INPUT 1 -p udp --dport $PORT -j ACCEPT; iptables -I FORWARD 1 -i wg0 -j ACCEPT; iptables -I FORWARD 1 -o wg0 -j ACCEPT; iptables -t nat -A POSTROUTING -s $NET.0/24 -o $WAN -j MASQUERADE
PostDown = iptables -D INPUT -p udp --dport $PORT -j ACCEPT; iptables -D FORWARD -i wg0 -j ACCEPT; iptables -D FORWARD -o wg0 -j ACCEPT; iptables -t nat -D POSTROUTING -s $NET.0/24 -o $WAN -j MASQUERADE
EOF

# Values the add-client script reads
printf 'IP=%s\nPORT=%s\nNET=%s\nDNS="%s"\n' "$IP" "$PORT" "$NET" "$DNS" > server.env

# Let the server pass traffic from the tunnel to the internet
echo 'net.ipv4.ip_forward = 1' > /etc/sysctl.d/99-wireguard.conf
sysctl --system > /dev/null

if command -v ufw > /dev/null && ufw status | grep -q 'Status: active'; then
  ufw allow "$PORT/udp"
fi

systemctl enable --now wg-quick@wg0
echo "WireGuard is running on $IP, UDP port $PORT (network card $WAN)."
echo "Add a device:  sudo bash wg-add-client.sh phone1"
PartWhat it does
ip -4 route show defaultFinds the network card that leads to the internet. It is not always eth0: Oracle uses names like enp0s6, others ens3.
curl ... api.ipify.orgReads the public IP from outside. On Oracle, AWS and Google Cloud the public IP is not on the network card, so reading it locally gives the wrong address.
wg genkey, wg pubkeyThe server's private key stays on the server; the public key goes into every device's file.
iptables -I ... 1The rules are inserted at the top. Some images (Oracle's Ubuntu, for one) end their rules with a REJECT; rules added at the end would never be reached.
MASQUERADEDevices' traffic leaves the server with the server's IP, which is what makes it a VPN.
net.ipv4.ip_forward = 1Lets Linux pass traffic from the tunnel to the internet. Without it, devices connect but nothing loads.
server.envSaves the IP, port and DNS for the second script.

Add a phone with a QR code

Save this as wg-add-client.sh next to the first script. Run it once per device with a name, for example sudo bash wg-add-client.sh phone1:

#!/bin/bash
# Add a phone or computer to the WireGuard server.
# Usage:  sudo bash wg-add-client.sh phone1
set -euo pipefail

NAME=${1:-}
[[ $NAME =~ ^[A-Za-z0-9_-]+$ ]] || { echo "Give a name of letters, numbers, - or _ :  sudo bash $0 phone1"; exit 1; }

cd /etc/wireguard
source ./server.env
umask 077
[ -f "clients/$NAME.conf" ] && { echo "clients/$NAME.conf already exists"; exit 1; }

# The first free address: .2, .3 ... (.1 is the server)
N=""
for i in $(seq 2 254); do
  grep -q "AllowedIPs = $NET.$i/32" wg0.conf || { N=$i; break; }
done
[ -n "$N" ] || { echo "No free addresses left in $NET.0/24"; exit 1; }

KEY=$(wg genkey)
PUB=$(echo "$KEY" | wg pubkey)
PSK=$(wg genpsk)

# Add the device to the server. It is saved in wg0.conf, so it survives a restart.
cat >> wg0.conf <<EOF

[Peer]
# $NAME
PublicKey = $PUB
PresharedKey = $PSK
AllowedIPs = $NET.$N/32
EOF
wg syncconf wg0 <(wg-quick strip wg0)

# The device's own config file
cat > "clients/$NAME.conf" <<EOF
[Interface]
PrivateKey = $KEY
Address = $NET.$N/32
DNS = $DNS
MTU = 1280

[Peer]
PublicKey = $(cat server.pub)
PresharedKey = $PSK
Endpoint = $IP:$PORT
AllowedIPs = 0.0.0.0/0
PersistentKeepalive = 25
EOF

qrencode -t ansiutf8 < "clients/$NAME.conf"
echo "Saved /etc/wireguard/clients/$NAME.conf ($NET.$N). Scan the code above in the WireGuard app."

On the phone, install the official WireGuard app (Android or iPhone), tap +, choose Scan from QR code and point the camera at the code in your terminal. On a computer, copy the file from /etc/wireguard/clients/ and import it in the WireGuard app.

PartWhat it does
The loop over .2 to .254Gives each device the first free address, so every device has its own
wg genpskA preshared key: an extra secret on top of the key pair, for each device
wg syncconfAdds the device to the running server without cutting the others off
MTU = 1280Mobile networks often drop large packets; a smaller MTU avoids “connected but no internet”
PersistentKeepalive = 25Keeps the connection alive behind mobile and home routers
qrencode -t ansiutf8Draws the device's file as a QR code right in the terminal

Check that it works

Turn the VPN on in the app and open any “what is my IP” page: it should show your server's IP. On the server:

# On the server: every device, its last handshake and how much it has used
sudo wg show

# The server's public IP, to compare with what the phone shows
curl -4 https://api.ipify.org

A recent latest handshake and growing transfer numbers mean the device is connected and using the tunnel. To take a device off the server:

# Remove a device: its public key is in /etc/wireguard/wg0.conf, under its name
sudo wg set wg0 peer 'THE-DEVICE-PUBLIC-KEY=' remove
# Then delete its [Peer] block from wg0.conf and its file in /etc/wireguard/clients/

Common problems

ProblemCause and fix
No handshake in wg showUDP 51820 is closed in the provider's firewall (the panel, not the server), or the device's file has the wrong IP. On Oracle, also check the security list.
Connected, but nothing loadsForwarding is off, or the network card name is wrong. Check sysctl net.ipv4.ip_forward and the -o name in wg0.conf.
Works on Wi-Fi, not on mobile dataUsually the MTU (it is already 1280 here). Some mobile and office networks block UDP: then you need OpenVPN on TCP 443.
Slow speedThe server is far from you, or the cheap plan shares its CPU heavily. Try a server in a nearer location.
Streaming sites block youThat data centre's IP range is known as a server range. Try another provider or location.
Nothing works after a rebootCheck systemctl status wg-quick@wg0; the script enables it, so it should start by itself.

From one server to a VPN app with many users

The scripts above are right for you and your family, where you scan each QR code yourself. A VPN app that strangers download from Google Play needs a different setup:

  • Devices register themselves. Each phone makes its own key pair and sends only the public key to your server, which hands out an address and adds it automatically. Nobody scans anything.
  • An IP pool bigger than 254 devices. One /24 network runs out fast, so you need several pools or a larger range, and a way to free addresses of devices that never come back.
  • A server list. The app downloads a list of servers in several countries from your website, so you add a server without updating the app.
  • Traffic and abuse. You watch traffic per server, spread users over servers, and deal with abuse reports before the provider suspends you.

Building and testing that part takes weeks.

The finished version: our VPN app source code

Our Android VPN app source code is that many-user setup, finished:

  • Kotlin and Jetpack Compose, with WireGuard and OpenVPN servers in one list and one-tap connect
  • A key pair made on each phone, and a registration script that gives each device an address from your IP pool
  • A server script that adds the registered devices to WireGuard automatically
  • The server list loaded from your own website, so new servers need no app update
  • Free VPN Gate OpenVPN servers with an update script, for a VPN that works before you rent any server
  • A speed test, AdMob and Firebase, ready to reskin and publish

If you would rather use SSTP, the secure VPN proxy app connects to SSTP servers listed in a JSON file on your website.

Where to go next

Questions people ask

What is the best VPS for a WireGuard VPN server?
One with enough monthly traffic, a location near you or in the country you want to appear in, and a normal IPv4 address. CPU matters little: WireGuard runs well on 1 vCPU and 512 MB to 1 GB of RAM. Oracle's free tier, Hetzner, DigitalOcean, Vultr and Akamai are common choices.
How much RAM does a WireGuard server need?
Very little. WireGuard runs inside the Linux kernel, so a server with 512 MB to 1 GB of RAM handles a family or a small group easily. Traffic and network speed run out long before memory does.
How much bandwidth does a VPN use?
Everything the devices download passes through the server. Browsing uses little, but video uses 1 to 3 GB an hour, so one person often uses 50 to 150 GB a month. A plan with 500 GB to 1 TB is enough for personal use; an app with many users needs many terabytes.
Can I run a WireGuard VPN on a free VPS?
Yes. Oracle Cloud's free tier includes servers that are free for good, with 10 TB of outbound traffic a month. Free servers are often out of capacity, and Oracle's Ubuntu image blocks ports with its own firewall rules, so follow a guide made for it.
Which port does WireGuard use?
Any UDP port you choose; 51820 is the usual one. Open it in the VPS provider's firewall and on the server. WireGuard does not use TCP.
How many devices can one WireGuard server handle?
A /24 tunnel network gives 253 device addresses; larger ranges give thousands. In practice the limit is the server's network speed and traffic allowance, not WireGuard itself.
Why does my WireGuard VPN connect but no websites load?
IP forwarding is off, the network card name in the NAT rule is wrong, or the MTU is too big. Check net.ipv4.ip_forward, the -o name in wg0.conf, and set MTU = 1280 in the device's file.
Is it allowed to run a VPN on a VPS?
A private VPN for yourself is allowed by almost every provider. Running a public VPN service brings abuse reports such as copyright notices, so read the provider's acceptable use policy before you sell VPN access or publish a VPN app.
Is my own VPN on a VPS private?
Your internet provider only sees encrypted WireGuard traffic to your server. The websites see your server's IP. The VPS provider can see where the traffic goes after it leaves the server, so pick a provider you trust.
Should I use WireGuard or OpenVPN on my VPS?
WireGuard for speed, battery life and simple setup. Keep OpenVPN on TCP 443 as a second option for networks that block UDP, such as some offices and mobile networks.

Written by Habib Baloch

I build Android apps, websites and Ubuntu servers, and write down exactly how I did it.

Ask me about this guide →