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
    user
  2. Confirm that the local or internal service to be exposed is reachable from the client machine.
    $ ss -tlnp | grep 8081
    LISTEN 0      5          127.0.0.1:8081       0.0.0.0:*    users:(("python3",pid=14599,fd=3))        

    Local loopback listeners such as 127.0.0.1:8081 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 -f -N -R 9000:localhost:8081 user@host.example.net

    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=15136,fd=8))                         
    LISTEN 0      128            [::1]:9000          [::]:*    users:(("sshd",pid=15136,fd=7))                         

    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 lang="en">
    <head>
    <meta charset="utf-8">
    <title>Directory listing for /</title>
    ##### 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 -f -N -R 0.0.0.0:9000:localhost:8081 user@host.example.net

    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:8081

    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:8081

    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://host.example.net:9000/ | head -n 5
    <!DOCTYPE HTML>
    <html lang="en">
    <head>
    <meta charset="utf-8">
    <title>Directory listing for /</title>
    ##### snipped #####
  12. Close the SSH session when the remote forwarded port is no longer needed to remove the listening socket.
    $ pkill -f "ssh -f -N -R 9000:localhost:8081"

    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.