Putty-like SSH port forwarding on Linux and MacOS

January 31, 2023 | 4 minute read
Text Size 100%:

As a Linux or Mac user you benefit from a very useful, built-in terminal and SSH client implementation that’s mostly identical across all Unix-like systems. For a very long time Windows did not provide a SSH client out of the box leading to a pleathora of 3rd party clients. Putty is still one of the most popular tools available to perform remote administration on Windows, despite the fact that recent Windows versions do provide an SSH client.

One of the nice things in Putty is its ability to add port forwarding rules on the fly, e.g. after the session has already been established. A similar feature exists for SSH clients on MacOS and Linux, and even on Windows's command-line SSH client as it's based on OpenSSH, too.

Port-forwarding in openSSH clients

The contents of this post was tested with a wide range of SSH clients, from Oracle Linux 8.6 to Debian 11, Ubuntu 22.04, and Windows 10 22H2. Although no research has been conducted to find out when exactly dynamic SSH port forwarding was added to SSH clients it can safely be assumed the feature has been around for a while.

Port-forwarding at connection time

You can specify either the -L or -R flag (and -D for completely dynamic port-forwarding using SOCKS - which is not in scope of this article) when establishing a SSH session to a remote host, specifying how ports should be forwarded. Throw in the -N flag and you don’t even open your login shell! That’s a very convenient way to enable port forwarding. For example:

[user@somehost]$ ssh remoteuser@server2 -i ~/.ssh/remoteuser -L 8080:server2:8080 

Occasionally you may not know in advance which ports to forward, and establishing a new session might not be convenient. Wouldn’t it be nice if you could simply add a port forwarding rules just like with Putty?

Putty-like port-forwarding

Once established you can control the behaviour of your SSH session using escape characters. The ssh(1) man page dedicates an entire section to them. The most interesting escape sequence from this article's point of view is ~C. It opens a command line and allows you to make changes to the connection. Quoting verbatim from the man page:

[~C:] Open command line. Currently this allows the addition of port forwardings using the -L, -R and -D options (see above). It also allows the cancellation of existing port-forwardings with -KL[bind_address:]port for local, -KR[bind_address:]port for remote and -KD[bind_address:]port for dynamic port-forwardings. !command allows the user to execute a local command if the PermitLocalCommand option is enabled in ssh_config(5). Basic help is available, using the -h option.

Let’s try this in practice. Assuming you would like to use port-forwarding to tunnel the Oracle Enterprise Manager (EM) Express port for a Pluggable Databases (PDBs) to your local laptop. The database server name is server2. The first step is to find out which port is used for EM Express. Connected to the PDB in question, you can use DBMS_XDB_CONFIG to get the HTTPS port number like so:

SQL> show con_name


SQL> select dbms_xdb_config.gethttpsport from dual;


With that information at hand the port forwarding rule can be added to the currently established SSH session.

[remoteuser@server2 ~]$      # hit ~ followed by C to open the command line
ssh> L5510:server2:5510      # add a local port forwarding rule
Forwarding port.

As soon as you see the message “Forwarding port” you are all set, provided of course the ports are defined correctly in your forwarding rule and there’s no service running on port 5510 on your laptop. If you point a supprted web browser to https://localhost:5510/em the connection request is forwarded to server2’s port 5510. In other words, you connect to Enterprise Manager Express.

Should you find yourself in a situation where you’re unsure which ports you have forwarded, you can find out about that, too. Escape character ~# displays currently active, forwarded ports:

[remoteuser@server2 ~]$ ~#     # hit ~ followed by # to display the information
The following connections are open:
  #0 client-session (t4 r0 i0/0 o0/0 e[write]/4 fd 4/5/6 sock -1 cc -1 io 0x01/0x01)
  #3 direct-tcpip: listening port 5510 for server2 port 5510, connect from port 58950 to port 5510...

Your client session is always present as line #0. In the above output line #3 indicates the browser session connecting to EM Express. Unfortunately the forwarded port is only shown once an initial connection is established. This is close to Putty’s behaviour, but not a match. If you really need to know ports in LISTEN status you have to use lsof or netstat and related tools.

You can even stop forwarding sessions on the command line:

[remoteuser@server2 ~]$   # hit ~C again to enter the command line
ssh> KL5510            # remove local port forwarding definition
Canceled forwarding.

Once all sessions previously using the forwarded port have ended the forwarding definition is no longer listed in the output of ~#.


The ssh command line client offers quite a few options not many users are aware of. Dynamically adding port forwarding rules to a session is a great feature that comes in handy at times Although it’s not quite on par with Putty’s port forwarding options it’s nevertheless quite useful and you might find yourself using it. The sshd (= server) configuration must of course allow port forwarding for this to work, if port forwarding fails you’ll get a message similar to this on in your ssh session:

[remoteuser@server2 ~]$ channel 3: open failed: administratively prohibited: open failed

Please see for yourself how useful the feature is, there are many cases the author has made use of the dynamic port forwarding when working on the command line.

Martin Bach

Martin is a product manager at Oracle helping customers in Europe and around the world address their IT related problems. He is most interested in cloud technology, DevOps and how these can be used best with Oracle technology.

Previous Post

Cloud native DevOps with Oracle Linux and VirtualBox: It's all about increasing business velocity

Gursewak Sokhi | 5 min read

Next Post

Oracle B2C Service - Introducing Dynamic Values to Workspace Rule Actions

Jyothi Krishna P | 5 min read