Forward a TCP port from an SSH server to an SSH client
Content |
Tested on |
Debian (Etch, Lenny, Squeeze) |
Ubuntu (Hardy, Intrepid, Jaunty, Karmic, Lucid, Maverick, Natty, Precise) |
Objective
To forward connections on a particular TCP port from an SSH server to an SSH client.
Scenario
Suppose that you wish to connect to a remote machine using SSH in order to run programs, but forward any print jobs back to a CUPS server running on your local machine using IPP. Your local machine does not have a public IP address, and in any event you would prefer not to make the CUPS server publicly accessible.

Method
Overview
When you connect to a machine using SSH you can ask for one or more TCP ports to be forwarded through the secure channel. This does not interfere with the normal operation of SSH, and if required you can multiplex several ports through the same channel. The endpoints of a forwarded connection need not be on the machines running SSH.
The CUPS server will be running on the same machine as the SSH client, and the CUPS client on the same machine as the SSH server. You therefore need to forward connections from the SSH server back to the client.
The default port for IPP is 631, however if the machine running the SSH server has its own CUPS server then this port will already be taken. These instructions therefore use a different port number (8631) for that end of the connection.
IPP is a well-behaved protocol that is not adversely affected by the forwarding process. You should be aware that this is not true of all protocols. The issues are similar to those which arise when performing NAT, so if a protocol cannot traverse a NAT gateway (or can do so only with explicit support from the gateway) then it is unlikely to work when forwarded using SSH.
Establish the SSH connection
To forward a port from the server to the client use the -R
option when establishing the connection:
ssh -R 127.0.0.1:8631:127.0.0.1:631 ssh.example.com
The four colon-separated arguments following the -R
option have the following meaning:
- The first argument (127.0.0.1) is the address that the SSH server should bind to when listening for connections.
- The second argument (8631) is the port number on which the SSH server should listen for connections.
- The third argument (127.0.0.1) is the address to which the SSH client should forward connections.
- The fourth argument (631) is the port number to which the SSH client should forward connections.
Binding to the loopback address prevents other machine from connecting to the port, which is almost certainly the right behaviour for the scenario described here. See below if you want to allow connections from other machines.
Instruct remote client processes to use the forwarded port
If the default port for the relevant protocol is available, and you have instructed SSH to listen on it, then it is possible that remote clients will connect by default without any further intervention. Otherwise, the remote client will need to be told what to connect to.
In this particular scenario the default port for IPP is 631, but the port that has been forwarded is 8631. The CUPS client configuration should be altered to reflect this:
ServerName 127.0.0.1:8631
The ServerName
directive can be placed either in the global configuration file (typically /etc/cups/client.conf
) or the configuration file for a particular user (typically ~/.cups/client.conf
).
An alternative would be to make the local printer known to the remote CUPS server (if there is one) using 127.0.0.1:8631 as the hostname in the printer URI. This would allow programs to choose between using a local printer or a remote one.
Testing
In the scenario considered here, and assuming that you have added a ServerName
directive as described above, you should now be able to access any printers known to the CUPS server on the local machine. For example, it should be possible to use the lpstat
command to list the available printers and their current status:
lpstat -p
Troubleshooting
See Troubleshooting SSH port forwarding.
Variations
Allow connections from other machines
The instructions above assume that you want the SSH server to bind to the loopback address when listening for connections to forward. This prevents connections from other machines, which is usually the appropriate behaviour.
If you want to bind to the wildcard address instead then you must first change the GatewayPorts
setting in the SSH server configuration file (typically /etc/ssh/sshd_config
) to clientspecified
:
GatewayPorts clientspecified
The default is ‘no’, in which case the server binds to the loopback address regardless of what is specified on the command line. You can set GatewayPorts
to ‘yes’, which forces the server to bind to the wildcard address, but this is inadvisable because it could lead you to believe that access is limited when it is not.
The SSH server must be restarted for the configuration change to take effect. Afterwards it should be possible to bind to the wildcard address by omitting the first argument to the -R
option:
ssh -R :8631:127.0.0.1:631 ssh.example.com
Exercise caution when using SSH in this manner. In the absence of any firewall rules, the effect of the above command would be to make local printers accessible to any machine on the Internet. Worse, so far as the local CUPS server is concerned, connections will appear to originate from localhost. Thus, even if CUPS has been configured to refuse non-local connections, the use of port forwarding would circumvent that protection.
See also
Tags: ssh