How to Set Up a Reverse SSH Tunnel to Access Your Home Server via VPS
Your home server sits behind a NAT router with a dynamic IP — no way to SSH into it from outside without complicated port forwarding or dynamic DNS. A VPS solves this elegantly with a reverse SSH tunnel: your home server connects outward to the VPS (which it can always reach), and the VPS then forwards incoming connections back to your home server. The result: a stable, permanent way to access your home server from anywhere using just the VPS’s fixed IP.
This guide covers setting up a reverse SSH tunnel, keeping it alive with autossh and systemd, and hardening the connection for production use.
How Reverse SSH Tunneling Works
Normal SSH:
You → Internet → Home Server (BLOCKED by NAT)
Reverse SSH Tunnel:
Home Server → outbound SSH → VPS (always works)
You → SSH to VPS → tunnel → Home Server ✅
The home server initiates the connection (outbound, which NAT allows). The VPS listens on a port and forwards connections back through that tunnel to the home server.
Requirements
- A VPS with a static public IP (e.g., VPS.DO USA VPS)
- A home server running Linux (Ubuntu, Raspberry Pi, etc.)
- SSH access to both machines
💡 VPS.DO Tip: Any VPS.DO plan works for this. Even the smallest plan handles multiple reverse tunnels comfortably. View Plans →
Step 1: Set Up SSH Keys (No Password Authentication)
The tunnel must connect automatically without a password prompt:
# On your home server — generate a dedicated tunnel key
ssh-keygen -t ed25519 -C "home-server-tunnel" \
-f ~/.ssh/tunnel_key -N ""
# Copy the public key to your VPS
ssh-copy-id -i ~/.ssh/tunnel_key.pub user@YOUR_VPS_IP
# Test the passwordless connection
ssh -i ~/.ssh/tunnel_key user@YOUR_VPS_IP
Step 2: Configure the VPS for Tunneling
# On the VPS — allow gateway ports (needed for tunnel to accept external connections)
sudo nano /etc/ssh/sshd_config
# Add or uncomment:
GatewayPorts yes
AllowTcpForwarding yes
sudo systemctl restart sshd
Step 3: Create the Reverse Tunnel
# Run this on your HOME SERVER
# This forwards VPS port 2222 → home server port 22
ssh -i ~/.ssh/tunnel_key \
-N \ # No remote command (tunnel only)
-R 2222:localhost:22 \ # Remote port 2222 → local SSH
-o ServerAliveInterval=30 \
-o ServerAliveCountMax=3 \
user@YOUR_VPS_IP
Now, from your VPS (or from any machine that can reach your VPS), connect to your home server:
# From your VPS — access the home server
ssh -p 2222 home_user@localhost
# From anywhere else — SSH to VPS, then hop to home server
ssh user@YOUR_VPS_IP
ssh -p 2222 home_user@localhost
Or directly in one command:
ssh -J user@YOUR_VPS_IP -p 2222 home_user@localhost
Step 4: Keep the Tunnel Alive with autossh
A plain SSH tunnel dies if the connection drops. autossh monitors and restarts it automatically:
# On the home server
sudo apt install autossh -y
# Test autossh tunnel
autossh -M 0 \
-i ~/.ssh/tunnel_key \
-N \
-R 2222:localhost:22 \
-o ServerAliveInterval=30 \
-o ServerAliveCountMax=3 \
-o ExitOnForwardFailure=yes \
user@YOUR_VPS_IP
The -M 0 flag disables autossh’s own monitoring port and relies on SSH’s built-in keepalive instead (simpler and more reliable).
Step 5: Run the Tunnel as a systemd Service
Make the tunnel start automatically on boot and restart if it fails:
sudo nano /etc/systemd/system/ssh-tunnel.service
[Unit]
Description=Reverse SSH Tunnel to VPS
After=network-online.target
Wants=network-online.target
StartLimitIntervalSec=0
[Service]
Type=simple
User=YOUR_HOME_USER
ExecStart=/usr/bin/autossh -M 0 \
-i /home/YOUR_HOME_USER/.ssh/tunnel_key \
-N \
-R 2222:localhost:22 \
-o "ServerAliveInterval=30" \
-o "ServerAliveCountMax=3" \
-o "ExitOnForwardFailure=yes" \
-o "StrictHostKeyChecking=no" \
user@YOUR_VPS_IP
Restart=always
RestartSec=10
Environment="AUTOSSH_GATETIME=0"
[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload
sudo systemctl enable ssh-tunnel
sudo systemctl start ssh-tunnel
sudo systemctl status ssh-tunnel
The tunnel now starts on boot and automatically reconnects if the connection drops. ✅
Step 6: Forwarding Multiple Services
You can tunnel multiple ports in a single SSH connection:
# Forward multiple ports in one tunnel:
# - Port 2222 → home SSH (22)
# - Port 8080 → home web server (80)
# - Port 5900 → home VNC (5900)
# - Port 8443 → home HTTPS (443)
autossh -M 0 \
-i ~/.ssh/tunnel_key \
-N \
-R 2222:localhost:22 \
-R 8080:localhost:80 \
-R 5900:localhost:5900 \
-o ServerAliveInterval=30 \
user@YOUR_VPS_IP
# Access each service from anywhere:
# SSH: ssh -p 2222 user@YOUR_VPS_IP
# Web: http://YOUR_VPS_IP:8080
# VNC: vnc://YOUR_VPS_IP:5900
Step 7: Expose the Tunnel Publicly
By default, the reverse tunnel binds to localhost on the VPS — only accessible from within the VPS. To allow external connections:
# The GatewayPorts yes setting (Step 2) allows:
-R 0.0.0.0:2222:localhost:22
# Update the firewall on the VPS
sudo ufw allow 2222/tcp
Now anyone who knows your VPS IP can SSH to port 2222 and reach your home server.
Step 8: Security Hardening
Restrict tunnel access by IP
# On VPS UFW — only allow tunnel port from your trusted IPs
sudo ufw allow from YOUR_LAPTOP_IP to any port 2222
sudo ufw deny 2222/tcp
Create a dedicated restricted tunnel user on VPS
# On VPS — create a user that can only forward ports, not run commands
sudo useradd -m -s /bin/false tunneluser
sudo passwd tunneluser
# Restrict the tunnel user in /etc/ssh/sshd_config
Match User tunneluser
AllowTcpForwarding yes
X11Forwarding no
AllowAgentForwarding no
PermitTTY no
ForceCommand echo 'This account is for tunneling only'
Use the restricted user for the tunnel
# Home server tunnels through the restricted user
ssh-copy-id -i ~/.ssh/tunnel_key.pub tunneluser@YOUR_VPS_IP
autossh -M 0 \
-i ~/.ssh/tunnel_key \
-N \
-R 2222:localhost:22 \
tunneluser@YOUR_VPS_IP
Practical Use Cases
| Use Case | Port to forward |
|---|---|
| SSH to home server | -R 2222:localhost:22 |
| Access home Plex/media server | -R 32400:localhost:32400 |
| Raspberry Pi VNC remote desktop | -R 5900:localhost:5900 |
| Home NAS web interface | -R 5000:localhost:5000 |
| Home automation (Home Assistant) | -R 8123:localhost:8123 |
| Development server testing | -R 3000:localhost:3000 |
| Printer/scanner sharing | -R 631:localhost:631 |
Monitoring Tunnel Status
# On the VPS — check active tunnels
ss -tlnp | grep LISTEN
# Look for ports 2222, 8080, etc.
# Check autossh process on home server
systemctl status ssh-tunnel
journalctl -u ssh-tunnel -f
# Test tunnel connectivity from VPS
ssh -p 2222 home_user@localhost "hostname && uptime"
Final Thoughts
A reverse SSH tunnel transforms a VPS into a permanent gateway to any machine on any network — home servers, office machines, remote Raspberry Pi devices, IoT hardware. The setup takes under 30 minutes and costs nothing beyond your VPS subscription. With autossh and systemd, the tunnel is self-healing and starts automatically on every reboot.