How to make an SSH tunnel publicly accessible?

181,939

Solution 1

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 [email protected]

or

ssh -R 0.0.0.0:8080:localhost:80 -N [email protected]

or

ssh -R "[::]:8080:localhost:80" -N [email protected]

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 (clientspecified, or, in rare cases, to yes) 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.

Solution 2

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.

Solution 3

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

Solution 4

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 [email protected] "ssh -g -N -L 80:localhost:10080 localhost"

Solution 5

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.

Share:
181,939

Related videos on Youtube

Trevor Rudolph
Author by

Trevor Rudolph

im a coder

Updated on September 18, 2022

Comments

  • Trevor Rudolph
    Trevor Rudolph over 1 year

    Referring back to this question, I am executing the below via OpenSSH (Client: Mac OS X 10.6 | Server: Linux Mint), however the port that is being tunneled is not working publicly:

    ssh -R 8080:localhost:80 -N [email protected]
    
    • The purpose is so the local port can be opened on the remote computer
    • It seems as if the remote side binds only on localhost, instead of to all interfaces
    • It works when opening the port on localhost on the remote computer, but when trying to access the public IP 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?

    • Admin
      Admin about 11 years
      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.
  • Trevor Rudolph
    Trevor Rudolph about 11 years
    doesn't seem to be working... it starts up but i cant connect remotely
  • snapshoe
    snapshoe about 11 years
    Try 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.
  • Trevor Rudolph
    Trevor Rudolph about 11 years
  • Trevor Rudolph
    Trevor Rudolph about 11 years
    GatewayPorts=clientspecified or GatewayPorts clientspecified
  • Trevor Rudolph
    Trevor Rudolph about 11 years
    and do i add that to the client or remote?
  • snapshoe
    snapshoe about 11 years
    already answered in the answer-- on website.com
  • Trevor Rudolph
    Trevor Rudolph about 11 years
    OH MY GOD IT WORKED!!!!! I have done exactly that 1 million times!! I just forgot that * in bash will give files and i needed \*
  • Stefan Seidel
    Stefan Seidel about 11 years
    Yeah, that's exactly why I always prefer 0.0.0.0 - it's IPv4 only, but it'll do most of the time :)
  • Trevor Rudolph
    Trevor Rudolph about 11 years
    fe80::1 hahaha
  • Trevor Rudolph
    Trevor Rudolph about 11 years
    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
  • Stefan Seidel
    Stefan Seidel about 11 years
    Well, actually [::] should work for all v4+v6! 127.0.0.1 means loopback, i.e. you're back to square one ;)
  • Trevor Rudolph
    Trevor Rudolph about 11 years
    yea, i thought as much, but 0.0.0.0 will bind directly to the ipv4 interface so its not device specific
  • Trevor Rudolph
    Trevor Rudolph about 11 years
    and [::] is only ipv6 right? How can it be used in ipv4?
  • Stefan Seidel
    Stefan Seidel about 11 years
    No, [::] 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.
  • Trevor Rudolph
    Trevor Rudolph about 11 years
    well yea, i actualy jsut researched ipv6 for a half hour and now instead or \*: im using [::0]:
  • Trevor Rudolph
    Trevor Rudolph about 11 years
    and instead of localhost im using [::1] works like a charm
  • Giovanni Luisotto
    Giovanni Luisotto almost 10 years
    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!
  • Daniil Iaitskov
    Daniil Iaitskov almost 8 years
    I used -L instead of -R and it also works
  • Sunry
    Sunry over 7 years
    GatewayPorts yes solved my problem.
  • Michael Schubert
    Michael Schubert over 7 years
    This actually works to bypass forwarding rules!
  • Phil_1984_
    Phil_1984_ over 7 years
    GatewayPorts = yes (on the remote sshd config) fixed it for me too
  • E.T
    E.T over 7 years
    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.
  • Grezzo
    Grezzo almost 7 years
    Love this solution. Great workaround when you don't want the change the config on the machine
  • karser
    karser over 6 years
    "GatewayPorts yes" made my day, thanks @StefanSeidel
  • php_nub_qq
    php_nub_qq over 5 years
    YOU ARE A FING HERO
  • Michał Politowski
    Michał Politowski about 5 years
    Note 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"
  • Owl City
    Owl City about 5 years
    By defautl "GatewayPorts" argument is not exist. Thank you pro!
  • Jaime
    Jaime almost 5 years
    +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 ;]
  • surj
    surj over 4 years
    GatewayPorts yes in my ~/.ssh/config worked well in macOS
  • oliora
    oliora about 4 years
    Thank you for the answer! It make sense to add a note that user needs to restart sshd after the configuration update.
  • Shankara Narayana
    Shankara Narayana almost 4 years
    I was tripping for almost 30 mins because I did not read the entire answer. Gateway Ports yes worked
  • Henning
    Henning over 3 years
    Never add "GatewayPorts" after a "Match" command (even if it is not indented) or you will go crazy! (cert from the manpage: "Only a subset of keywords may be used on the lines following a Match keyword")
  • Adam F
    Adam F over 2 years
    It works, I have no idea WHY it works
  • Gloomy
    Gloomy over 2 years
    Can you expand on "clientspecified, or, in rare cases, to yes"? Why should it generally not be yes (which seems to be what everyone is doing)?