1

I have 3 Servers, A is a public accessable Server in the Internet. B Hosts a Webservice I want to access. C has access rights to connect to A and B.

Now i want that if a Client D tries to access a special Port on A that he gets forwarded to B.

IP's and Ports

A:

  • 1.0.0.1:22 SSHD Server
  • 1.0.0.1:443 Public Port which i want to use

B:

  • 1.0.0.2:23 SSHD Server
  • 1.0.0.2:444 Webservice I want to access

C:

  • 1.0.0.3

D:

  • 1.0.0.4

Diagram:

  +------------+        +------------+
  | Client (D) +--------> Public (A) |
  +------------+        +-----^------+
                              |
  +----------------+    +-----------+
  | Webservice (B) <----+ Proxy (C) |
  +----------------+    +-----------+

Question:

What ssh tunnel Commands do i need to execute on C so that if i try to open 1.0.0.1:443 on D i get the service hosted on 1.0.0.2:444 ?

mac.1
  • 149
  • 2
  • 5
  • 10
  • I think i got half of it working by creating an ssh Relay with the following command: ssh -R 443:1.0.0.2:444 user@1.0.0.1 -p 22 This way, any connection from A to localhost:443 will return 1.0.0.2:444. However It is not possible to access yet from Client D – mac.1 May 21 '17 at 08:30
  • What you search is something like SSH VPN https://www.startpage.com/do/search?query=ssh+vpn – Aleksandar May 21 '17 at 10:58
  • You need to allow remote connects with the `-o GatewayPorts yes` option – eckes May 29 '17 at 09:59

3 Answers3

1

This is not quite how SSH tunnels work.You can get near to what you describe, but not exactly in the way you draw it up.

2 options are available to you:

  1. use Local port forwarding
  2. use Dynamic port forwarding

1) Local port forwarding

This requires you to change your approach: the tunnel needs to be opened from the client, from D in your diagram. it is easy to achieve, on the client (D) just do a

ssh -L 443:1.0.0.2:444 user@1.0.0.3

of course that requires you to:

  • have shell access or a putty client on D
  • have a user on the proxy (C) that D can login to
  • be able to connect from D to C via ssh
  • have the X11Forwarding and AllowTcpForwarding set to yes in the server config on C

I will explain Dynamic port forwarding in a moment

  • Between D and A ist the Internet and between A and C is the Internet. Only B and C are in the same network. So i don't think i can do local port forwarding. I will take a look at dynamic port forwarding – mac.1 May 20 '17 at 18:01
  • local port forwarding would still work for you, if you can reach C from D, and C can reach B. But you really need to be able to start the tunnel from a shell or a putty on D, the client. If you cannot do this, your only options is Dynamic port forwarding. – AndreasPolzInfonova May 20 '17 at 18:22
1

On C you can run

ssh -fNR 1.0.0.1:443:1.0.0.2:444 root@1.0.0.1

It will only work if you login as root user because 443 is a privileged port. Moreover it only works if sshd on A is configured with GatewayPorts set to yes or clientspecified. (The default is no and using yes cannot be recommended, so if you want to do it this way I recommend clientspecified).

kasperd
  • 30,455
  • 17
  • 76
  • 124
  • You could avoid all the problems using `socat` and `sudo`. e.g: `ssh 1.0.0.1 "sudo -b socat tcp-l:443,fork,reuseaddr tcp:1.0.0.2:444 2>/dev/null 2>&1"`. – rudimeier May 29 '17 at 13:18
  • @rudimeier You are assuming there is a route between A and B. The question sort of implies there isn't any such route. – kasperd May 29 '17 at 13:55
  • 1
    Ah, ok. Anyways, in this case (and if C is reachable by A) I would run one `socat` on A (forward A to C) and another `socat` on C (forward C to B). The advantage is that it's more easy to start the tunnels onboot on A and C independently without any auto-ssh-login involved. – rudimeier May 29 '17 at 15:18
0

Edit:

@kasperd mentioned that you can set GatewayPorts for the user to you don't have to use nginx. I leave the workaround here for others.

Add this to /etc/ssh/sshd_config

Match User <username>
   GatewayPorts yes

Original Answer:

I found a solution achieving this with ssh and nginx. It is not perfect because i have to install a nginx server on A with a proxy. I had to enable ssl and give this nginx instance a own ssl certificate.

So the Solution will look like this: C will execute the following command to create a Relay between A and B:

ssh -R 445:1.0.0.2:444 user@1.0.0.1 -p 22

This will cause any input on Port 445 on 1.0.0.1 to be redirected to 1.0.0.2:444. So a local user on A can now executewget https://localhost:445 --no-check-certificate to get the index page of your webservice. However it is not public available yet. (in case you wonder: Port 445 is correct, i must use some unused port yet for the next part)

So i created a nginx server on A which will redirect any traffic from Port 443 to port 445. And used the following config:

server {
        listen 443 ssl default_server;
        listen [::]:443 ssl default_server;
        ssl on;

        ssl_certificate /etc/nginx/ssl/server.crt;
        ssl_certificate_key /etc/nginx/ssl/server.key;

        server_name proxy.<your-domain>.com;

        location / {
          proxy_pass        https://127.0.0.1:445;
          proxy_set_header  X-Real-IP  $remote_addr;
          proxy_set_header  Host $host;
        }
}

Now you can use your webbrowser (in incognito mode on Firefox to prevent issues with the certificate) to suft to https://proxy..com:443 and get the result from your Webservice. The IP of proxy..com must be 1.0.0.1.

What i dislike here is that i have to create a new webserver which will create a new encrypted session instead of just redirecting the one of my webservice located on B. However this is a good workaround till i find a better solution.

mac.1
  • 149
  • 2
  • 5
  • 10