I have two machines, Client and Server.

Client (who is behind a corporate firewall) opens a reverse SSH tunnel to Server, which has a publicly-accessible IP address, using this command:

ssh -nNT -R0:localhost:2222 [email protected]

In OpenSSH 5.3+, the 0 occurring just after the -R means "pick an available port" rather than explicitly calling for one. The reason I'm doing this is because I don't want to pick a port that's already in use. In truth, there are actually many Clients out there that need to set up similar tunnels.

The problem at this point is that the server does not know which Client is which. If we want to connect back to one of these Clients (via localhost) then how do we know which port refers to which client?

I'm aware that ssh reports the port number to the command line when used in the above manner. However, I'd also like to use autossh to keep the sessions alive. autossh runs its child process via fork/exec, presumably, so that the output of the actual ssh command is lost in the ether.

Furthermore, I can't think of any other way to get the remote port from Client. Thus, I'm wondering if there is a way to determine this port on Server.

One idea I have is to somehow use /etc/sshrc, which is supposedly a script that runs for every connection. However, I don't know how one would get the pertinent information here (perhaps the PID of the particular sshd process handling that connection?) I'd love some pointers.


  • 2
    Wouldn't a VPN be more appropriate? OpenVPN is super simple to configure. Jun 27, 2012 at 21:12
  • Sounds interesting. I don't know much about VPN. Is this something that could work even if the Client machine is configured to use DHCP?
    – Tom
    Jun 27, 2012 at 21:25
  • 1
    Yes, it runs off another TUN/TAP interface, so other interfaces are irrelevant. Jun 27, 2012 at 21:28
  • @sonassi, it looks like this VPN thing will do the trick. Thanks for the info.
    – Tom
    Jun 28, 2012 at 0:22
  • I've added an answer below specifically guiding you through the VPN process with OpenVPN (based on Debian/Ubuntu) Jun 28, 2012 at 11:22

6 Answers 6


Wouldn't a VPN be more appropriate? OpenVPN is super simple to configure. Here is a sample config and some links to guide your through the certificate creation process:

apt-get install openvpn
mkdir /etc/openvpn/easy-rsa
mkdir -p /etc/openvpn/ccd/client_server
touch /etc/openvpn/ipp.txt
cp -a /usr/share/doc/openvpn/examples/easy-rsa/2.0/* /etc/openvpn/easy-rsa
cd /etc/openvpn/easy-rsa
source ./vars
./build-key-server server
cd /etc/openvpn/easy-rsa/keys
openssl pkcs12 -export -out server.p12 -inkey server.key -in server.crt -certfile ca.crt

Then create a new file /etc/openvpn/client_server.conf and put the following in it, changing the SERVER_IP_ADDRESS as appropriate

port 8443
proto udp
dev tun
ca /etc/openvpn/easy-rsa/keys/ca.crt
pkcs12 /etc/openvpn/easy-rsa/keys/server.p12
dh /etc/openvpn/easy-rsa/keys/dh1024.pem
ifconfig-pool-persist /etc/openvpn/ipp.txt
client-config-dir /etc/openvpn/ccd/client_server
keepalive 10 120
status /var/log/openvpn-status.log
verb 3
reneg-sec 0

Then build a key per user who is going to connect, and create the config file in the ccd dir

./build-key-pkcs12 [email protected]
echo "ifconfig-push" > /etc/openvpn/ccd/client_server/[email protected]

The IP address MUST be suitable for a /30 subnet (see http://www.subnet-calculator.com/cidr.php), as there is only 2 addresses available (server and client) per connection. So your next available client IP would be and so on.

Then you now have static IPs per connecting user.

Then supply the [email protected] file to the end-user and use the following config file

dev tun
proto udp
pkcs12 [email protected]
resolv-retry infinite
ns-cert-type server
verb 3
reneg-sec 0
  • Thanks for the thorough answer! I do have two questions about this, though. A) Specifying the for the client's ifconfig-push line does not seem to work, but it does work if I specify a second IP address. Why is this? And B) does this approach mean that 4 IP addresses are used per connection?
    – Tom
    Jun 28, 2012 at 18:01
  • On some Linux systems, the syntax for the ifconfig-push line is different. Eg. ifconfig-push - I've no idea why it differs on platforms. And yes, it means 4 IPs are used per client (wasteful, but the nature of the beast). Jun 28, 2012 at 18:07

If the clients each have different usernames, you can use netstat to find out what port that user's sshd process is listening on. For example:

% sudo netstat -tlpn | grep 'sshd: mgorven@'
tcp        0      0*               LISTEN      5293/sshd: mgorven@
tcp        0      0*               LISTEN      5293/sshd: mgorven@
  • You can, but this requires running netstat as root on the bastion server, which is ideally avoided Jun 8, 2020 at 21:52

You could alter the ephemeral port range (/proc/sys/net/ipv4/ip_local_port_range for Linux) and then use statically allocated ports outside that range.

  • No need to change the ephemeral range for that. By default the ephemeral range ends at 61000, so there is thousands of available port numbers above that. I have often used echo $[61002+RANDOM%4532] to pick a port number in that range.
    – kasperd
    Jul 1, 2017 at 18:00
  • The problem with statically allocated ports is that a client will be unable to reconnect if and forward that port if the server is still holding a previous connection using it. If the client doesn't shut down cleanly, the server may preserve that for a few minutes. Jun 8, 2020 at 21:53

I want the same setup like you, I increased the log level of the SSH server to DEBUG, and it showed in the logs what was the local port of the client

for example:

client command: ssh -N -R0: [email protected]

server log:

Jun 30 11:28:59 debsid sshd[27577]: debug1: Local forwarding listening on port 35391

there you see the port number


You should be able to extract the relevant information from the output of:

lsof -i tcp

Run as root.


Run this script on the server:

sudo lsof -i -n | grep "sshd" | grep "(LISTEN)" | awk '{print $2}' | while read line; do sudo lsof -i -n | egrep $line | sed 3~3d | sed 's/.*->//' | sed 's/:......*(ESTABLISHED)//' | sed 's/.*://' | sed 's/(.*//' | sed 'N;s/\n/:/' 2>&1 ;done

You may or may not need the two sudo's. Remove if you don't.

PS - This is a modified version of a solution I found elsewhere a while back. I think it may have come from StackOverflow, but I can't find the original reference.

You must log in to answer this question.

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