SYSTEM_BLOG
TIME: 00:00:00
STATUS: ONLINE
~/blog/reverse-ssh-tunnel-remote-access
$ cat reverse-ssh-tunnel-remote-access.md _
| 2026-01-09 | 11 min

Reverse SSH Tunnels: Access Your Home Computer From Anywhere

# Reverse SSH Tunnels: Access Your Home Computer From Anywhere

My phone buzzes at 2 AM. A critical server config file is on my home desktop, behind NAT, behind my ISP's double-NAT, unreachable. That was the last time I got locked out of my own machine.

## The NAT Problem

Your home computer doesn't have a public IP. It's hidden behind your router's NAT, invisible to the internet. Port forwarding works until your ISP decides you're behind carrier-grade NAT too. Dynamic DNS helps, but not when there's no port to forward.

"The solution isn't to punch holes inward. It's to reach outward from where you already are."

## The Architecture

TEXT
┌─────────────────────────────────────────────────────────────────┐
│                         INTERNET                                │
└─────────────────────────────────────────────────────────────────┘
         │                                    │
         │ (1) Outbound SSH                   │ (3) Connect to
         │     Connection                     │     VPS:7000
         │                                    │
         ▼                                    │
┌─────────────────┐                    ┌──────┴──────┐
│  HOME COMPUTER  │◄───── Tunnel ─────►│    VPS      │◄──── PHONE
│  (Behind NAT)   │                    │ (Public IP) │
│                 │                    │             │
│  SSH Server     │  (2) VPS opens     │  Port 7000  │
│  Port 22        │      port 7000     │  listening  │
└─────────────────┘                    └─────────────┘

The magic is in the direction. Your home computer initiates an outbound connection to a VPS you control. That connection carries a reverse tunnel that exposes your home's SSH port on the VPS. Now your phone connects to the VPS, and traffic flows backward through the tunnel.

## Key Components

ComponentPurpose
VPSPublic IP endpoint, tunnel bridge
autosshMaintains persistent tunnel with auto-reconnect
GatewayPortsSSH config allowing remote port binding
fail2banBrute-force protection on exposed port
systemdService management with hardening

## The SSH Command Anatomy

The core of the system is a single SSH command:

BASH
ssh -N -R 0.0.0.0:7000:localhost:22 user@vps

Breaking it down:

The 0.0.0.0 is critical. Without it, the tunnel binds only to 127.0.0.1 on the VPS, unreachable from outside.

## GatewayPorts: The Server-Side Gate

SSH servers block remote port binding by default. You need to explicitly enable it:

BASH
# In /etc/ssh/sshdconfig
GatewayPorts clientspecified

Two modes exist:

ModeBehavior
clientspecifiedClient must explicitly request 0.0.0.0 binding
yesAll remote forwards bind to 0.0.0.0 automatically
I recommend clientspecified. It requires explicit intent, reducing accidental exposure.

## Persistence with autossh

Raw SSH dies on network hiccups. autossh wraps SSH with monitoring and auto-restart:

BASH
autossh -M 0 \
    -o "ServerAliveInterval=30" \
    -o "ServerAliveCountMax=3" \
    -o "ExitOnForwardFailure=yes" \
    -N -R 0.0.0.0:7000:localhost:22 \
    -i ~/.ssh/idrsatunnel \
    user@vps

Key options:

  • >-M 0: Disable autossh's monitoring port, use SSH keepalives instead
  • >ServerAliveInterval=30: Send keepalive every 30 seconds
  • >ServerAliveCountMax=3: Disconnect after 3 missed responses (90 seconds)
  • >ExitOnForwardFailure=yes: Fail fast if tunnel can't be established

## Systemd Service with Hardening

Wrapping autossh in systemd gives us boot persistence and security:

INI
[Unit]
Description=Persistent Reverse SSH Tunnel
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
User=youruser
Environment="AUTOSSH
GATETIME=0"
ExecStart=/usr/bin/autossh -M 0 -o ServerAliveInterval=30 ...
Restart=always
RestartSec=10

# Security hardening

NoNewPrivileges=yes ProtectSystem=strict ProtectHome=read-only PrivateTmp=yes

[Install]
WantedBy=multi-user.target

The hardening options:

## Fail2ban: Brute-Force Protection

An open port on the internet attracts scanners within minutes. Fail2ban bans IPs after failed attempts:

INI
[reverse-ssh-tunnel]
enabled = true
port = 7000
filter = sshd
logpath = /var/log/auth.log
maxretry = 5
bantime = 3600
findtime = 600

This configuration:


## The Setup Scripts

I automated the entire process into two scripts:

### Server Script (VPS)

BASH
sudo ./setup-server.sh

Handles:

  1. Backup existing sshdconfig
  2. Configure GatewayPorts
  3. Open firewall port
  4. Install and configure fail2ban
  5. Restart SSH daemon

### Client Script (Home Computer)

BASH
./setup-client.sh

Handles:

  1. Install autossh
  2. Ensure local SSH server running
  3. Generate dedicated tunnel SSH key
  4. Copy key to VPS
  5. Create hardened systemd service
  6. Enable and start tunnel

## Security Considerations

### Dedicated Tunnel Key

Never reuse keys. Generate a dedicated key for the tunnel:

BASH
ssh-keygen -t ed25519 -f ~/.ssh/idrsatunnel -N "" -C "reverse-tunnel"

If compromised, revoke only this key.

### Disable Password Authentication

Once key-based auth works, disable passwords on your home machine:

BASH
# /etc/ssh/sshdconfig
PasswordAuthentication no
PubkeyAuthentication yes

### Non-Standard Port

Default port 7000 works, but a random high port (10000-65000) reduces scanner noise:

BASH
# Less noise, same security
ssh -R 0.0.0.0:47832:localhost:22 user@vps

### Phone SSH Key

Generate a key on your phone's SSH app and add it to ~/.ssh/authorized_keys on your home computer. Never authenticate with passwords over the tunnel.

## Troubleshooting

### Tunnel Not Binding to 0.0.0.0

BASH
# On VPS, check what's listening
ss -tlnp | grep 7000

# Should show: 0.0.0.0:7000

# Not: 127.0.0.1:7000

Fix: Ensure GatewayPorts clientspecified is set and client uses 0.0.0.0:7000 in the -R flag.

### Connection Drops

Increase keepalive tolerance:

BASH
-o "ServerAliveInterval=60"
-o "ServerAliveCountMax=5"

### Service Won't Start

Check logs:

BASH
sudo journalctl -u ssh-tunnel -n 50

Common issues:


## Why Not VPN?

VPNs work, but they're heavyweight. A reverse SSH tunnel:

## Conclusion

Reverse SSH tunnels invert the traditional connection model. Instead of fighting NAT and firewalls, you tunnel out from where you already have access. Combined with autossh persistence, systemd hardening, and fail2ban protection, you get a production-ready remote access solution.

The scripts are available on GitHub. Clone, configure, and never get locked out again.