ssh keep-alive tip

Whenever I login remotely to my machine in Canada, the ssh session dies after a while if I don’t actively type something. This is not the server timing out, but rather the TCP connection hanging. Figuring out a way to keep sending it keystrokes automatically is beyond my ability, but I found out that I could just have it send me data continually, and that works just as well to keep the terminal session alive. The following Bourne Shell loop works:

> while date ; do sleep 10 ; done

This just prints the date and time to my terminal every 10 seconds. At any time, I can interrupt it with a CTRL-C and continue to use the session. So now you know. 😛

46 thoughts on “ssh keep-alive tip

  1. Well, you just gotta add these two lines to the /etc/ssh/sshd_config file on your server:

    KeepAlive yes ClientAliveInterval 60

    Now just restart sshd and your connection should never be interrupted again.

  2. Max: But remember that most people have no root access on most machines. In addition, keep alives are a big security threat. If somebody walks away from their shell and somebody else drops in, sshd will have actually kept the shell open for them.

    So I took the command from above, wrapped it in a “sh” call and it works just fine. I use this to keep my various ssh tunnel alive. Every 20 sec I get an echo to the shell but I can still type commands as usual:
    sh -c 'while echo "Tunnel..." ; do sleep 20 ; done'&
    Thanks for the tip, Mad Philosopher 😀

  3. > Every 20 sec I get an echo to the shell but I can still type commands as
    > usual:
    >
    > sh -c ‘while echo “Tunnel…” ; do sleep 20 ; done’&

    So do this:
    sh -c 'while echo "Tunnel…" > /dev/null; do sleep 20 ; done' &

  4. You could also do something clever with port forwards and netcat.

    Like this little keep-alive ssh script:

    --- begin kassh ---
    #!/bin/bash
    
    # Pick a random high numbered port.
    port=$[$RANDOM+32000]
    
    ## Keepalive process..
    (sleep 300; while netcat -z -v localhost $port; do
            sleep 300
    done) >/dev/null 2>&1 &
    
    # Initiate SSH connection with whatever argument we were given.
    ssh -L $port:localhost:7 $*
    
  5. Redirecting the echo to /dev/null probably will not work, because sshd would have no reason to send bytes to the client. Personally I do something like ‘ping -i 10 ‘ or ‘tail -f /var/log/httpd-access.log’ when I need such a hack; as long as you are sending junk packets you might as well have some information in them.

  6. When SSH’ing, I always use “screen”. An excellent tutorial is located here: http://jmcpherson.org/screen.html

    Screen can also display a little clock running. Put the following line in a file called “.screenrc” and put it in the home directory.
    caption always '%c:%s'

  7. A friend of mine wrote this for me awhile back. He calls it spin.c
    Compile this and run it… it’ll give you a nice spinny thing to keep your ssh session busy.

    #include <stdio.h> int i; char spin[4] = { '|', '/', '-', '\\' }; void main() { for(i=0;;usleep(300000), fflush(stdout)) printf("%c\x08", spin[++i%4]); }

  8. Do as Bart says, use screen if you do not have root access on the remote machine. It is really usefull, much easier than the other sollutions, and it is not a hack like most of them. If you do have root access you can fix the source of the problem, but you might still want to have a look at screen.

  9. Read the earlier post about ServerAliveInterval. You don’t need root access. Just create a file:

    $HOME/.ssh/config

    and put:

    ServerAliveInterval 60

    in it.

  10. DO NOT RUN TOP – it requires too much overhead(processor cycles) and your sysadmin will kill it if he notices anyway.

  11. Thanks Cam, yours was the simplest to implement, worked great.
    All the others & madphilo: thanks for your inputs !
    No wonder google lists this page at the top when searching for ssh keepalive.

  12. Cam’s response seems easiest. I just wanted to note that I had to create the ~/.ssh/config file, and ‘chmod g-w’ on it before I could slogin somewhere (note: this may be a SELinux feature).

  13. There’s a program called autossh that is especially useful for keeping SSH tunnels alive. It can also be used to keep a shell login session active over a long period.

    You configure the autossh process, which runs in the background to maintain various SSH connections, and then rather than connect to the remote host, you connect to a port on your local machine. The underlying SSH session can break many times, but your client programs never detect an actual break in the connection; they are always presented with an active connection. autossh handles all the reconnections behind the scenes. I’ve used it successfully on intermittant wireless and dialup connections.

    http://freshmeat.net/projects/autossh

  14. The suggestions involving tunneling sound nice as they wouldn’t interfere with your console. However, they are a bit more work to set up. If you don’t want to do all that you could do what I do. I usually just start up top. That’s usually good enough to keep the session going as there is almost always some kind of movement going as various processes’ priorities are moved up and down. Even if there isn’t, it has a clock n it which is constantly updating.

    I also highly recommend the screen utility. It is good for two reasons. 1) if you are running something long that doesn’t have any output to keep your session alive you can open a new terminal within screen and run top or something else there. 2) If your connection does close whatever you were running should continue running and you only need connect again and re-attach to the old screen session.

    Of course, if you do have root, setting the KeepAlive in sshd_config is the most convenient option.

  15. now for some reason, cam’s suggestion is not working anymore…ssh term keeps timing out on me…I’ll try autossh …

  16. or you could just do a
    ssh -o TCPKeepAlive mark@localhost
    which will do the same and handy if bouncing between boxes.

  17. Here is the script I wrote to overcome this issue. This script scrolls a text message on screen randomly as “Keep Alive On…”

    #!/bin/ksh
    x=0
    y=0
    flip_flop=0
    while [ 1=1 ]
    do
    	clear
    	if [[ $x -ge ${LINES} ]]; then
    		x=1
    	else
    		x=`expr $x + 2`
    	fi
    	
    	if [[ $y -ge ${COLUMNS} ]]; then
    		y=1
    	else
    		y=`expr $y + 2`
    	fi
    	tput cup $x $y
    	if [[ $flip_flop -eq 0 ]]; then
    		echo "Keep Alive On"
    		flip_flop=1
    	else
    		flip_flop=0
    		echo "`tput smso`Keep Alive On`tput rmso`"
    	fi
    	sleep 2
    done
    
  18. Does the
    “ServerAliveInterval 60”
    go on the local machine or on the foreign host?

  19. Mister Confused Person:

    The “ServerAliveInterval 60” is a client-side option, so it goes on the local machine, as you say.

    Here’s the pertinent paragraph from the ssh_config man page on my Ubuntu system:

    ServerAliveInterval

    Sets a timeout interval in seconds after which if no data has been received from the server, ssh will send a message through the encrypted channel to request a response from the server. The default is 0, indicating that these messages will not be sent to the server, or 300 if the BatchMode option is set. This option applies to protocol version 2 only. ProtocolKeepAlives is a Debian-specific compatibility alias for this option.

  20. It’s worth noting that many SSH timeouts come from firewalls and no amount of tinkering with timeout settings (other than on the firewall) will fix it. The only way in these cases is to simulate traffic (which is what the client’s keepalive settings should do, but don’t always in my experience).

    I find this works very well (although possibly it’s overkill being in perl):

    perl -e 'sleep 59 && print STDERR "\x00" while 1' &
    

    Run it as soon as you SSH in, and remember the pid so you can kill it before you leave. It squirts a null every 59 seconds. If you change the \x00 for a printable character you will see it appear on your terminal but it still won’t impact what you are doing.

  21. Bruce:

    You can automate this by putting the following in your .kshrc (or its equivalent for your shell in its rc file, or put it in .profile (or .login)):

    case $- in i*s*)
    perl -e 'sleep 59 && print STDERR "\x00" while 1' &
    trap "kill ${!}" 0
    ;;
    esac
    

    Because, in working with computers, being lazy is a great virtue…

  22. Both Cam and Max’s solutions (ie ClientAliveInterval and ServerAliveInterval) resolve the timeout issue, even when a firewall is timing out connections which transit it.

    We just installed a new firewall here and it’s default behavior (which is also unchangeable without a firmware upgrade) is to timeout sessions after 5 minutes. Having a bunch of pissed off engineers in your cube is never a good thing, so thanks to Cam and Max.

    I guess this is what I get for buying a firewall off of ebay. 🙂

  23. Another dirty hack that keeps an ssh connection alive without printing annoying messages to the console:

    sh -c while sleep 20 ; do echo -ne "\a" ; done
    

    This “prints” an alert, which probably produces a beep every 20 seconds but since my workstation has no sounds, its a neat variant of the above keep-alive command.

  24. dude, echo -ne “\a” would beep on the server not the client. the admin at the bunker is probably going nuts trying to figure out what all that beeping is. (….the server probably doesn’t have sounds, either, though)

  25. “some other dude”, that’s not correct. Don’t forget the difference between console and terminal.

    When using SSH, you’re on a terminal, not the console. If you sent the \a to the console then the beep would be at the server, otherwise you’re printing it to your (pseudo) terminal and your terminal emulator (putty or whatever) will receive it. It’s then up to the terminal emulator to actually do something with it. putty can be configured to do various things on receiving the alarm, such as beep or flash the window.

  26. Remember that

    ServerAliveInterval
    

    is limited by

    ServerAliveCountMax
    

    and that ServerAliveCountMax is set to 3 by default!

    That is, if you set ServerAliveInterval to 60 and ServerAliveCountMax is left to default value (3), after the client has sent 3 keep alive packets it will disconnect. That makes 60 x 3 = 180 seconds.

    So if you want more time away, you set ServerAliveInterval to 60 and ServerAliveCountMax to the numer you want (for example: 100). The client will send one keep alive packet every 0 seconds for 100 times or, if you prefer, 100 keep alive packets, one every 60 seconds. 😀

    You set this up in your $HOME/.ssh/config file.

    Most of these options are explained in man ssh_config.

    Thanks a lot to Cam for pointing us all in the right direction!!!!

  27. Todd Says:

    June 8th, 2006 at 1336 UTC

    DO NOT RUN TOP – it requires too much overhead(processor cycles) and your sysadmin will kill it if he notices anyway.

    Absolutely not true.

    1> It only uses many cycles if you have the interval set way too short, like under .5 seconds

    2> if your sysadmin is obsessed with you not using top, he/she should simply disable your ability to run it, not ‘kill it’ once you do.

  28. Thanks madphilosopher i tried your looping print to terminal but Cam’s .ssh config was the fix i was after. Just a note that this config file should be created on your own machine not the server. Oh and it works on Mac OSX too 🙂

  29. The correct syntax for setting the ssh TCPKeepAlive option is:

    ssh -o TCPKeepAlive=yes mark@localhost
    

    i.e., you must include the "=yes" value after the TCPKeepAlive identifier!

    All the Best,
    Joe

    Mark says:
    January 16, 2007 at 1504 UTC

    or you could just do a

    ssh -o TCPKeepAlive mark@localhost
    

    which will do the same and handy if bouncing between boxes.

  30. I’m guessing that no one here has tried:

    export TMOUT=0 in their ~/.bash_profile? It works with our stringent security policies on our RHEL5 machines. No need to send a loop to the background.

    while date; sleep 5; done > /dev/null
    

    Would work better than the poster’s loop anyway, you wouldn’t need crap printed to the screen, and it is registered as “activity”.

  31. how can i implement a windows/apache/php web site to keep track of unix servers, using some sort of keep alive.. I m currently using a ping but i find that a bit slow if you have multiple servers is there another low level tool/utility i can use to check on server availability?

  32. Very interesting. I’m in Canada (just got here recently) and have noticed the same behavior. Back in the U.S., I could keep an idle connection open indefinitely (weeks, months, etc.), whereas here I return to my terminal and see closed connections if I leave my machine for a bit (haven’t tested to see exactly how long, but it seems quite short, definitely under an hour). I blame my either my ISP (TekSavvy) or its cable provider (Rogers). It’s downright wrong to close people’s TCP connections just because you feel like it. What if I were streaming something from a server and the server had a hiccup and stopped streaming for some time: are they going to close that connection, too, and force me to restart the entire stream just because they feel like it? Canada is weird in this respect. Whether it’s due to bureaucracy or incompetence, it doesn’t matter, it just plain sucks and makes no sense at all.

  33. Screen plus the clock device worked best for me. I can keep a perfectly decent interface (email) with but minor glitches. Use the -O option in screen – it will optimize the output for your type of terminal instead of forcing strict VTx. Also, you may need to resize the window to fully accomodate changes. Thanks to all contributors!

    One more note: I hadn’t needed this until now; my ISP improved services seriously by introducing FTTH, but their core equipment is giving timeouts to either SSH or port 22 (we don’t know which for sure yet) after painfully short inactivity times. I’ve seen this in a few other networks as well.

Leave a Reply

Your email address will not be published. Required fields are marked *