If you can use a separate connection only to forward port(s), i.e. possibly with -N
, then consider this workaround:
while echo; do sleep 1; done | ssh user@server 'exec bash -c "while read -t 5; do :; done"'
(Include port forwarding(s) on your own).
When newlines from echo
stop getting to the remote side, read -t 5
will eventually fail and the entire remote loop will exit. The SSH server will notice its child process exited, it will terminate the connection and release the port(s).
Notes:
read -t
is not portable, the command explicitly calls bash
to handle it.
- If the command interpreter for
user@server
is bash
then there is no need for exec bash
; sole "while read -t 5; do :; done"
(instead of 'exec bash -c …'
) will work.
read -t 5
is quite straightforward. You can develop code that implements the concepts of Interval
and CountMax
.
I tested this approach on my laptop, with actual remote port forwarding (-R
) and beep
instead of :
to hear from the server. When I disconnected Wi-Fi, the beeping stopped. When I reconnected Wi-Fi quickly, the beeping caught up and continued. But when I reconnected few seconds too late, the local command exited because it learned the SSH server had terminated the connection as designed. Important things:
- There were other SSH connections to the same server, governed by
*AliveInterval
and *AliveCountMax
, and they survived. This means my special connection ended without assistance from these options. If I waited long enough with Wi-Fi turned off, then almost all connections would terminate because of the options, including the local half of the special connection. The exception would be the remote half; it would have been long gone anyway because bash
would had exited.
- I was able to connect again immediately, never got
remote port forwarding failed for listen port
. Therefore I think my approach can be a valid solution to your problem.
ServerAlive*
settings matter when alive messages sent from the client cannot trigger response from the server. Maybe they get to the server and only the responses cannot get to the client. More likely the communication is disrupted in both directions.ServerAlive*
settings will make the client consider the connection terminated, but how can it inform the server if packets cannot get to it in the first place? The server will consider the connection valid untilClientAlive*
tell otherwise.