How to Establish SSH Reverse Tunneling for Remote Access to NATed Ubuntu Machines


1 views

When dealing with Ubuntu machines behind restrictive routers (where port forwarding isn't possible), traditional SSH access becomes challenging. The solution lies in creating persistent SSH tunnels that bypass NAT restrictions.

The most reliable method is reverse tunneling, where your local machine initiates an outbound connection to a publicly accessible server, then creates a tunnel back to itself.

ssh -fN -R 8022:localhost:22 user@your_public_server.com

This command establishes a reverse tunnel where port 8022 on your public server forwards to port 22 on your local machine.

1. On your local Ubuntu machine (behind NAT):

ssh-keygen -t ed25519
ssh-copy-id user@your_public_server.com

2. Create persistent connection using autossh:

autossh -M 0 -fN -o "ServerAliveInterval 30" -o "ServerAliveCountMax 3" \
-R 8022:localhost:22 user@your_public_server.com

From any other computer, connect through the public server:

ssh -J user@your_public_server.com localhost -p 8022

For production environments, consider these enhancements:

# /etc/ssh/sshd_config on public server
GatewayPorts clientspecified
ClientAliveInterval 60
TCPKeepAlive yes

Create systemd service for automatic reconnection:

[Unit]
Description=AutoSSH tunnel service
After=network.target

[Service]
ExecStart=/usr/bin/autossh -M 0 -N -o "ExitOnForwardFailure=yes" \
-o "ServerAliveInterval 30" -o "ServerAliveCountMax 3" \
-R *:8022:localhost:22 user@your_public_server.com
Restart=always
RestartSec=60

[Install]
WantedBy=multi-user.target

If you encounter "Address already in use" errors:

netstat -tulnp | grep 22
kill -9 [PID]

For connection stability issues, add these SSH options:

-o "ExitOnForwardFailure=yes" -o "StrictHostKeyChecking=no" \
-o "ConnectTimeout=10" -o "BatchMode=yes"

For environments with strict firewall rules:

# VPN-based solution
ssh -w 0:0 user@your_public_server.com

# Using ProxyCommand
ssh -o ProxyCommand="ssh -W %h:%p user@your_public_server.com" user@localhost -p 22

When you have a machine (let's call it Client) behind a restrictive NAT/router that you can't configure port forwarding on, but you need persistent SSH access to it. You do have access to another publicly accessible server (Server). Here's how we solve this using SSH reverse tunneling.

Instead of trying to forward ports from your NAT (which you can't configure), we'll make the behind-NAT machine initiate an outgoing connection to your public server and create a reverse tunnel. This is often called "SSH tunneling" or "port forwarding over SSH".

On your Client machine (behind NAT):

ssh -N -R 2222:localhost:22 user@your-public-server.com

This command:

  • -N tells SSH not to execute remote commands
  • -R creates a reverse tunnel
  • 2222 is the port on the public server that will forward to
  • localhost:22 is your local SSH server

To ensure the tunnel stays alive:

autossh -M 0 -f -N -o "ServerAliveInterval 30" -o "ServerAliveCountMax 3" \
-R 2222:localhost:22 user@your-public-server.com

Key parameters:

  • -M 0 disables monitoring (autossh has its own keepalive)
  • -f runs in background
  • ServerAliveInterval keeps the connection active

Once the tunnel is established, from anywhere you can access your behind-NAT machine by:

ssh -p 2222 localhost -l username

(Executed on your public server)

For better security:

# On your public server's sshd_config:
GatewayPorts clientspecified
AllowTcpForwarding remote

And consider using SSH keys instead of passwords for all connections.

If you need more comprehensive access (not just SSH), consider setting up a VPN like WireGuard. This provides full network access to your behind-NAT machine.

Example WireGuard config (client side):

[Interface]
PrivateKey = your_private_key
Address = 10.8.0.2/24

[Peer]
PublicKey = server_public_key
AllowedIPs = 0.0.0.0/0
Endpoint = your-public-server.com:51820
PersistentKeepalive = 25