If your SSH connection is not surviving brief network outages, then there's something else going on that's not letting
ssh and TCP do their normal thing.
See below for details. Anyway:
The Quickest-and-Dirtiest No-Dependencies Solution
Create a shell script like this:
# Tune these numbers depending on how aggressively
# you want your SSH session to get reconnected.
timeout_options='-o ServerAliveInterval=4 -o ServerAliveCountMax=2'
# 255 is the status OpenSSH uses to signal SSH errors, which
# means we want to connect. All other exit statuses suggest
# an intentional exit.
# Keep opening the SSH connection and immediately dropping into
# `screen` until an intentional exit happens.
while [ "$status" = 255 ]
ssh $timeout_options -t "$@" screen -dR
# You can add a `sleep` command here or a counter or whatever
# you might need as far as rate/retry limiting.
This will just run a stupid-simple loop that keeps trying to connect with
ssh and attach to
screen. Pass the host or whatever else you'd normally pass to your
ssh invocation as command-line arguments.
The reconnect is just based on whether SSH reports an error with the connection, which means it has no intelligence for detecting non-SSH errors like "you literally don't have WiFI turned on" or whatever, but that probably doesn't matter for you.
I'm assuming you have
ssh-agent or a no-passphrase SSH key that will allow reconnects to just work without additional input from you.
There's going to be a tiny race condition where if you hit
^C during just the right human-imperceptible fraction of a second during a reconnect you could end up killing the script instead of passing the
^C through to the client terminal, so if you suspect a connection hang don't mash
^C too zealously.
Simplest Additional Software Solution
You can try the program autossh, which should be available in your Ubuntu package repository.
If you need to build from source or audit it, it's a single C program that compiles without any additional libraries as dependencies, seems to have more intelligence about checking connection liveliness than my hack above, and it also ships with a convenient
rscreen script command which auto-attaches to
ssh normally recovers
Just to verify, because I don't like saying things without checking myself, I ran a little test before answering:
I got on my WiFi with a Linux device, made an SSH connection to another device on my LAN, verified I had a working
ssh connection to the other end (could run commands, etc), then on the client disconnected the WiFi (causing the interface to be de-configured: no more IP addresses), typed a bunch more characters into the ssh session (no response, of course), and then reconnected to my WiFi - the reconnection actually failed at least once due to bad signal and other factors, then finally reconnected: I waited about five seconds for the
ssh session to recover, nothing happened so I hit one more key, and the
ssh session immediately came alive again, with all the keys that I had typed during the disconnect appearing on the command line.
ssh just writes/reads into the TCP network socket until the OS tells it something went wrong, and TCP is actually very tolerant of prolonged connection drops.
Left to its own devices with default kernel settings the TCP stack in Linux will happily tolerate the connection going completely silent for many minutes before declaring the connection dead and reporting an error to
ssh - by the time it finally gives up we're talking in the ballpark of ~30 minutes, or at least certainly long enough to outlast connection hiccups lasting a second or a minute.
Underneath the covers, the Linux TCP stack gradually retries messages with longer and longer delays, though, which means that by the time your connection does come back, you might be looking at additional lag before your
ssh session seems to come "alive" again.
Why this sometimes breaks
Often something is actively causing the connection to close after some significantly shorter period of inactivity than the amount that the TCP stack will tolerate, and then failing to report that connection state to your
Likely candidates include:
Firewalls or NAT'ing routers, which have to use memory to remember each live TCP connection - as an optimization and some mitigation against DOS attacks, they will sometimes just forget your connection, and then silently ignore consequent packets for it, because packets in the middle of a connect when you don't remember the connection existing look invalid.
Better-behaved firewalls/routers will inject a TCP RST packet, which typically manifests as a
connection reset by peer error message, but the reset packet is a fire-and-forget, so if the connection to your client is still having issues at that moment and drops the reset packet too, your client will think the connection is still alive.
The server itself might have a firewall policy to silently drop unexpected packets, which would break the client's connection resumption attempts whenever the server thinks the connection closed but the client doesn't: your client keeps trying to continue the connection, but the server is just ignoring it because there's no live connection to which these packets belong in the server's firewall state.
Since you're running Linux, carefully check your server's
nft if you're using the new stuff) for exactly what you're allowing vs. dropping. It's very common to allow new/established/related packets on the TCP SSH port, but not "invalid" ones - if you're dropping silently everything that isn't allowed, this common setup could cause these kinds of freezes after brief connection issues.
Your SSH server itself might be configured to close the connection after a period of inactivity, using one of OpenSSH options for TCP or SSH client keepalive packets. By itself this won't cause indefinite hangs, but it can put you in one of the states described above.
It's possible you're just not giving it enough time to "unhang" on its own after you get into the state where your
ssh session hangs up.