Hosting Your Own VPN on a £1 VPS

I’ve long been a fan of self-hosted infrastructure, but until recently, my VPNs were always built for internal access. This time, I decided to go a step further, building my own personal VPN server for privacy and IP/location masking.

RackNerd recently dropped a £1/month VPS deal via LowEndBox (not sponsored), and I couldn’t resist the temptation to spin something up.

VPS Specs

Here’s what you get for just over a tenner per year:

1x vCPU Core

1GB RAM

20GB SSD Storage

2TB Bandwidth

1Gbps Port

Dedicated IPv4

Full Root Access

KVM Virtualisation

This setup is more than enough to run a lean, secure WireGuard VPN.

Quick Setup Guide

1. SSH In & Update

ssh root@your.server.ip
passwd # change root password
apt-get update && apt-get upgrade -y

2. Install Docker & Docker Compose

apt-get install -y ca-certificates curl gnupg lsb-release

mkdir -p /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/$(. /etc/os-release; echo "$ID")/gpg | gpg --dearmor -o /etc/apt/keyrings/docker.gpg

echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/$(. /etc/os-release; echo "$ID") \
$(lsb_release -cs) stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null

apt-get update
apt-get install -y docker-ce docker-ce-cli containerd.io

# Install Docker Compose
curl -L "https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
chmod +x /usr/local/bin/docker-compose

docker --version
docker-compose --version

Set Up SSH Key Auth

On your local machine:

ssh-keygen -t rsa -b 4096 -C "your_email@example.com"
ssh-copy-id root@your.server.ip

Or do it manually if ssh-copy-id isn’t available.

Then disable password auth on the server:

nano /etc/ssh/sshd_config

Make sure these lines are set:

PermitRootLogin yes
PasswordAuthentication no
ChallengeResponseAuthentication no
UsePAM no

Restart SSH:

systemctl restart ssh

Test your key login before closing your current session!

Deploy WireGuard with wg-easy

First, generate a secure password hash:

docker run ghcr.io/wg-easy/wg-easy wgpw 'YOUR_PASSWORD'

Take note of the hash output, remember to double all dollar signs ($$) when pasting into docker-compose.yml as per below.

Sample docker-compose.yml

volumes:
etc_wireguard:

services:
wg-easy:
image: ghcr.io/wg-easy/wg-easy
container_name: wg-easy
environment:
- LANG=en
- WG_HOST=YOUR_SERVER_IP
- PASSWORD_HASH=$$2a$$12$$abc123... # use your generated hash
- WG_PORT=51820
- WG_DEFAULT_ADDRESS=10.8.0.x
- WG_DEFAULT_DNS=8.8.8.8,1.1.1.1
- WG_MTU=1420
- WG_ALLOWED_IPS=0.0.0.0/0
- WG_PERSISTENT_KEEPALIVE=25
- UI_TRAFFIC_STATS=true
- UI_CHART_TYPE=2
volumes:
- etc_wireguard:/etc/wireguard
ports:
- "51820:51820/udp"
- "51821:51821/tcp"
restart: always
cap_add:
- NET_ADMIN
- SYS_MODULE
sysctls:
- net.ipv4.ip_forward=1
- net.ipv4.conf.all.src_valid_mark=1

Start the container:

docker-compose up -d

Enable IP Forwarding

echo 1 > /proc/sys/net/ipv4/ip_forward
echo "net.ipv4.ip_forward=1" >> /etc/sysctl.conf
sysctl -p

Set Up NAT (Masquerading)

iptables -t nat -A POSTROUTING -s 10.8.0.0/24 -o eth0 -j MASQUERADE

Persist iptables rules:

mkdir -p /etc/iptables
iptables-save > /etc/iptables/rules.v4

crontab -e

Add:

@reboot iptables-restore < /etc/iptables/rules.v4

Result: Your Own Private VPN

At this point, you’ve got a fully functioning WireGuard VPN that routes all your internet traffic via your VPS and hides your IP and location.

Manage it via a web UI (http://your.server.ip:51821) to create clients as described in my other post.

Minimal resources, maximum control.