Introduction
This guide shows you exactly how to do the same — the old-school, bulletproof way using SSH reverse tunnels.
No Cloudflare Tunnel. No Ngrok. Just SSH + systemd.
The Downsides (and Why They’re Manageable)
- Home internet isn’t datacenter-grade (outages happen)
- Most ISPs use CGNAT → you can’t open ports normally
Solution: Use a cheap VPS as a public “jump box”. Your heavy server stays home. The VPS only forwards ports.
How It Works – The Magic of Reverse SSH Tunnels (-R)
Internet → Cheap VPS (public IP) → SSH reverse tunnel → Your home server (behind CGNAT)
Your home server initiates an outbound SSH connection to the VPS and says:
“Anything that hits port 8096 on you → send it to my local Jellyfin on 8096”
Zero ports opened on your home router. Zero exposure.
## Step-by-Step Setup
### 1. On Your Home Server (the powerful one)
```bash
# Create folder for tunnel configs
sudo mkdir -p /etc/sshtunnels
# Example: expose Jellyfin (port 8096)
sudo nano /etc/sshtunnels/jellyfin.confContent of the file:
8096:8096 # remote_port:local_port
443:8443 # optional: HTTPS reverse proxy on VPS → your local 8443
80:8080One line per service. First number = port on the VPS, second = port on your home server.
2. Generate an SSH Key (if you don’t have one)
ssh-keygen -t ed25519 -C "home-server-tunnel"Copy the public key to your VPS:
ssh-copy-id user@your-vps-ip3. Create the Tunnel Manager Script
sudo nano /usr/local/bin/sshtunnel.sh#!/bin/bash
# === EDIT THESE ===
REMOTE_USER="root" # or your VPS user
REMOTE_HOST="123.45.67.89" # your VPS public IP
SSH_KEY="/home/youruser/.ssh/id_ed25519"
SSH_PORT="22" # change if you use a non-standard port
# ==================
INSTANCE="$1"
CONFIG_FILE="/etc/sshtunnels/${INSTANCE}.conf"
if [[ ! -f "$CONFIG_FILE" ]]; then
echo "Error: Config file $CONFIG_FILE not found!"
exit 1
fi
# Build -R arguments
FORWARD_OPTS=""
while IFS=: read -r remote_port local_port; do
[[ -z "$remote_port" || "$remote_port" =~ ^# ]] && continue
# Clean any old process using the remote port
ssh -p "$SSH_PORT" "$REMOTE_USER@$REMOTE_HOST" \
"lsof -i :$remote_port -t | xargs -r kill -9" 2>/dev/null
FORWARD_OPTS="$FORWARD_OPTS -R $remote_port:localhost:$local_port"
done < "$CONFIG_FILE"
echo "Starting tunnel $INSTANCE → $REMOTE_HOST ($FORWARD_OPTS)"
exec ssh -o StrictHostKeyChecking=no \
-o ServerAliveInterval=30 \
-o ServerAliveCountThreshold=3 \
-o ExitOnForwardFailure=yes \
-o GatewayPorts=yes \
-N -T \
-i "$SSH_KEY" \
-p "$SSH_PORT" \
$FORWARD_OPTS \
"$REMOTE_USER@$REMOTE_HOST"Make it executable:
sudo chmod +x /usr/local/bin/sshtunnel.sh4. Create a Systemd Service (Auto-Start & Auto-Reconnect)
sudo nano /etc/systemd/system/sshtunnel@.service[Unit]
Description=SSH Reverse Tunnel for %i
After=network-online.target
Wants=network-online.target
[Service]
User=youruser # ← change to your home user (not root!)
Group=youruser
ExecStart=/usr/local/bin/sshtunnel.sh %i
Restart=always
RestartSec=10
[Install]
WantedBy=multi-user.targetReload and enable:
sudo systemctl daemon-reload
# Start a tunnel (example: jellyfin)
sudo systemctl enable --now sshtunnel@jellyfin.serviceCheck status:
sudo systemctl status sshtunnel@jellyfin.service5. On the VPS Side (Optional but Recommended)
Install a tiny web server or Caddy/nginx to terminate TLS and proxy to the forwarded ports.
Example with Caddy (automatic HTTPS):
# On the VPS
apt install caddy
# /etc/caddy/Caddyfile
jellyfin.yourdomain.com {
reverse_proxy localhost:8096
}Now jellyfin.yourdomain.com → your home Jellyfin, fully encrypted.
All running on my beast home server behind CGNAT.
Pros of This Setup
- Works behind any CGNAT / ISP block
- No third-party dependency (no Cloudflare, no Ngrok)
- Full encryption possible
- Survives reboots (systemd + Restart=always)
- Costs almost nothing
Final Words
This is the one really cool way I’ve found to self-host heavy services at home in 2025.
Your powerful hardware stays home. Your $1/month VPS is just a traffic cop.
If you enjoyed this guide, share it with a friend or subscribe to The Self Hosting Art.
Thank you for reading — now go build your unstoppable home lab!