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 [email protected]
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 "[email protected]"
ssh-copy-id [email protected]
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.