Sign up ×
Ask Ubuntu is a question and answer site for Ubuntu users and developers. It's 100% free.

I'm working on setting up an unattended Ubuntu PC with Ubuntu Server 12.04 Minimal, and since this PC will be placed in a remote location with no keyboard or screen (unattended), I need to have a permanent SSH connection from this machine to a middle-server (between itself and me) - reason being, this PC will be behind a NAT firewall.

I followed dot-to-dot instructions at but when I connect, I just get an error Quote: ssh: connect to host port 19999: Connection refused So I went back googling for a solution and found

Surprisingly, Alexonlinux's solution worked out-of-the-box.

Seeing this, I tried the previous method, this time using Port 6333, but no luck. Then I tried Alexonlinux's method using Port 19999 and again it works fine.

The reason I can't stick to Alexonlinux's solution is, that it requires some commands to be entered on the PC behind the NAT, and that's not possible in my case.

I really wonder what could be stopping the connection when using Fabelier's method. Maybe the script is not loading? I did try manually running the script but still no luck.

I have also set

GatewayPorts yes

on the PC behind the NAT.

For the record, here's the script I've used from Fabalier's method:

a=`ps -ef | grep 19999 | grep -v grep`
if [ ! "$a" ]; then
    ssh -fN -R 19999:localhost:22 <middle-usename>@<middle-hostname>

(obviously I've changed the @ to the necessary) I had to change the first line as brackets were not acceptable.

Would really appreciate some help on this, pls.

share|improve this question
1) Both links are 404s, please fix them. 2) you start out very well (first paragraph), but I'm lost later on, could you rephrase pieces like "what could be stopping the connection"? 3) Does your actual question boils down to... "How can I keep this SSH reverse tunnel active in the background and automatically respawned?" as that's my best guess about your question right now. 4) that piece of script is a horrible way of checking things... –  gertvdijk Jan 11 '13 at 11:34
sorry about the links. Here they are, corrected:…… "what could be stopping the connection"; By this I was meaning, what could be causing the "connection failed" error. You're correct. I need to keep this SSH reverse tunnel active in the background and automatically respawned. But I need it to connect in the first place. –  user93078 Jan 11 '13 at 14:03
Please edit your question rather than providing new info via comments. –  gertvdijk Jan 11 '13 at 14:07
Okay, by re-reading your question I think your issue just boils down to a "connection refused" error on the remote/headless machine while running the ssh -R command. Is that correct? Then 1) make sure the 'machine in between' is accepting connections on port 22 (as you connect on the regular SSH port). 2) provide some more information like: does this work from another machine or from nowhere? (then issue is with the middle one). 3) I will probably be able to answer your issue, but this now looks way more complicated than it is, probably. –  gertvdijk Jan 12 '13 at 13:10
Thanks. Yes, the "middle" machine is accepting connections on Port22 - infact I do alot of SSH to it from anywhere. Also, as I mentioned, the reverse SSH tunnel is working when I use the method suggested at… where there is no script involved. I would stick to this method, but the only thing is, the remote/headless machine is an unattended one and I cannot have anyone entering commands into it, thus I need a script that will keep the remote/headless machine permanently connected to the middle machine. –  user93078 Jan 13 '13 at 7:27

1 Answer 1

I found this expect script that someone else had written. It works for me - I have remote/unattended devices behind firewall and routing owned by other companies. Instead of having to work with them to expose my ssh port to the world via port forwarding so I can access the devices, I wanted to be able to use Reverse SSH. So built my own little system to get around that.

The server side runs a PHP & MySQL based website. I can click on a device and go to it's page. I click "Reverse SSH" button, which puts the command "Reverse SSH" into the database with the device ID.

On the client side, I have a python script that runs every minute via crontab. Everytime it runs, it reports the system health info, cpu load, memory, disk space, etc via HTTP to the server. During that HTTP transaction, if a command is waiting for the device that checked in, I send the command back. The client side then matches that command, and executes a call to bash "expect /path/to/client/reversessh.expect".

The expect script is prefilled with my server ssh info (yeah, I know it's "insecure", but it works for now.), and establishes the Reverse SSH connection for up to 1 hour (you can set it to longer if you need). I can then log into the remote device from my locality.

The server I am running is Ubuntu Server 14.04, and the remote devices range from beaglebone black and virtual servers to desktop Pc's, RPi and RPi2.

On the debian based systems, I install expect via apt-get:

apt-get install expect

Here is the expect script, modify it as needed. It might take a moment to get it working but it does work. I hope the formatting doesn't get messed up, it is hard to copy and paste a large code block like this and get it to turn out right:

Example reversssh.expect

#!/usr/bin/expect -f
#Author: g0 2010 , 
#License:Same as Expect - Public Domain
#revtun sets up a reverse ssh tunnel  
#ssh example: ssh -R 1025:localhost:22 -p 443 user@ -fN
#Hardcode the arguments or pass them at this order on the command line
#eg:$revtun 1025 22 443 user password

set remoteport "1234" # this is the port on your server that will serve the tunnel
set localport "22" # ssh port of remote/target device
set port "2222" # This is the port in which the remote device will ssh into your server. If you use standard port for ssh on server then it is, it's 22.
set user "" #ssh user on your server 
set host "" # server host ie or
set password "" # user password for servers ssh user
set report_to "" # I never used this...see below line that starts with curl. In your web server php script do <?php print_r($_GET); ?>

if {$argc > 0} { set remoteport [lindex $argv 0] } 
if {$argc > 1} { set localport [lindex $argv 1] } 
if {$argc > 2} { set port [lindex $argv 2] } 
if {$argc > 3} { set user [lindex $argv 3] } 
if {$argc > 4} { set host [lindex $argv 4] } 
if {$argc > 5} { set password [lindex $argv 5] } 
if {$argc > 6} { set report_to [lindex $argv 6] } 

set message "m"

set timeout 3600 # number of seconds to keep the tunnel open, this is set to 1 hour.

set pid [spawn ssh -N -R $remoteport:localhost:$localport $user@$host -p $port]
while {1} {

        expect -nocase -re ".*yes/no?.*" {
                send "yes\r"
        } -nocase -re "password*" {
                send -- "$password\r\n"
                #send -- "\n"
        } -re "(%|\\\$|#) " {
                set message "$message-prompt"
        } eof {
                set message "$message-eof"
        } -re "incorrect|invalid" {
                set message "$message-incorrect"
        } -nocase -re ".*Warning.*" {
                set message "$message-warning"
        } timeout {
                set message "$message-timeout"


set user "$env(USER)"
exec curl $report_to?$user-$message --silent >/dev/null

#1 hour max connection time used to keep the script running

And if you want to keep it running if/when it goes down, I would use cron to run a bash script to check if the sshd program is running, if not running start it, otherwise do nothing. If you have other SSH connections going on, checking sshd may not work for you. Since this Reverse SSH script is the only SSH activity on the remote devices, it works for me. In my system, I can kill the Reverse SSH connection on a device by shooting off another command to the remote device when it checks in, "Disconnect Reverse SSH", and that causes the client side to run this command with bash:

kill `pidof sshd`

Edit your crontab with: crontab -e

The first 6 lines of the crontab file below are nice to specify, you may want to edit them to your liking.

Example crontab

MAILTO="" # local mail address to get cron messages, leave blank to disable
USER=root # run these cron jobs as root user
HOME=/root # root users home dir

# Example check reverse SSH connection - runs every minute
* * * * * bash /path/to/check_reverse_ssh.bash

Example check_reverse_ssh.bash

process_id=`ps aux | grep "sshd" | grep -v "grep"`
if [ -z "$process_id" ]; then
    echo "process not running for certain."
    expect /path/to/reversessh.expect &
    echo "sshd is running, If so, your tunnel should be good to go";

Good luck!

share|improve this answer

Your Answer


By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.