Mahbubur Riad
Back to blog
Hosting & Server 8 min read

Zero‑Trust Remote Access on a $5 VPS: Deploying WireGuard, OpenVPN, and Cloudflare Access

Jun 16, 2026 · Mahbubur Riad

Learn how to build a budget‑friendly Zero‑Trust remote access gateway on a $5 VPS using WireGuard, OpenVPN and Cloudflare Access – step‑by‑step with code, comparison and FAQ.

On this page

Zero‑Trust Remote Access on a $5 VPS

If you’re tired of cheap SSH tunnels that leak credentials, and you don’t want to pay a premium for a managed Zero‑Trust service, you can build your own gateway for under five dollars a month. This guide walks you through WireGuard, OpenVPN and Cloudflare Access, shows how they fit together, and gives you a practical checklist you can copy‑paste into your next VPS.


Why a $5 VPS Makes Sense for Zero‑Trust

Reason What it means for you
Cost Most cloud providers (DigitalOcean, Linode, Hetzner) offer a 1 CPU/1 GB RAM droplet for $5/month. That’s cheap enough to spin up a test environment without breaking the budget.
Control You own the OS, the firewall, the keys – no hidden back‑doors.
Scalability When traffic grows you can upgrade the droplet or add a second node without re‑architecting the tunnel.
Zero‑Trust compatibility All three tunnel options (WireGuard, OpenVPN, Cloudflare Access) support modern authentication methods (OIDC, SSO, short‑lived certs).

A $5 VPS is not a silver bullet – you still need to secure the host, keep it patched, and monitor traffic. The sections below assume a fresh Ubuntu 22.04 LTS install.


Prerequisites

  • A $5 VPS with root access (Ubuntu 22.04 LTS recommended).
  • A domain name you control (e.g., example.com).
  • Cloudflare account with the domain added and DNS managed by Cloudflare.
  • Basic familiarity with Linux CLI, ssh, and editing text files.
  • Optional but recommended: a secondary device for testing (your laptop, phone, etc.).

1. Prepare the VPS

Bash
# 1️⃣ Update the system
sudo apt update && sudo apt upgrade -y

# 2️⃣ Install essential tools
sudo apt install -y curl gnupg2 ca-certificates lsb-release ufw

# 3️⃣ Harden the firewall – we’ll only allow SSH (22) and the tunnel ports later.
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow 22/tcp   # SSH
sudo ufw enable

Tip: Keep a second SSH session open while you test firewall changes. If you lock yourself out, you can revert with the other session.


2. WireGuard – The Fast, Modern Option

2.1 Install WireGuard

Bash
sudo apt install -y wireguard

2.2 Generate Server Keys

Bash
# Create a dedicated wg0 config directory
sudo mkdir -p /etc/wireguard/keys
sudo chmod 700 /etc/wireguard/keys

# Server private & public key
wg genkey | sudo tee /etc/wireguard/keys/server_private.key | wg pubkey | sudo tee /etc/wireguard/keys/server_public.key

2.3 Server Configuration (/etc/wireguard/wg0.conf)

INI
[Interface]
# Private key generated above
PrivateKey = <$(sudo cat /etc/wireguard/keys/server_private.key)>
Address = 10.10.0.1/24
ListenPort = 51820
# Optional: keepalive for NAT traversal
PostUp = ufw allow 51820/udp
PostDown = ufw delete allow 51820/udp

# Example client – you’ll add more later
#[Peer]
#PublicKey = <client_public_key>
#AllowedIPs = 10.10.0.2/32

Replace <$(sudo cat …)> with the actual key or use command substitution when creating the file programmatically.

2.4 Enable IP Forwarding & Start WireGuard

Bash
# Enable routing
echo "net.ipv4.ip_forward=1" | sudo tee -a /etc/sysctl.conf
echo "net.ipv6.conf.all.forwarding=1" | sudo tee -a /etc/sysctl.conf
sudo sysctl -p

# Start the interface
sudo systemctl enable wg-quick@wg0
sudo systemctl start wg-quick@wg0

2.5 Create a Client Profile

On your laptop (or any device that will connect):

Bash
# Generate client keys locally
wg genkey | tee client_private.key | wg pubkey > client_public.key

# Build the .conf file
cat <<EOF > client-wg0.conf
[Interface]
PrivateKey = $(cat client_private.key)
Address = 10.10.0.2/32
DNS = 1.1.1.1

[Peer]
PublicKey = $(sudo cat /etc/wireguard/keys/server_public.key)
Endpoint = vpn.example.com:51820   # We'll create a DNS record later
AllowedIPs = 0.0.0.0/0, ::/0
PersistentKeepalive = 25
EOF

Import client-wg0.conf into the WireGuard client app (Linux, macOS, iOS, Android). You now have a fast, UDP‑based tunnel.


3. OpenVPN – The Compatibility Workhorse

WireGuard is great, but some legacy devices (older Android, certain corporate firewalls) only speak OpenVPN. Let’s set it up side‑by‑side.

3.1 Install OpenVPN and Easy‑RSA

Bash
sudo apt install -y openvpn easy-rsa

3.2 Create PKI Directory

Bash
make-cadir ~/openvpn-ca
cd ~/openvpn-ca
./easyrsa init-pki

3.3 Build CA and Server Certs

Bash
# Build a new CA (no password for automation)
./easyrsa --batch build-ca nopass

# Server certificate & key
./easyrsa build-server-full server nopass

# Diffie‑Hellman parameters (required for TLS)
./easyrsa gen-dh

3.4 Generate Client Certs (repeat for each client)

Bash
./easyrsa build-client-full client1 nopass

3.5 Server Config (/etc/openvpn/server.conf)

CONF
port 1194
proto udp
dev tun
ca /home/ubuntu/openvpn-ca/pki/ca.crt
cert /home/ubuntu/openvpn-ca/pki/issued/server.crt
key /home/ubuntu/openvpn-ca/pki/private/server.key
dh /home/ubuntu/openvpn-ca/pki/dh.pem
auth SHA256
cipher AES-256-GCM
persist-key
persist-tun
user nobody
group nogroup
push "redirect-gateway def1 bypass-dhcp"
push "dhcp-option DNS 1.1.1.1"
keepalive 10 120
verb 3
status /var/log/openvpn-status.log
log-append /var/log/openvpn.log

3.6 Enable IP Forwarding & Firewall Rules

Bash
sudo sysctl -w net.ipv4.ip_forward=1
sudo ufw allow 1194/udp
# NAT for VPN traffic
sudo iptables -t nat -A POSTROUTING -s 10.8.0.0/24 -o eth0 -j MASQUERADE
sudo iptables-save | sudo tee /etc/iptables.rules

Create a systemd service to restore iptables on boot (optional).

3.7 Start OpenVPN

Bash
sudo systemctl enable openvpn-server@server
sudo systemctl start openvpn-server@server

3.8 Export Client .ovpn File

Bash
cat > client1.ovpn <<EOF
client
dev tun
proto udp
remote vpn.example.com 1194
resolv-retry infinite
nobind
persist-key
persist-tun
remote-cert-tls server
auth SHA256
cipher AES-256-GCM
verb 3
<ca>
$(cat ~/openvpn-ca/pki/ca.crt)
</ca>
<cert>
$(cat ~/openvpn-ca/pki/issued/client1.crt)
</cert>
<key>
$(cat ~/openvpn-ca/pki/private/client1.key)
</key>
EOF

Import client1.ovpn into any OpenVPN client.


4. Cloudflare Access – Adding Zero‑Trust Policies

Both WireGuard and OpenVPN give you an encrypted tunnel, but they don’t enforce who can log in. Cloudflare Zero‑Trust (formerly Access) adds identity‑aware policies, short‑lived tokens, and audit logs.

4.1 Create a Cloudflare Tunnel (Optional – we’ll use DNS only)

If you prefer Cloudflare to terminate TLS before the tunnel, you can create a Cloudflare Tunnel that forwards to 127.0.0.1:51820 (WireGuard) or 127.0.0.1:1194 (OpenVPN). For a $5 VPS we’ll skip the extra tunnel process and let Cloudflare handle the access layer only.

4.2 Add a DNS Record for the VPN Endpoint

In Cloudflare DNS:

  • Type: A
  • Name: vpn
  • Content: Your VPS public IP
  • Proxy status: DNS only (orange cloud off – we don’t want Cloudflare proxy for UDP ports).

4.3 Configure Cloudflare Access Application

  1. NavigateZero TrustAccessApplicationsAdd an application.
  2. Name: WireGuard VPN (or OpenVPN).
  3. Domain: vpn.example.com.
  4. Session duration: 12h (or shorter for higher security).
  5. Policies: Click Add a policyIncludeEmails → add your corporate or personal email addresses. Optionally add Identity Providers (Google, Azure AD, GitHub).
  6. Save.

Cloudflare now issues a signed JWT that the client presents before the tunnel is allowed.

4.4 Enforcing the JWT on the Server

Both WireGuard and OpenVPN can verify the token via a simple script that runs on connection.

WireGuard – Using wg-quick Pre‑Up Hook

Bash
# /etc/wireguard/check_jwt.sh
#!/usr/bin/env bash
# Expect the token as the first argument (passed via environment variable by client)
TOKEN="$CF_ACCESS_JWT"
if [[ -z "$TOKEN" ]]; then
  echo "[ERROR] No Cloudflare JWT provided"
  exit 1
fi
# Verify against Cloudflare's public keys (cached)
curl -s https://<team-id>.cloudflareaccess.com/cdn-cgi/access/certs > /tmp/cf_certs.pem
if ! echo "$TOKEN" | jwt verify -k /tmp/cf_certs.pem -a "<team-id>"; then
  echo "[ERROR] JWT verification failed"
  exit 1
fi
exit 0

Make it executable: sudo chmod +x /etc/wireguard/check_jwt.sh

Add to wg0.conf:

INI
PostUp = /etc/wireguard/check_jwt.sh

Note: The client must export CF_ACCESS_JWT before bringing up WireGuard. Most GUI clients don’t support env vars, so a more practical approach is to wrap the wg-quick up command in a wrapper script that fetches the token via Cloudflare Access API.

OpenVPN – Using auth-user-pass-verify

Create a script /etc/openvpn/verify_jwt.sh:

Bash
#!/usr/bin/env bash
TOKEN="$1"
# Download Cloudflare certs (once a day recommended)
if [ ! -f /etc/openvpn/cf_certs.pem ]; then
  curl -s https://<team-id>.cloudflareaccess.com/cdn-cgi/access/certs > /etc/openvpn/cf_certs.pem
fi
# Verify JWT – using `jwt-cli` (install via pip)
if ! echo "$TOKEN" | jwt verify -k /etc/openvpn/cf_certs.pem -a "<team-id>"; then
  echo "auth-failure" > /dev/null
  exit 1
fi
exit 0

Add to server.conf:

CONF
plugin /usr/lib/openvpn/openvpn-plugin-auth-pam.so openvpn
auth-user-pass-verify /etc/openvpn/verify_jwt.sh via-env
script-security 3

Now OpenVPN will only allow connections that present a valid Cloudflare JWT.


5. Comparison – WireGuard vs OpenVPN vs Cloudflare Tunnel

Feature WireGuard OpenVPN Cloudflare Tunnel (managed)
Performance 30‑40 % lower latency, ~1 Gbps on cheap CPUs Good but CPU‑heavy AES, ~300‑500 Mbps Cloudflare edge acceleration, but extra hop adds latency
Ease of Setup 15 min (single config) 45 min (PKI, scripts) 10 min (cloud UI)
Client Compatibility Modern OSes, mobile apps; older devices need third‑party client Broad – Windows, macOS, Linux, iOS, Android, many routers Browser‑only or Cloudflare WARP client
Zero‑Trust Integration Requires custom script (as shown) Requires script or auth‑plugin Built‑in policy engine
Port Usage UDP 51820 (can be blocked) UDP 1194 (or TCP) HTTPS 443 (always open)
Cost $5 / mo VPS + Cloudflare free tier $5 / mo VPS + Cloudflare free tier $5 / mo VPS or Cloudflare paid plan for high‑scale
Audit & Logging Manual (syslog) Built‑in status logs Cloudflare logs & SIEM integration

Bottom line: If you control the client environment and need raw speed, WireGuard wins. If you need legacy support or a single‑sign‑on experience without extra scripting, OpenVPN plus Cloudflare Access is a solid compromise. Cloudflare Tunnel alone is the fastest way to get Zero‑Trust without self‑hosting, but you lose the $5‑VPS cost‑saving.


6. Full Checklist – Deploy Your Own Zero‑Trust VPN

  • Provision a $5 VPS (Ubuntu 22.04 LTS) and secure SSH.
  • Set up UFW – allow only 22, 51820/udp (WireGuard), 1194/udp (OpenVPN).
  • Install WireGuard and generate server/client keys.
  • Create wg0.conf, enable IP forwarding, start the service.
  • Test WireGuard from a client device.
  • Install OpenVPN & Easy‑RSA, build CA, server, and client certs.
  • Configure server.conf, enable NAT, start OpenVPN.
  • Export client .ovpn and test connectivity.
  • Add DNS record vpn.example.com in Cloudflare (DNS‑only).
  • Create Cloudflare Access application for the VPN domain.
  • Write JWT verification scripts for WireGuard and OpenVPN.
  • Wrap client start‑up to fetch a Cloudflare JWT (CLI cloudflare access login or API).
  • Monitor logs (journalctl -u wg-quick@wg0, openvpn-status.log).
  • Set up daily cron to refresh Cloudflare cert bundle.
  • Document credentials in a secure vault (e.g., Bitwarden).

7. FAQ

1. Do I really need Cloudflare Access if I already have a VPN?

Zero‑Trust adds identity verification, short‑lived tokens, and audit trails. A VPN alone trusts anyone who has the key or certificate. Adding Cloudflare Access means a compromised key is useless without a valid JWT.

2. Can I run both WireGuard and OpenVPN on the same VPS without port conflict?

Yes. WireGuard uses UDP 51820 by default, OpenVPN uses UDP 1194 (or TCP 443 if you change it). Just keep the firewall rules separate and ensure IP forwarding is enabled for both subnets (10.10.0.0/24 and 10.8.0.0/24).

3. What happens if my ISP blocks UDP?

Switch OpenVPN to TCP 443 (or any allowed port). Performance will drop but the tunnel stays reachable. WireGuard currently only supports UDP, so you’d need to fall back to OpenVPN or use Cloudflare WARP which tunnels over HTTPS.

4. How do I rotate WireGuard keys without breaking existing clients?

Generate a new key pair, add a new [Peer] block for each client with the old public key, then update the client config with the new private key. Once all clients have migrated, remove the old [Peer] entries.

5. Is the $5 VPS enough for multiple simultaneous remote users?

For light office use (5‑10 concurrent users) the 1 CPU/1 GB combo handles WireGuard comfortably. OpenVPN is more CPU‑intensive; you may hit the CPU ceiling around 5‑7 active streams. Monitor htop and consider upgrading to the $10 plan if you need headroom.


8. Wrap‑Up

You now have a fully functional, budget‑friendly Zero‑Trust remote‑access gateway. Whether you choose WireGuard for raw speed, OpenVPN for broad compatibility, or a hybrid with Cloudflare Access for policy enforcement, the core pieces live on a $5 VPS you control end‑to‑end.

Remember to keep the host patched, rotate keys regularly, and review Cloudflare Access policies whenever team members join or leave. The combination of a tiny VPS, open‑source tunneling, and Cloudflare’s identity layer gives you enterprise‑grade security without the enterprise price tag.

Happy tunneling!
Your fellow sysadmin

For more hands‑on guides and deeper dives, visit mahbuburriad.com.

Related

Related posts