VPN Configuration for Secure Remote Access to Your Homelab
We earn commissions when you shop through the links on this page, at no additional cost to you. Learn more.
When I first started managing my homelab remotely, I made the mistake of exposing services directly to the internet with just basic authentication. Within hours, my logs filled with brute-force attempts. That's when I realized: a good VPN setup isn't optional—it's foundational. This guide covers three proven approaches I've used in production: WireGuard for speed and simplicity, OpenVPN for compatibility, and Tailscale for zero-config magic. I'll show you exactly how to deploy each, with security hardening baked in from the start.
Why VPN Over Port Forwarding?
I prefer VPN to reverse proxies for homelab access because it creates an encrypted tunnel that hides your entire infrastructure from the internet. Port forwarding exposes individual services—even behind authentication, it's still a public target. A VPN lets you access your homelab like you're on the local network, without broadcasting your IP or service types.
The tradeoff: VPN adds latency and requires client software on every device. Reverse proxies are simpler for public services (like a blog), but for homelab administration? VPN wins every time.
Option 1: WireGuard—Fast and Lean
I chose WireGuard for my primary setup because it's a ~600-line kernel module versus OpenVPN's 100,000 lines. It's faster, simpler to audit, and uses modern cryptography by default (ChaCha20, Poly1305, Curve25519).
You can run WireGuard on a cheap VPS (around $40/year from RackNerd or similar providers) or on your router if you're comfortable with it. I recommend the VPS approach for uptime: your homelab can go offline without losing remote access.
Setting Up WireGuard Server on Ubuntu 22.04
#!/bin/bash
# Install WireGuard
sudo apt update
sudo apt install -y wireguard wireguard-tools
# Enable IP forwarding (critical for VPN 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
# Generate server keys
cd /etc/wireguard
umask 077
wg genkey | tee privatekey | wg pubkey > publickey
# Display keys for reference
echo "=== Server Private Key ==="
cat privatekey
echo ""
echo "=== Server Public Key ==="
cat publickey
Now create the WireGuard configuration file:
sudo cat > /etc/wireguard/wg0.conf << 'EOF'
[Interface]
# Your VPS public IP (replace with actual IP)
Address = 10.0.0.1/24
ListenPort = 51820
PrivateKey = YOUR_SERVER_PRIVATE_KEY_HERE
PostUp = iptables -A FORWARD -i %i -j ACCEPT; iptables -A FORWARD -o %i -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
PostDown = iptables -D FORWARD -i %i -j ACCEPT; iptables -D FORWARD -o %i -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE
# Client 1: Desktop
[Peer]
PublicKey = CLIENT1_PUBLIC_KEY
AllowedIPs = 10.0.0.2/32
# Client 2: Laptop
[Peer]
PublicKey = CLIENT2_PUBLIC_KEY
AllowedIPs = 10.0.0.3/32
# Client 3: Phone
[Peer]
PublicKey = CLIENT3_PUBLIC_KEY
AllowedIPs = 10.0.0.4/32
EOF
Start WireGuard:
sudo systemctl enable wg-quick@wg0
sudo systemctl start wg-quick@wg0
sudo wg show # Verify it's running
# Open the firewall port
sudo ufw allow 51820/udp
sudo ufw enable
Generating Client Configs
For each client device, generate a keypair and add it to the server config:
#!/bin/bash
# Run this locally on your client machine, or on the VPS for distribution
CLIENT_NAME="desktop"
cd /tmp
umask 077
wg genkey | tee ${CLIENT_NAME}_privatekey | wg pubkey > ${CLIENT_NAME}_publickey
cat > ${CLIENT_NAME}.conf << EOF
[Interface]
Address = 10.0.0.2/32
PrivateKey = $(cat ${CLIENT_NAME}_privatekey)
DNS = 8.8.8.8, 8.8.4.4
[Peer]
PublicKey = YOUR_SERVER_PUBLIC_KEY_HERE
Endpoint = YOUR_VPS_IP:51820
AllowedIPs = 10.0.0.0/24, 192.168.1.0/24
PersistentKeepalive = 25
EOF
echo "Client config generated: ${CLIENT_NAME}.conf"
echo ""
echo "=== Add this to server wg0.conf [Peer] section ==="
echo "[Peer]"
echo "PublicKey = $(cat ${CLIENT_NAME}_publickey)"
echo "AllowedIPs = 10.0.0.2/32"
AllowedIPs = 10.0.0.0/24, 192.168.1.0/24 on clients to route both VPN subnet and your home network through the tunnel. This assumes your homelab is on 192.168.1.0/24—adjust as needed.After generating client configs, restart the server to apply changes:
sudo systemctl restart wg-quick@wg0
Option 2: Tailscale—Zero Config, Cloud Magic
Tailscale abstracts away the complexity: no port forwarding, no key management, no IP addressing headaches. I use it for quick team access and non-critical services. The trade-off is vendor lock-in and a cloud control plane—but for $0 (personal tier), it's remarkable.
Install on your VPS or homelab server:
curl -fsSL https://tailscale.com/install.sh | sh
# Start the daemon
sudo systemctl start tailscaled
sudo systemctl enable tailscaled
# Authenticate (opens browser)
sudo tailscale up
# View your Tailscale IP
tailscale ip -4
Then install Tailscale on your client devices (phone, laptop, desktop) and authenticate. Within seconds, all devices can ping each other by hostname. Tailscale automatically configures firewall holes and handles NAT traversal.
To access your homelab services through Tailscale, just use the Tailscale IP of your server:
tailscale ip -4 # e.g., 100.123.45.67
# Then browser: http://100.123.45.67:8080 (Jellyfin, etc.)
Option 3: OpenVPN—Maximum Compatibility
OpenVPN works on ancient devices and is well-understood by most admins. I deploy it when I need to support legacy clients or team members on restrictive networks (some corporate firewalls block WireGuard UDP).
Quick OpenVPN server setup with EasyRSA:
sudo apt install -y openvpn easy-rsa
# Set up PKI
sudo mkdir -p /etc/openvpn/easy-rsa
cd /etc/openvpn/easy-rsa
sudo /usr/share/easy-rsa/easyrsa init-pki
sudo /usr/share/easy-rsa/easyrsa build-ca nopass
sudo /usr/share/easy-rsa/easyrsa gen-req server nopass
sudo /usr/share/easy-rsa/easyrsa sign-req server server
sudo /usr/share/easy-rsa/easyrsa gen-dh
# Copy certs to OpenVPN directory
sudo cp pki/ca.crt /etc/openvpn/
sudo cp pki/private/server.key /etc/openvpn/
sudo cp pki/issued/server.crt /etc/openvpn/
sudo cp pki/dh.pem /etc/openvpn/
# Generate client cert
sudo /usr/share/easy-rsa/easyrsa gen-req client nopass
sudo /usr/share/easy-rsa/easyrsa sign-req client client
Create server config:
sudo cat > /etc/openvpn/server.conf << 'EOF'
port 1194
proto udp
dev tun
ca ca.crt
cert server.crt
key server.key
dh dh.pem
server 10.8.0.0 255.255.255.0
push "route 192.168.1.0 255.255.255.0"
push "dhcp-option DNS 8.8.8.8"
push "dhcp-option DNS 8.8.4.4"
keepalive 10 120
comp-lz4
user nobody
group nogroup
persist-key
persist-tun
status /var/log/openvpn/status.log
verb 3
mute 20
EOF
sudo systemctl enable openvpn@server
sudo systemctl start openvpn@server
Security Hardening: Non-Negotiable Additions
Firewall Rules
On your VPS, restrict VPN access to SSH and essential ports:
sudo ufw default deny incoming
sudo ufw default allow outgoing
# Allow SSH (adjust port if using non-22)
sudo ufw allow 22/tcp
# Allow WireGuard (UDP 51820)
sudo ufw allow 51820/udp
# Allow OpenVPN (UDP 1194)
sudo ufw allow 1194/udp
# If running HTTP/HTTPS on VPS for web UI
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable
sudo ufw status
SSH Hardening
VPN doesn't protect SSH—lock it down:
sudo sed -i 's/#PermitRootLogin yes/PermitRootLogin no/' /etc/ssh/sshd_config
sudo sed -i 's/#PubkeyAuthentication yes/PubkeyAuthentication yes/' /etc/ssh/sshd_config
sudo sed -i 's/#PasswordAuthentication yes/PasswordAuthentication no/' /etc/ssh/sshd_config
sudo systemctl restart sshd
Fail2Ban for Brute-Force Protection
sudo apt install -y fail2ban
sudo cat > /etc/fail2ban/jail.local << 'EOF'
[DEFAULT]
bantime = 3600
findtime = 600
maxretry = 3
[sshd]
enabled = true
port = ssh
filter = sshd
logpath = /var/log/auth.log
EOF
sudo systemctl enable fail2ban
sudo systemctl restart fail2ban
Connecting From Home
On your home server/router running WireGuard or OpenVPN client:
# For WireGuard, install client and place config in /etc/wireguard/
sudo apt install -y wireguard wireguard-tools
sudo wg-quick up wg_client # if config is /etc/wireguard/wg_client.conf
# For OpenVPN
sudo apt install -y openvpn
# Place client.ovpn in /etc/openvpn/ and run:
sudo openvpn /etc/openvpn/client.ovpn &
Verify the tunnel is active:
ping 10.0.0.1 # WireGuard server IP
ping 10.8.0.1 # OpenVPN server IP
Keeping Keys Secure
Store private keys offline whenever possible. I keep backups encrypted with GPG:
gpg --symmetric --cipher-algo AES256 /etc/wireguard/privatekey
# Prompts for passphrase; creates privatekey.gpg
# Never store passphrases in scripts. Use a password manager (Bitwarden, 1Password, etc.)
Remote Access Workflow
Once set up, accessing your homelab is simple:
- Connect to VPN (WireGuard app or
wg-quick up) - Ping home server to verify tunnel
- Browse to internal services