Why does `curl <this machine's IP>` behave differently than `curl localhost`?

In your ssh command, you are not specifying a bind_address for your -L option.

According to man ssh:

By default, the local port is bound in accordance with the GatewayPorts setting. However, an explicit bind_address may be used to bind the connection to a specific address. The bind_address of localhost indicates that the listening port be bound for local use only, while an empty address or * indicates that the port should be available from all interfaces.

To allow connections on all interfaces and not just localhost (which is an alias for 127.0.0.1, the address of the loopback interface), specify a bind_address of 0.0.0.0 in your -L option, e.g.

sudo ssh -L 0.0.0.0:140:localhost:8000 [email protected] -N

If you would prefer it listen on a particular IP, you can specify it instead of 0.0.0.0.


This is what man 1 ssh states:

-L [bind_address:]port:host:hostport
-L [bind_address:]port:remote_socket
-L local_socket:host:hostport
-L local_socket:remote_socket

Specifies that connections to the given TCP port or Unix socket on the local (client) host are to be forwarded to the given host and port, or Unix socket, on the remote side. […]

By default, the local port is bound in accordance with the GatewayPorts setting. However, an explicit bind_address may be used to bind the connection to a specific address. The bind_address of localhost indicates that the listening port be bound for local use only, while an empty address or * indicates that the port should be available from all interfaces.

GatewayPorts mentioned is the one from ssh_config (not the one from sshd_config, this one is for -R). From man 5 ssh_config:

GatewayPorts

Specifies whether remote hosts are allowed to connect to local forwarded ports. By default, ssh(1) binds local port forwardings to the loopback address. This prevents other remote hosts from connecting to forwarded ports. GatewayPorts can be used to specify that ssh should bind local port forwardings to the wildcard address, thus allowing remote hosts to connect to forwarded ports. The argument must be yes or no (the default).

Your command

ssh -L 140:localhost:8000 [email protected] -N

does not specify bind_address, it qualifies to "by default". It looks like GatewayPorts for ssh is no.

Note "an empty address" looks differently: -L :140:localhost:8000. The extra colon matters. This variant does specify bind_address as an empty string, while -L 140:localhost:8000 you used does not specify bind_address at all.

To bind to all interfaces use an empty address (-L :140:localhost:8000) or * (in a shell you should quote it, e.g. -L '*':140:localhost:8000).