7

I am doing a permanent port forwarding via SSH. It is basically

while true; do
        ssh <somewhere> \
                -R <dst-port>:localhost:<src-port> \
                -N -n -o ExitOnForwardFailure=yes
        sleep 10
done

However, that is not very reliable. Sometimes, the port is not forwarded at all (I'm not sure if the connection is correctly alive but I can see the process on the client and it is running already for several hours), sometimes the connection is surely not alive anymore (because the network interface is down) but it takes very long (sometimes up to 30-60 minutes) to timeout.

How can I make that more reliable? I want to have a timeout of maybe a minute.


I just found this very related/similar question. However, the first answer indicates that ExitOnForwardFailure should solve it but I already have that and it does not (I can see right now the running ssh process with this option but the port is not forwarded).

5 Answers 5

6

I put these in the SSH client config file:

ServerAliveInterval = 60
ServerAliveCountMax = 3

Alternatively, these options can be passed on the ssh command line via -o.

Some clients may not have this configuration control, such as the various meager clients for mobile devices. In that case, it is still possible to configure it globally on the each server being connected to, which of course requires privileges on the server machine. The OpenSSHD implementation doesn't seem to have a way for users to customize server parameters (no ~/.ssh/sshd_config file is read where selected parameters could be customized from the server side).

2
  • That seems to work. I'm really surprised because I am connected to my server 24/7 for a month with plain ssh ... but when doing a reverse port forwarding, it dies pretty quickly if I don't use the "keep alive" feature. Nov 1, 2023 at 23:51
  • 1
    @AlexisWilke The flipside is that keep-alive features can unnecessarily kill an idle connection, if there is a network outage, when otherwise that connection could have survived the outage.
    – Kaz
    Nov 2, 2023 at 1:03
3

I use autossh like this on my work machine to setup for remote web development:

autossh -M0 -N -R \*:8080:localhost:80 -R \*:5051:localhost:22 home

autossh is a program that keeps restarting ssh if it crashes or stops for any reason other than "kill -9". The above command sets up two tunnels: one for forwarding port 80 on my work machine to 8080 on my home machine, the other tunnels the ssh server on my work machine to my home machine. The * in front of the port makes this work with any hostname, not just localhost. You might need to set "GatewayPorts yes" on your sshd_config for that to work though. I have hosts in ~/.ssh/config and /etc/hosts on my home machine to make this even more transparent. For other systems it's necessary to use ProxyCommand (http://sshmenu.sourceforge.net/articles/transparent-mulithop.html), but I don't have the host I use this command with powered on at the moment to grab it.

~/.ssh/config:

Host work
    hostname localhost
    port 5051

Then it's just

autossh -M0 -t home 'ssh work'

from any host to connect.

1
  • I read already about autossh before. However, I still have exactly the same problems as before. The connection still dies but autossh doesn't recognize it.
    – Albert
    Aug 9, 2012 at 20:25
1

This version sends frequently some data to the server. If the connection has died, the pipe should break sooner or later.

while true; do
        { while true; do echo echo ping; sleep 10; done } | \
        ssh <somewhere> \
                -R <something> \
                -o ExitOnForwardFailure=yes \
                >/dev/null
        sleep 10
done
0

You could try changing your SSH command to:

ssh SOMEWHERE -R DSTPORT:localhost:SRCPORT -n -o ExitOnForwardFailure=yes \
    "while true; do echo ping; sleep 10; done" >/dev/null

This causes a small amount of data to be sent over the TCP connection every 10 seconds (feel free to change that period). That may be sufficient to keep the connection alive.

10
  • Have you actually tried that? I was thinking about some similar hack, though I couldn't really believe that there would be no timeout otherwise, so I haven't even tried yet.
    – Albert
    Aug 8, 2012 at 2:34
  • Yes, I've used that trick to positive effect.
    – Fran
    Aug 8, 2012 at 15:02
  • I tried it now. It doesn't work, the connection still dies silently and it doesn't recognize it.
    – Albert
    Aug 10, 2012 at 10:10
  • Then something other than a TCP timeout is causing the connection to fail. If you SSH into the machine normally, and run that while loop from the shell prompt, will it still disconnect? If so, you have a network problem.
    – Fran
    Aug 10, 2012 at 13:46
  • How should the client now if the server is not sending anything anymore that the connection has died? I have now made a slightly different variant where the client is constantly sending something (and the SSH protocol requires to get some form of ack), so if that fails at some point, the client knows that the connection has died. See my own answer.
    – Albert
    Aug 13, 2012 at 3:19
0

As quoted previously by Kaz, the connection does not seem to require any explicit traffic to keep alive. Something like:

ssh you@there 'read ANYTHING' < $PIPE

just works. $PIPE is a named pipe you'll write to when you're done.

Well, let's be explicit - the $PIPE is more complex than 'read ANYTHING' and is worth a verbose example. Here is the code I use to rdesktop a machine in a network I cannot access directly:

p_user=myself
p_bridge=me@there
p_host=192.168.xxx.yyy
p_port=9999

p_size=100%      # or: p_size=1280x1024
p_trace=stderr   # or: p_trace=null

s_trace() {  echo "$*" > /dev/$p_trace; }

PIPE=$TEMP/${0##*/}.$$
mkfifo $PIPE.0
mkfifo $PIPE.1

trap 'rm $PIPE.0 $PIPE.1' 0

# ----------------------------------------------------
ssh $p_bridge \
    -L $p_port:$p_host:3389 \
    'read CONNECT; date; read QUIT' \
  < $PIPE.1 \
  > $PIPE.0 \
  & 
# ----------------------------------------------------

# note: "type -p" is somehow required with xinit
# note: "-p -" reads password from stdin
DESKCMD="$(type -p rdesktop) -P -z -u $p_user -p - -g $p_size localhost:$p_port"

{
  echo connect >&3; read CONNECT <&4; s_trace "CONNECTED: $CONNECT"
  $DESKCMD -f    # or: xinit $DESKCMD -- :1
  echo quit >&3
} \
  3> $PIPE.1 \
  4< $PIPE.0

wait

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .