A long-running SSH tunnel can stop working when a network drops or the SSH process exits. autossh helps by watching an SSH connection and starting the SSH process again when it fails.
It’s useful for persistent port forwards, but it isn’t a fix for bad credentials, an incorrect tunnel, or an unreachable service. Get ordinary SSH working first; then add autossh for recovery.
Start with a working SSH command
Before using autossh, test the same host with SSH directly:
ssh user@example.com
For a tunnel, check that its forwarding options work too. This makes it easier to tell whether a failure comes from SSH authentication or forwarding, rather than autossh.
An unattended connection also needs to be able to authenticate without someone answering prompts. Configure key-based authentication and verify the server’s host key in advance. Don’t disable host-key checking just to make an automated connection start.
Install autossh through your system’s package manager. For example, on Ubuntu or Debian:
sudo apt update
sudo apt install autossh
With Homebrew on macOS:
brew install autossh
A persistent local forward
Suppose an application on your computer needs to reach a service listening on port 5432 from the SSH server’s point of view. Forward a local port through that server:
autossh -M 20000 -N \
-L 15432:127.0.0.1:5432 \
user@example.com
Connect your local application to 127.0.0.1:15432. The SSH server then connects to 127.0.0.1:5432 on its side of the connection.
Here, -N tells SSH not to run a remote command; the connection is only for forwarding. -L defines the local forward. -M 20000 enables autossh’s monitoring connection, using the specified port and the next port for its monitoring loop. Those monitor ports are separate from the application port 15432, and they must be available.
You can also supervise a reverse forward. For example:
autossh -M 20000 -N \
-R 2200:127.0.0.1:22 \
user@example.com
This asks the SSH server to listen on port 2200 and forward connections back to port 22 on the machine running autossh. Whether that remote port is reachable beyond the SSH server depends on the server’s policy and configuration.
Choose how to detect a failed connection
Autossh has two related recovery approaches:
- With
-M port, it sends test traffic through the tunnel and can restart SSH if the monitor detects a failure. - With
-M 0, it disables that monitor-port loop. Autossh can still restart SSH when the SSH process exits, but it no longer performs the separate tunnel test.
When using -M 0, SSH keepalives can help detect a connection that has stopped responding. Add them as SSH options:
autossh -M 0 -N \
-o "ServerAliveInterval=30" \
-o "ServerAliveCountMax=3" \
-o "ExitOnForwardFailure=yes" \
-L 15432:127.0.0.1:5432 \
user@example.com
ServerAliveInterval makes the SSH client send a keepalive after the configured idle interval. ServerAliveCountMax sets how many unanswered requests it tolerates before disconnecting. When SSH exits, autossh can start it again.
ExitOnForwardFailure=yes makes SSH exit if it cannot establish the requested forward. That gives autossh a chance to retry, but it does not check whether the application behind the forward is healthy. Keepalives and autossh also don’t make reconnects seamless: active sessions are interrupted, and applications may need to reconnect.
Run it in the background—or let a service manager supervise it
For a quick background tunnel, autossh supports -f:
autossh -M 0 -f -N \
-o "ServerAliveInterval=30" \
-o "ServerAliveCountMax=3" \
-L 15432:127.0.0.1:5432 \
user@example.com
Backgrounding is convenient for a temporary task, but it doesn’t arrange to start the tunnel after a reboot. For a tunnel that must run persistently, use your operating system’s service manager. With systemd, run autossh in the foreground so systemd can supervise it; don’t add -f to its ExecStart.
A minimal unit might look like this:
[Unit]
Description=Persistent SSH tunnel
Wants=network-online.target
After=network-online.target
[Service]
User=YOUR_LINUX_USER
Environment=AUTOSSH_GATETIME=0
ExecStart=/usr/bin/autossh -M 0 -N -o ServerAliveInterval=30 -o ServerAliveCountMax=3 -o ExitOnForwardFailure=yes -L 15432:127.0.0.1:5432 user@example.com
Restart=always
RestartSec=10
[Install]
WantedBy=multi-user.target
Adapt the account, host, ports, and SSH settings to your environment. Check the installed executable path with command -v autossh before using it in ExecStart. The service account must be able to use the required SSH key and must already trust the correct host key. AUTOSSH_GATETIME=0 tells autossh to retry even if the initial SSH connection fails soon after startup; it doesn’t fix the reason for the failure.
After saving the unit, reload systemd and start it:
sudo systemctl daemon-reload
sudo systemctl enable --now autossh-tunnel.service
sudo systemctl status autossh-tunnel.service
To inspect its output, use:
journalctl -u autossh-tunnel.service
When the tunnel keeps restarting
Start by running the underlying SSH command without autossh and fix any authentication, host-key, DNS, or connectivity problem. Then check that the requested forward is allowed, its listening port is free, and the destination service is reachable from the correct side of the connection.
If you use -M port, also check that both monitor ports are available. If you use -M 0, confirm that SSH keepalives are configured if you need an unresponsive connection to eventually exit. Run autossh in the foreground while troubleshooting so errors are visible.
Frequent restarts usually point to an unresolved SSH or forwarding problem. Autossh can retry a connection, but it can’t make invalid credentials, a blocked port, or an unavailable destination work.
I originally published a more detailed version of this guide on the SSHFlow blog.
I'm also building SSHFlow — an SSH client where every server gets its own workspace for terminals, SFTP, code, and databases.
Top comments (0)