Forwarding a remote port over SSH exposes a listening port on a server that actually terminates connections on a client-side or internal service. This pattern provides a controlled path into environments behind firewalls, enables reverse tunnels from systems without public addresses, and centralizes external access through a single OpenSSH endpoint.

Remote port forwarding in OpenSSH uses the -R flag to instruct the remote sshd process to listen on a port and forward traffic over an encrypted channel to a target host and port reachable from the client. Binding addresses control whether the listening socket is only on the remote loopback interface or is reachable from other systems, and server-side options such as GatewayPorts and AllowTcpForwarding govern what clients are allowed to request.

Allowing remote port forwarding can expose sensitive local or internal services if configuration is too permissive or tunnels remain open longer than necessary. Server policies should restrict which users can forward ports and which destinations are reachable, and production environments should monitor tunnels and clean up stale sessions. The commands assume basic shell access to both ends of the connection and a remote sshd configuration that permits remote forwarding.

Steps to forward a remote port in SSH:

  1. Open a terminal on the local system that will initiate the SSH connection.
    $ whoami
    alice
  2. Confirm that the local or internal service to be exposed is reachable from the client machine.
    $ ss -tlnp | grep 8080
    LISTEN 0      128          127.0.0.1:8080       0.0.0.0:*    users:(("python3",pid=4242,fd=3))

    Local loopback listeners such as 127.0.0.1:8080 are common for development web servers.

  3. Start an SSH session that sets up a basic remote port forward bound to the remote loopback interface.
    $ ssh -R 9000:localhost:8080 user@server.example.com
    user@server.example.com's password:
    Welcome to Ubuntu 22.04.4 LTS
    Last login: Mon May 13 10:10:01 2024 from 198.51.100.23
    ##### snipped #####

    The -R option uses the form remote_port:target_host:target_port to tell sshd which port to listen on and where to send the traffic.

  4. On the remote server reached by the SSH session, verify that the forwarded port is listening on the loopback address.
    $ ss -tlnp | grep 9000
    LISTEN 0      128          127.0.0.1:9000       0.0.0.0:*    users:(("sshd",pid=1532,fd=9))

    A loopback-only bind ensures that only processes on the remote server can connect to the forwarded port.

  5. From the remote server, access the forwarded port to confirm that the tunneled service responds correctly.
    $ curl -s http://127.0.0.1:9000/ | head -n 5
    <!doctype html>
    <html>
      <head><title>Local app</title></head>
      <body>
    ##### snipped #####
  6. To make the remote forwarded port reachable from other hosts, start an SSH session that binds the remote socket to an explicit address such as 0.0.0.0.
    $ ssh -R 0.0.0.0:9000:localhost:8080 user@server.example.com

    Binding to 0.0.0.0 combined with a permissive firewall exposes the tunneled service to any host that can reach the remote server.

  7. If binding to non-loopback addresses fails, review the remote sshd configuration for forwarding-related directives.
    $ sudo grep -E '^(AllowTcpForwarding|GatewayPorts|PermitOpen)' /etc/ssh/sshd_config
    AllowTcpForwarding remote
    GatewayPorts clientspecified
    PermitOpen localhost:8080

    AllowTcpForwarding controls whether clients may request any port forwarding, and GatewayPorts determines whether non-loopback bind addresses from the client are honored.

  8. Adjust the forwarding directives in /etc/ssh/sshd_config so that remote port forwarding follows the required policy, using a restrictive PermitOpen list where necessary.
    ///etc/ssh/sshd_config
    AllowTcpForwarding remote
    GatewayPorts clientspecified
    PermitOpen localhost:8080

    Limiting PermitOpen to specific destinations prevents untrusted users from turning the server into a generic TCP relay.

  9. Validate the updated sshd configuration for syntax errors.
    $ sudo sshd -t

    Syntax errors in /etc/ssh/sshd_config can stop sshd from starting and block remote logins until fixed via console or recovery access.

  10. Reload the remote sshd service to apply configuration changes without interrupting existing sessions.
    $ sudo systemctl reload sshd
  11. From a separate host that can reach the remote server, connect to the forwarded remote port to confirm that the tunneled service is available.
    $ curl -s http://server.example.com:9000/ | head -n 5
    <!doctype html>
    <html>
      <head><title>Local app</title></head>
      <body>
    ##### snipped #####
  12. Close the SSH session when the remote forwarded port is no longer needed to remove the listening socket.
    $ exit
    Connection to server.example.com closed.

    Long-lived remote port forwards increase exposure for the tunneled service and should be shut down when tasks complete or no longer require remote access.

Discuss the article:

Comment anonymously. Login not required.