"If we see light at the end of the tunnel, it is the light of the oncoming train" ~ Robert Lowell. Oh yes, another good quote. This post is on SSH tunneling, or as I like to call it ‘Poor Man’s VPN’. Contrary to the sysadmin’s popular belief, SSH tunneling actually can be very valuable use for both techies and home users. I say contrary to popular belief because ‘reverse tunneling’ and tunneling http traffic through SSH can bypass firewalls and content filters. But this article isn’t about how to violate your corporate internet use policy, it’s about how to create SSH tunnels to make your life just a little bit easier.
Why SSH Tunnels instead of VPN? Well, I actually use both at home. If you have followed any of my posts on jaysonbroughton.com, I use a 3-factor authentication with OpenVPN (user name, certificate & One-Time-Password). But if I want to check on one of my servers from the house via my Android, or a computer where I don’t have administrative rights (required of my custom portable OpenVPN client), or even tunnel vnc over ssh to fix a problem on my better half’s Linux laptop then SSH is my backup to using VPN.
What I’ll cover here today is just your basics: how to create tunnels, what the syntax means, examples of reverse tunnels and why would you use each one of them. I’ll briefly go over ssh_config, but a more in-depth post on custom ssh_config’s will be at a later date.
So as always, time to dispense with the necessities. I use Debian in a virtual environment so your results may vary. In this case I am using OpenSSH_5.3p1 as a Server and a mix of OpenSSH 5.X ssh clients with my examples. Before I get too far into tunneling I’ll say this: If you feel the need to use SSH tunneling via http or reverse SSH tunnels to bypass your corporate firewall make sure you are not violating any of your companies Internet Acceptable Use Policy. This goes without saying, your System Administrators will hunt you down and fry you when they find that you’re bypassing the content filter or setting a reverse tunnel in order to tunnel back into a server at work. As a System Administrator myself, I take immense pleasure in locating such individuals. At the very least check with your Network/System Administrator so they are not caught off-guard. LinuxJournal.com and myself are not liable for your blatant violations of your corporate policy :-) With that said, let’s have some fun shall we?
Creating an SSH tunnel is actually quite easy. Figuring out what to do with it once you have learned how to create a tunnel might be slightly more difficult. So I’ll give you a few use cases to get your mind churning before we get into the details of creating a tunnel. I used to travel quite a bit before kids and with a previous IT job. When I traveled I would end up in the strangest of hotel rooms (you know the kind) with even stranger wireless access points. Do you really want to connect to a wireless access point where the SSID of the hotel is missspelled? Or the airport where there appears to be quite a few open WAP’s? When I’m out and about I will tunnel my http traffic through ssh on my rooted droid to my home server. If I’m on my laptop/netbook I’ll open an ssh tunnel and route http traffic via socks5 so that all of my traffic is encrypted via ssh then back out to me. I wouldn’t trust an open WAP as far as I can throw it. What about anything else in plain text? I’ve tunneled SMTP traffic on my computer back to the house when certain places I’ve been block outbound SMTP. Same thing goes with pop3 (of which I’ve recently changed over to imap-s). Other examples of ssh tunneling include X11 applications tunneled via SSH, and VNC sessions. One of the things I brought up earlier is reverse tunneling, which is..well you got it, the reverse of tunneling. In this case you create a tunnel from a server that is behind a firewall with no SSH servers to an SSH server. Then when you log into that SSH server you can re-establish the connection. What good is that you say? Well if your corporate VPN is down, or requires Windows only VPN clients but you really don’t want to lug your laptop home to check on a process running when you get home you can reverse tunnel. In this case you would establish a connection from server X to your home machine. Once you arrived at the house you would re-establish the connection to server X, thus bypassing the firewall/VPN and checking on the process without having to establish a VPN connection. I do this very rarely as I feel this is bad juju, bypassing all the rules setup on my firewall and VPN is usually a last resort.
So there are your examples for SSH tunneling, now let’s show you how to get ‘er done.
Before we get too carried away on the client side of things there are a few things that need to be edited on the server-side of sshd.config. in /etc/ssh/sshd_config I tend to make the following changes. Before you get too carried away, make a copy of /etc/ssh/sshd_config origional file so you have a reference in case something goes horribly wrong. cp /etc/ssh/sshd_config /etc/ssh/sshd_config.orig
# Force SSH Protocol 2 Protocol 2 #Turn on Privileged Separation for security UsePrivilegeSeparation yes #Deny root login PermitRootLogin no #Do not allow empty passwords PermitEmptyPasswords no # Forward my X Sessions X11Forwarding yes X11DisplayOffset 10 # I hate Motd displays PrintMotd no # It’s alliivee TCPKeepAlive yes
Don’t forget if you do make any changes to your sshd_config file, you need to restart your sshd service in order to make the necessary changes.
All right, lets get into switches. No no, not the switches your ‘pa made you pull off the tree branch when you broke ma’s favorite vase, SSH switches.
A typical SSH tunnel (without tunneling X) looks like this:
ssh -N -p 22 firstname.lastname@example.org -L 2110:localhost:110
= Do not execute a remote command
= External SSH port 22. I tend to use other external SSH ports to keep skript kiddies from hitting my home SSH server
= username@hostname(or ip address)
= Bind information. Broken down as such: client-port:hostname:hostport – In this example your binding POP3 on the server to your localhost port 2110
So how about some examples?
Forward pop3 and smtp through SSH:
ssh -N -p 2022 email@example.com -L 2110:localhost:110 -L 2025:localhost:25
Forward google Talk through SSH:
(-g Allows remote hosts to connect to local forwarding ports)
Basically anything that is sent in plain-text can be secured via SSH tunneling. Once you have established the tunnel, on the client-side you would configure your settings for the hostname as localhost and the port as your ‘client-port’, be it 2110,2020,5223, or any other port that you have selected to forward through.
Encrypt your HTTP Traffic
This is another one that goes without saying. If you work for a company that has an ‘IT Acceptable Use Policy’ check before you do this. This is one that I use whenever I’m out of town or in a place that I don’t trust the wifi. On an android I’ll use my SSHTunnel app, but if I’m on my laptop I use the following SSH command
ssh -D 5222 firstname.lastname@example.org -N
After you make a connection, then set your browser of choice (or any application that allows proxy) to localhost:5222. This will create a dynamic port forward and tunnel all the application traffic through your SSH server, both encrypting your data and bypassing content filters.
Tunneling X and VNC Sessions
Remember when you added ‘X11Forwarding yes’ to your sshd_config? This is where tunneling X comes in.
ssh -X -p 2022 email@example.com
You guessed it, -X tunnels X. Remember though, this will tunnel X apps from your remote machine to your client machine running Linux. If you somehow find you’re on a Microsoft Windows machine and want to tunnel, just install Cygwin/X (http://x.cygwin.com/) on your guest OS. I haven’t personally tried this but from what I understand it gives you an X windowing system that should allow you to run your remote X apps in Windows.
When it comes to tunneling VNC sessions, you have to be careful. If the client you’re tunneling from has a vnc server running on say 5900, make sure you don’t decide to put your local forwarding port at 5900 or you will just connect right back to yourself. Connecting via VNC is as straight forward as any of the other services:
ssh -p 2022 firstname.lastname@example.org -L 5900:localhost:5900
In this example your connecting to ssh external port 2022 as user bob to mylinuxserver.com. Your local forwarding port is 5900, the port you want to forward is mylinxuserver.com‘s 5900 vnc. Once you setup the forward you can open up your vnc client of choice and type: localhost:0 at which point you should be connected via vnc to your remote desktop. If you used 5901, then it would be localhost:1, and so on and so forth.
Reverse SSH Tunnels
Oh yes it’s time for my favorite part of SSH tunneling. Sure, getting access to a service from behind SSH is nice, so is tunneling your web traffic through encrypted SSH tunnels. But the real surprise comes when you can reverse the tunnel. As I’ve outlined earlier, a reverse tunnel is when you are behind a firewall that has no SSH server, but need to access it at a later date (be it minutes/hours/days later) but don’t want or have the ability to VPN in. You would connect to your SSH server from that machine, then reverse the tunnel by connecting to that open connection. What do I use it for? From time to time against a server, or even with friends and family with reverse VNC sessions via SSH tunnels. In this case they execute a putty saved session that logs into my ssh server as a certain user with no rights. Once the tunnel is established, I can vnc to their machine in order to remote to them. No more having them setup their firewall, or figure out log-me-in, or any of those other websites.
So the steps to create a reverse SSH tunnel are as follows:
- From client machine: ssh -R remoteport:localhost:22 username@servername
ex: ssh -R 2048:localhost:22 email@example.com
- From server side (to re-establish the tunnel): ssh -p 2048 localhost
And there you have it, a reverse tunnel. Yay!
For you visual learners out there, daddoo and nerdboy4200 from #linuxjournal got together and whipped up a message sequence chart using mscgen (http://www.mcternan.me.uk/mscgen/). Yes it’s opensource, and really awesome. I tried my hand at creating the mscgen chart for this article but what daddoo and nerdboy did in just a few short hours put my little image to shame.
An there you have it, a primer to SSH tunneling. Keep in mind that this was just a primer, what you can do with tunneling is limited only by your imagination. Later on I’ll go over setting up ssh_config on the client side so that all of these settings that I have described above can be saved as individual settings on your client-side ssh. But that’s a post for another time.
ssh -o ProxyCommand=’nc -x 127.0.0.1:30000 %h %p’ firstname.lastname@example.org
where 127.0.0.1:30000 is the socks5 proxy. Credit: Jethro Carr
You are using ‘connect’ for HTTPS as your proxy version, this is from man nc:
-X proxy_version Requests that nc should use the specified protocol when talking to the proxy server. Supported protocols are ”4” (SOCKS v.4), ”5” (SOCKS v.5) and ‘connect’ (HTTPS proxy). If the protocol is not specified, SOCKS version 5 is used.
So you should use the following to use SOCKS 5:
ProxyCommand /usr/bin/nc -X 5 -x 127.0.0.1:7777 %h %p
ProxyCommand /usr/bin/nc -x 127.0.0.1:7777 %h %p
I hope it helps.
Proxy Using SSH Tunnel
We can set up a socks proxy on top of a SSH tunnel. Besides the common proxy functions, such as web browsing, the proxy on top of SSH tunnel also ensures the security between the browser and the proxy server (the SSH server). In this post, we introduce and explain how to set up a proxy over SSH tunnel and the mechanism of it.
A simple example
Let’s start with a simple example. We can access a sshd server sshd_server and we want to use it as a socks5 proxy server. It is simple by using ssh:
$ ssh -D 8080 username@sshd_server
After that, set the browser such as firefox’s proxy option to use socks5 proxy 127.0.0.1:8080. That’s it!
Then, check whether your IP is from the proxy from the websites’ view: Who am I.
Making ssh proxy
We can set up a more complex proxy server through ssh. For example, we have a sshd server s2 and another server s1 as the proxy server. Then we can set up a proxy server system using ssh tunnel. s1 will act as the proxy server, while s2 connects to the service provider (s3). The overall system can be shown as this:
c0:p0 <> s1:p1 <==> s2:p2 <> s3
Maybe most of the time c0 and s1 are the same machines as the simple example at the beginning of the post.
Using ssh as a proxy to browse the web is very useful under some situation: Local access restriction such as behind a strict firewall in some country, company or school; You are in a insecure network environment while you want to login to your account.
Now let’s look at how to set up proxy by using ssh tunnel. This uses ssh’s “dynamic” port forwarding function by using parameter “-D”. ssh allocates a socket to listen to port on the local side, optionally bound to the specified ip address. Whenever a connection is made to this port, the connection is forwarded over the ssh channel, and the application protocol is then used to determine where to connect to from the remote machine.
1) Proxy listening to localhost port only
This proxy server can only be used on localhost, which means the other users can not use it. c0 and s1 in the graph above are the same machine.
The command is:
$ ssh -D p1 username@sshd_server
p1 is the port on localhost. Any port larger than 1024 can be chosen as p1. After setting up this proxy tunnel, set the proxy option in browser to 127.0.0.1:p1 and using socks5. Then it is done. Enjoy it now :) .
2) Proxy listening to specific IP
This kind of proxy server can provide service to other users. Users (and include yourself of course) can use this socks5 proxy with address s1_ip and port p1.
The command is:
$ ssh -D s1_ip:p1 username@sshd_server
This command sets up a socks5 proxy server on s1. The proxy address is: s1_ip:p1.
- Some useful ssh arguments
There are some other ssh arguments that can make the port forwarding more convenient for us:
-C Requests gzip compression of all data -T Disable pseudo-tty allocation -N Do not execute a remote command. This is useful for just forwarding ports. -f Requests ssh to go to background just before command execution. -n Redirects stdin from /dev/null (actually, prevents reading from stdin). -q Quiet mode. Causes most warning and diagnostic messages to be suppressed.
These arguments can be used with -D for different usages. I like to use this combination:
$ ssh -CnfND 8080 username@sshd_server
When I want to close the ssh proxy tunnel, I need to find the pid of it by
$ ps aux | grep ssh
and then kill it.
Or let it run in the shell:
$ ssh -CTND 8080 username@sshd_server
You can also configure it to listen on all addresses on the host by:
$ ssh -D "*:8080" username@sshd_server
Port forwarding squid proxy
This post mainly focus on using ssh to build up the proxy system. But the connection between the client and the other kind of proxy server such as squid can also make use of ssh tunnel. I only provides a simple example here, while more details of ssh port forwarding can be found from Port Forwarding using ssh Tunnel. For example, the proxy server and port is proxy:port. Now we can port forwards port 8080 on localhost to it by this:
$ ssh -L 8080:proxy:port username@sshd_server
If you are using Linux with NetworkManager, it is very convenient to set up the global proxy of GNOME to use the socks proxy created by SSH.
Creating and Using Socks Proxy on Windows ∞
Using Socks Proxy on iOS ∞
- Proxy using SSH Tunnel on Windows
- Git through SSH Tunnel as Proxy
- How to Configure iOS to Use Socks Proxy over SSH with a Linux/Unix Host
- How to Remote Control Linux Server Using VNC through SSH Tunnel
- SSH Port Forwarding on Linux
- Linux Cluster Solutions
SSH的三种端口转发（Port forwarding）/ 隧道协议概要
据我所知，SSH一共提供了 3 种端口转发，分别是本地转发（-L参数）、远程转发（-R参数）和动态转发（-D参数）。接下来我就一一介绍这几种不同的转发方式的使用。我尽量简明扼要地叙述主题重点，让人一看就学会（回忆起）该如何操作。
本地转发通过参数 -L 指定，格式：-L [本地主机:]本地主机端口:远程主机:远程主机端口。加上ssh待登录主机，这里就有了三台主机。
举例：ssh -L 50000:www.google.com:80 user@host。例中本地主机、远程主机和待登录主机分别用颜色红绿蓝标识。
当成功执行上面的命令之后，访问本地的50000端口，就等同于访问 www.google.com 的 80 端口。但和直接访问有着本质的区别：这次是通过登录主机来安全转发数据的，没有人知道你和远程主机之间传输了何种数据。就算你不能和远程主机建立连接（而登录主机能访问），那就能突破（绕过）（防火墙的）限制。
远程转发通过参数 -R 指定，格式：-R [登录主机:]登录主机端口:远程主机:远程主机端口。
举例：ssh -R 0.0.0.0:8080:localhost:80 user@host。
当成功执行上面的命令之后，访问登录主机的 8080 端口就相当于访问 localhost:80！
相对于本地转发和远程转发的单一端口转发模式而言，动态转发有点更加强劲的端口转发功能，即是无需固定指定被访问目标主机的端口号。这个端口号需要在本地通过协议指定，该协议就是简单、安全、实用的 SOCKS 协议。FQ（你懂的）就靠她了！
动态转发通过参数 -D 指定，格式：-D [本地主机:]本地主机端口。相对于前两个来说，动态转发无需再指定远程主机及其端口。它们由通过 SOCKS协议 连接到本地主机端口的那个主机（peer，比如最常见的浏览器）指定（此属协议内容，无需深究）。
举例：ssh -D 50000 user@host。
最常见的用途：FQ（大家都懂的）。在浏览器中设置代理类型为 SOCKS(5)，主机及端口：127.0.0.1:50000。然后 gg/ytb/tt/fb 等就一丝不挂地摆在眼前了！
ssh -L port1:localhost:port2 -A -t -o ProxyCommand=’nc -x 127.0.0.1:port %h %p’ host1 ssh -D port1 -A -t host2
-N Do not execute a remote command. This is useful for just forwarding ports.