Sometimes, ssh tunneling a port is insufficient. It’s fantastic if you want to remotely access some system, but suppose you want more of an ad-hoc VPN/proxy, to allow you to, say, browse the web through a remote system?
I thought about setting up squid on a remote system, but that would be a bit of work. Plus, I’d have to take care to lock it down so I wasn’t accidentally running an open proxy, which is all sorts of bad. I could also do OpenVPN, but that’s an even bigger headache to set up.
As it turns out, ssh includes native support for establishing a SOCKS proxy, too. Your local ssh client will stand up a SOCKS proxy on localhost, on a port you specify, and forward traffic through ssh to the remote system. You can then simply point your web browser at your local SOCKS server, and viola!
From the ssh manpage, it’s astonishingly easy:
-D [bind_address:]port Specifies a local ``dynamic'' application-level port forwarding. This works by allocating a socket to listen to port on the local side, optionally bound to the specified bind_address. Whenever a connection is made to this port, the connection is forwarded over the secure channel, and the application protocol is then used to determine where to connect to from the remote machine. Currently the SOCKS4 and SOCKS5 protocols are supported, and ssh will act as a SOCKS server. Only root can forward privileged ports. Dynamic port forwardings can also be specified in the configuration file.
Add -N to stand up the tunnel but not give you a command prompt, and optionally -C to enable compression. (Typically only useful on slower connections.)
Putting it in action, it looks something like this:
mawagner ~ $ ssh -CND 8000 bos.n1zyy.com
It will continue to run in the foreground without any output. That’s all it takes—you’ve now got a SOCKS server running.
Now, configure your browser to use it. In Firefox, in the Preferences menu, Advanced › Network › Connection › Settings lets you set up a SOCKS proxy. Just fill in the SOCKS proxy line, with “localhost” for the hostname (not the remote server—ssh is listening on localhost and forwarding connections there for you) and whatever port you specified on the command line (8000 in my example).
Chrome seems to want this as command-line flags. On the Mac, it took this ridiculous command to launch:
$ /Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome --proxy-server="socks5://localhost:8000"
Take note that the SOCKS proxy will handle the actual connections, but DNS requests will still take place locally. If you’re trying to hide your traffic from an oppressive regime, this could be bad. It’ll also be bad if you’re trying to connect to something over a great distance and they’re using geo-DNS to steer you to the right place. But when your home ISP just sucks and you want to bypass their overloaded connection to Youtube, this is just the trick.