How to make ssh tunnel open to public?

189

87

Well, referring back to this question, I am running the command

ssh -R 8080:localhost:80 -N root@example.com

on a Mac. Yet the port that is being tunneled is not working publicly. I am running such a command to make it so that the local port can be opened on the remote computer. And it does work when opening the port on localhost on the remote computer, but when I try to access the public IP address of the remote computer from my local computer the port doesn’t seem to be open. How would I make the tunnel public on the IP for anyone to access?

EDIT: It seems as if the remote side binds only on localhost instead of to all interfaces.

EDIT 2: The client is Mac OS X 10.6 and the server is Linux Mint, but they’re both OpenSSH.

Trevor Rudolph

Posted 2013-04-27T22:14:51.060

Reputation: 2 021

What does public IP mean? If you are trying to connect to a local computer thru the router and via the Internet, most routers will not allow such loopback. – harrymc – 2013-04-30T05:53:40.977

Answers

368

If you check the man page for ssh, you'll find that the syntax for -R reads:

-R [bind_address:]port:host:hostport

When bind_address is omitted (as in your example), the port is bound on the loopback interface only. In order to make it bind to all interfaces, use

ssh -R \*:8080:localhost:80 -N root@example.com

or

ssh -R 0.0.0.0:8080:localhost:80 -N root@example.com

or

ssh -R "[::]:8080:localhost:80" -N root@example.com

The first version binds to all interfaces individually. The second version creates a general IPv4-only bind, which means that the port is accessible on all interfaces via IPv4. The third version is probably technically equivalent to the first, but again it creates only a single bind to ::, which means that the port is accessible via IPv6 natively and via IPv4 through IPv4-mapped IPv6 addresses (doesn't work on Windows, OpenBSD).  (You need the quotes because [::] could be interpreted as a glob otherwise.)

Note that if you use OpenSSH sshd server, the server's GatewayPorts option needs to be enabled (set to yes or clientspecified) for this to work (check file /etc/ssh/sshd_config on the server). Otherwise (default value for this option is no), the server will always force the port to be bound on the loopback interface only.

Stefan Seidel

Posted 2013-04-27T22:14:51.060

Reputation: 8 812

I used -L instead of -R and it also works – Daneel S. Yaitskov – 2016-08-09T09:04:35.903

42GatewayPorts yes solved my problem. – Sunry – 2016-10-25T08:18:59.723

4GatewayPorts = yes (on the remote sshd config) fixed it for me too – Phil_1984_ – 2016-12-05T13:29:34.733

3"GatewayPorts yes" made my day, thanks @StefanSeidel – karser – 2017-10-27T10:40:42.863

YOU ARE A FING HERO – php_nub_qq – 2018-12-21T21:45:52.423

1Note that GatewayPorts yes actually makes the bind_address irrelevant: "The argument may be [...], yes to force remote port forwardings to bind to the wildcard address" – Michał Politowski – 2019-03-15T18:30:24.470

By defautl "GatewayPorts" argument is not exist. Thank you pro! – Owl City – 2019-04-17T02:03:34.180

GatewayPorts yes in my ~/.ssh/config worked well in macOS – surjikal – 2019-10-12T19:39:36.770

14OH MY GOD IT WORKED!!!!! I have done exactly that 1 million times!! I just forgot that * in bash will give files and i needed \* – Trevor Rudolph – 2013-05-06T07:08:51.317

1I feel so dumb right now! But thank you! – Trevor Rudolph – 2013-05-06T07:09:19.833

4Yeah, that's exactly why I always prefer 0.0.0.0 - it's IPv4 only, but it'll do most of the time :) – Stefan Seidel – 2013-05-06T07:51:30.793

1fe80::1 hahaha – Trevor Rudolph – 2013-05-06T07:54:24.113

jk :D yea but 0.0.0.0 is good, but can you use 127.0.0.1? or is that too local and nonbinding – Trevor Rudolph – 2013-05-06T07:55:00.523

Well, actually [::] should work for all v4+v6! 127.0.0.1 means loopback, i.e. you're back to square one ;) – Stefan Seidel – 2013-05-06T08:06:03.937

yea, i thought as much, but 0.0.0.0 will bind directly to the ipv4 interface so its not device specific – Trevor Rudolph – 2013-05-06T09:01:17.953

and [::] is only ipv6 right? How can it be used in ipv4? – Trevor Rudolph – 2013-05-06T09:01:36.300

1No, [::] means 0:0:0:0:0....:0 and is essentially the IPv6 equivalent of 0.0.0.0 - but since IPv4 is basically a subset of IPv6 (e.g. ::ffff:10.120.78.40 is an IPv4-mapped IPv6 address), it'll mean the port is accessible both via IPv6 and IPv4. – Stefan Seidel – 2013-05-06T09:11:48.427

well yea, i actualy jsut researched ipv6 for a half hour and now instead or \*: im using [::0]: – Trevor Rudolph – 2013-05-06T09:31:04.307

and instead of localhost im using [::1] works like a charm – Trevor Rudolph – 2013-05-06T09:31:34.967

40

Edit:

-g works for local forwarded ports, but what you want is a reverse/remote forwarded port, which is different.

What you want is this.

Essentially, on example.com, set GatewayPorts=clientspecified in /etc/ssh/sshd_config.

--- previous (incorrect) answer ---

Use the -g option. From ssh's man page:

-g     Allows remote hosts to connect to local forwarded ports.

snapshoe

Posted 2013-04-27T22:14:51.060

Reputation: 939

doesn't seem to be working... it starts up but i cant connect remotely – Trevor Rudolph – 2013-04-28T06:21:14.053

2Try running netstat -elnpt from a separate tty to figure out what ports are bound to what address. Without -g, a port should be bound to 127.0.0.1:PORT. With -g, it should be bound to 0.0.0.0:PORT, which makes it accessible remotely. – snapshoe – 2013-04-28T14:58:20.097

http://pastebin.com/q6f4kJyd – Trevor Rudolph – 2013-04-28T16:11:24.827

2GatewayPorts=clientspecified or GatewayPorts clientspecified – Trevor Rudolph – 2013-04-29T00:01:28.043

and do i add that to the client or remote? – Trevor Rudolph – 2013-04-29T00:04:42.007

already answered in the answer-- on website.com – snapshoe – 2013-04-30T15:08:13.183

ok, ill try now – Trevor Rudolph – 2013-04-30T20:53:45.297

15

Here's my answer for completion:

I ended up using ssh -R ... for tunneling, and using socat on top of that for redirecting network traffic to 127.0.0.1:

tunnel binded to 127.0.0.1: ssh -R mitm:9999:<my.ip>:8084 me@mitm

socat: mitm$ socat TCP-LISTEN:9090,fork TCP:127.0.0.1:9999

Other option is to do a local-only tunnel on top of that, but i find this much slower

mitm$ ssh -L<mitm.ip.address>:9090:localhost:9999 localhost

Miguel Ping

Posted 2013-04-27T22:14:51.060

Reputation: 322

1+up you go good sir. I tried to tell ssh to bind to 0.0.0.0 without success.. then saw the * syntax, tried that, no dice. I imagine it may be some sort of security feature on sshd config or something that isn't allowing it.

Finally saw this post and socat worked awesome. Super useful, putting this in my back pocket ;] – Jaime – 2019-06-24T23:45:20.263

I like the fact that I don't have to deal with the sshd configuration and that I can do all of it without sudo. Plus I learn that socat exists. Thanks! – BrutusCat – 2014-06-12T14:00:32.433

10

You can also use a double forward if you won´t or can change /etc/ssh/sshd_config.

First forward to temporary port (e.g. 10080) on loopback device on the remote machine, then use local forward there to redirect port 10080 to 80 on all interfaces:

ssh -A -R 10080:localhost_or_machine_from:80 user@remote.tld "ssh -g -N -L 80:localhost:10080 localhost"

panticz.de

Posted 2013-04-27T22:14:51.060

Reputation: 231

1This actually works to bypass forwarding rules! – Michael Schubert – 2016-12-03T18:49:00.610

Love this solution. Great workaround when you don't want the change the config on the machine – Grezzo – 2017-08-18T14:54:01.133

8

Use the "gateway ports" option.

ssh -g -R REMOTE_PORT:HOST:PORT ...

In order to use that, you probably need to add "GatewayPorts yes" to your server's /etc/ssh/sshd_config.

Raúl Salinas-Monteagudo

Posted 2013-04-27T22:14:51.060

Reputation: 1 058

Actually this worked. What I do is that I use an EC2 instance as a forwarder to my REST server. This way, I don't need to stick my server in the DMZ and I don't need a public IP. Funny enough, with the first EC2 instance I created, ssh -R remote_port:localhost:port xxx@ec2xxx worked just fine but then I had to create another instance later on for some reason and from that point on, I was always getting: connection refused. Used tcpdump to look at what I was getting and there wasn't much info. -g plus GatewayPorts yes did the trick. – E.T – 2017-01-24T19:12:42.963

2

Jump hosts are a fairly recent addition to OpenSSH. This requires SSH access to the intermediate, but should work without additional configuration.

ssh -J root@example.com remoteuser@localhost -p 8080

This command instructs SSH to first connect to root@example.com, and then, from that machine, to initiate a connection to port 8080 at localhost (i.e., the port that is tunneled from the jump host to the remote host) under the remoteuser user name.

krlmlr

Posted 2013-04-27T22:14:51.060

Reputation: 572

0

If you'd like to put the configuration in you ~/.ssh/config instead of using command line parameters, you can try something like

Host REMOTE_HOST_NAME RemoteForward \*:8080 127.0.0.1:80

Remember to have you remote host's firewall allow connections to 8080 and ensure that the GatewayPorts option of your /etc/ssh/sshd config isnt set to no

Brad Mostert

Posted 2013-04-27T22:14:51.060

Reputation: 1