Access remote addresses, using a SSH server at home
Sometimes you need to use remote servers from home, but there is just no way to have them expose to the web. I guess the most usual situation is when you want to have access to your computer at work, which is behind the company network + firewalls and, despite it can see the web, it can not have external visibility. But there is a workaround using SSH which, properly setup, can be as safe as a VPN, with advantages. This solution is much more portable, since the VPN works at the operating system level, when SSH clients only at application level, usually using Putty.
I searched a lot on internet for a clear and straight approach, but it was not that easy to find. So I decided to wrote myself this article, my way, covering the following situation:
- I use Windows at both work and home.
- I have resources at work which I want to see from home (eg. a SQL Server, a web server running on my workstation there or even a Remote Desktop).
- I can not have more than a normal putty client running at work. No way to expose IPs or whatever, for obvious reasons.
- I can have a Linux installation running a SSH server at home (Raspberry PI, old desktop or a virtual machine).
- I can expose my SSH server to the web, using my router's port forwarding options.
[ Skip all the bla-di-bla and take me straight to the point - although it worth reading! ]
Is SSH safe enough?
IMHO, SSH tunneled connections can be considered as safe as VPNs if properly setup. A considerable advantage of VPN, as far as I am concerned, is that some solutions can disguise the entire communication, making an interceptor unable to have any clue about the connection details such as the encryption algorithm. In other hand, in a VPN the client have access to a whole environment which exposes many resources (network printers, shared drives, local servers and etc) while in SSH, only specific addresses (server:port) are made available, by demand. Both are based on AES encryption, one of the bests algorithms available. A VPN connects you to a entire network, while SSH only connects to a single computer, which makes me feel it is safer.
So the first question that comes up is: how can I ensure my SSH server is safe enough?
- It is not exposed using the DMZ option (which exposes a local IP through the router IP, all ports). Instead, I use the router port forwarding option to make the router's port 8822 expose my server's port 22, no more than that. So this is the only thing exposed to the web, which is encrypted under strong authentication.
- Password for SSH connections is disabled and only RSA keys are used for authentication. It prevents brute force attacks. I won't go through all this, but in short, edit the file /etc/ssh/sshd_config and set the following options to disable password authentication:
ChallengeResponseAuthentication no PasswordAuthentication no UsePAM no
- Fail2ban is installed, so repeated unsuccessful attempts blocks malicious IP and keep them from try for a while, when banned.
- Additional security could be added using the port knocking technique in the SSH server firewall. This is pretty cool, brilliant indeed, but would make this tutorial harder to understand and it is not in the scope.
Another thing that I missed in my research was a decent definition of what a "local" and "remote" forwarding really do, technically speaking. This is the way I found to explain the difference between both:
- Local forwarding: Bind a client port to an address visible to the server. So the client is "stealing" a resource from the server.
- Remote forwarding: Bind a server port to an address visible to the client. So the client is "giving" a resource to the server.
Be advised: Tunnels are not shared. It means that other computers in the same network can't use the bound ports, only the tunnel ends themselves, through 127.0.0.1:<port>.
In this article, we will need two connections, one of each type.
The first connection is started at work, using putty, to give a resource from work to the home server (remote forwarding).
The second connection is started from my notebook using putty, to "steal" the tunnel end from the home server (local forwarding), forwarding it to a local port on my netbook.
Now, straight to the point.
Let's say I want to use Remote Desktop at home to connect to my workstation port 3899 (the default one for this service). In this example I will use putty (for windows), although you will find the Linux equivalent commands at the end of the article.
0. At home: expose the SSH server to the web
Google is your friend. If you don't know how to do it and skipped the bla-di-bla about SSH security, you are wise to get back and take a look.
If you have dynamic IP at home, use a free dynamic dns service such as NO-IP.
1. At home: enable tunneling in the SSH server
Edit /etc/ssh/sshd_config and set
PermitTunnel yes AllowTcpForwarding yes
2. At work: connect to your home server
In my setup, I exposed my SSH server port 22 trough the router port 8822, so I just open putty and use the following parameters:
3. Create a Remote Forwarding tunnel to give the workstation port 3899 to the home SSH server (at port 9000).
Click the putty icon in the top right corner and choose "Change settings" from the menu.
Then, in the left-side tree, select Connection->SSH->Tunnels, type the following tunnel setup and click Add:
- Source port: 9000 (we are giving a resource from work to this port at the home server)
- Destination: localhost:3389 (or any other address accessible to the client, this is the resource you are giving)
- Select Remote and Auto
- CLICK ADD (I always forget, don't repeat my mistake).
- If the screen looks like below, click Apply.
R9000 is the home server port. localhost:3389 is the shared resource, from my workstation point of view (which is starting the connection).
4. At home: Tunnel open, but still unreachable from my notebook
Use this command to on the SSH server to be sure the port 9000 is open:
As you see here, my server has ports 22 (SSH) and 80 (HTTP) open to external connections (0.0.0.0), and ports 3306 (MySQL) and 9000 (the tunnel) only listening to local connections (127.0.0.1). The server obviously can access it's own port 9000, but my notebook still can't.
This was disappointing and made me stuck for a while. I was struggling trying to connect to the server port 9000 to get Remote Desktop access, without success because it was only listening to local connections.
The workaround is to make a second tunnel, with local forwarding, to steal this "local resource" from the server and bind it to a port in my notebook.
5. At home: Use putty again, to access the SSH home server and steal the local resource "localhost:9000"
So now what I want to do is to connect from my notebook to the SSH home server, and make the server's port 9000 (previously bound to the Remote Desktop at work) available on my notebook as a local port (9001 in this example). Then I will finally be able to talk to my workstation at port 3389 and connect to Remote Desktop.
From my notebook, I connect to my SSH server, using the following tunnel setup:
- Source port: 9001. Local port (at notebook) used to steal the SSH server port 9000.
- Destination: localhost:9000 (address visible to the SSH server, actually the tunneled connection which I want to have access).
- Select Local and Auto
- CLICK ADD.
- If the screen looks like below, click Apply.
6. At home: Finally connect to Remote Desktop
Now I can open the Remote Desktop application from my notebook and connect to localhost:9001 (which is bound to sshserver:9000, which is then bound to workcomputer:3389).
Command to open the Remote Forwarding tunnel, from work to home SSH server (step 2). In this example, 220.127.116.11 is my SSH server IP to the internet.
ssh -R 9000:localhost:3389 18.104.22.168
Command to open the Local Forwarding tunnel, from notebook to home SSH server (step 5). In this example, 192.168.0.123 is my SSH server IP in my home network.
ssh -L 9001:localhost:9000 192.168.0.123