The way you are using the -R option, it means you want the remote side to bind only to the loopback interface. From the ssh manual page:
-R [bind_address:]port:host:hostport
...
By default, TCP listening sockets on the server will be bound to the loopback interface only. This may be overridden by
specifying a bind_address. An empty bind_address, or the address ‘*’, indicates that the remote socket should listen on
all interfaces. Specifying a remote bind_address will only succeed if the server's GatewayPorts option is enabled (see
sshd_config(5)).
Simplified this means:
-R port:host:hostport will bind to loopback only
-R :port:host:hostport will bind to all interfaces
- as will
-R *:port:host:hostport and -R 0.0.0.0:port:host:hostport
So in your situation, any of these should work:
ssh -R :80:localhost:80 root@139.162.19.185
ssh -R *:80:localhost:80 root@139.162.19.185
ssh -R 0.0.0.0:80:localhost:80 root@139.162.19.185
*Below my original attempt to explain this behavior based on the documentation text - with some clarifications.
You used the PORT:IP:PORT syntax, which didn't specify a bind_address.
The text specifying a bind_address in the above description refers to there being a : before the remote port(The first port in PORT:IP:PORT). The way you have it in your example, there is no :, which means that you did not specify a bind_address, and according to the man page the remote side will bind only to the loopback interface (default). In order to bind to all interfaces, you need to specify a bind_address (i.e. add a : before the remote port), even if the actual bind_address is an "empty string"! Either an "empty string" or a * would work in this case, but keep in mind that the : is mandatory for it to not be limited to binding to the loopback address only!
Update
After the comments from @barlop, it seems my explanation was not very clear, so I am trying to clarify things here step by step:
- The option is defined as
-R [bind_address:]port:host:hostport.
- The whole
[bind_address:] part is optional. If it is not present,then the option has the format -R port:host:hostport and the default behavior applies, which means TCP listening sockets on the server will be bound to the loopback interface only.
- If the
[bind_address:] part is present, it means we have the format -R bind_address:port:host:hostport, notice that now the first : is not optional any more. From this moment on, bind_address can take several values, one of the possible values is indeed an empty string! So adding the colon to the option, means we do specify a bind_address this time, albeit an empty one (which, according to the description is taken to mean the remote socket should listen to all interfaces.
I hope this makes it a little more clear, basically not specifying a bind_address and specifying an empty string as bind_address are two different things! The "empty string" bind_address is considered to be a bind address, and refers to using :PORT:IP:PORT syntax without writing in anything there for the address, before the far left colon!.
Here is the output from me testing it (on a different port, but same effect):
See it's SSHing and running netstat -an on the remote machine.
gepa@localhost:~$ ssh -R :5555:localhost:5555 cloud1 netstat -an | grep :5555
tcp 0 0 0.0.0.0:5555 0.0.0.0:* LISTEN
tcp6 0 0 :::5555 :::* LISTEN
gepa@localhost:~$ ssh -R 5555:localhost:5555 cloud1 netstat -an | grep :5555
tcp 0 0 127.0.0.1:5555 0.0.0.0:* LISTEN
tcp6 0 0 ::1:5555 :::* LISTEN
Notice how adding a : before the first 5555 makes the remote host listen to all interfaces compared to omitting the :.
BTW, It is far more clear not to use an empty string bind_address and to write $ ssh -R *:5555:localhost:5555 comp or 0.0.0.0:80:localhost:80
Also the reason why the PORT:IP:PORT syntax binds to 127.0.0.1 is for security reasons. So if you do want it to bind non-locally, it's better if you make it very clear e.g. with a wildcard or specifying 0.0.0.0 or specifying a LAN address if only connecting from your LAN.
GatewayPorts yesandGatewayPorts clientspecifiedcan both be considered "enabled", but they are not equivalent in the context of your problem. – Kamil Maciorowski Feb 10 '23 at 16:23