Setting up SSH keys and an automatic SSH Tunnel for HTTP browsing on a Mac (OS X)

Often, I find myself having to surf the web through my employer. The main reason is that the library subscriptions for online journals recognizes the IP. For some strange reason, my ISP doesn't buy those subscriptions, but my university does. One option would be to set up a hassle free enterprise level VPN connection, while another, to set up a dedicated tunnel with tools available on your OS X.

The easiest thing to do is to tunnel the HTTP requests through an SSH tunnel. This can be done by opening a terminal window and typing the appropriate SSH command. Then, one has to change the relevant proxy configuration. For Firefox, this can be done through its own preferences (Firefox menu -> preferences -> network). For other browsers (such as Safari or Chrome), one has to change the system wide proxy settings (i.e., Apple menu -> system preferences -> network -> advanced -> proxies). The question is how can it be done automatically?

Here's how.

The automatic way of setting up a tunnel includes: (a) Setting up keys to allow password-less SSHing into the remote server. (b) Setting a launchd daemon that keeps the SSH alive. (c) Either setting up firefox to be your tunneled browser or (d) Setting up a proxy file (.pac) with proxy settings which tell any browser which URLs should be surfed from your ISP and which through the tunnel. These steps are not complicated and they are required only once. Then, any time you need to surf with the ip of a remote server, either you use firefox, or, you do nothing special at all.

In what follows, "client" will be your personal machine (i.e., the one you work at home), and "server" will be your machine at work into which you can SSH.

Setting up SSH keys

The first step is to set up a private/public key pair with which you can SSH into the server without requiring a password.

On the client machine, type ssh-keygen -t rsa and three times press 'enter'. You will see the following (or something similar).

Note that you generated a private key which is saved in ~/.ssh/id_rsa and a public key in ~/.ssh/id_rsa.pub. The next step is to copy the contents of the public key (e.g., type cat ~/.ssh/id_rsa.pub) and add them to the file .ssh/authorized_keys on the server machine. If such a file does not exist, then you should make a new one. Make sure however that your home directory, the .ssh directory and the files cannot be written by other people. If so, SSH will not like it! To make sure that everything has the right permissions, type

Try it by SSHing into the server. It should not ask you for a password. Note that you should do that only if you trust the security on your client machine. The reason is that any intruder on the client will also be able to gain access to your server machine.

Launchd daemon, keeping the tunnel alive

The second step is to set up the launchd daemon that will keep the connection alive. To do that, we have to write have the following .plist file

<?xmlversion="1.0"encoding="UTF-8"?>

<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"

"http://www.apple.com/DTDs/PropertyList-1.0.dtd">

<plistversion="1.0">

<dict>

<key>Label</key>

<string>com.ssh.tunnels</string>

<key>KeepAlive</key>

<dict>

<key>NetworkState</key>

<true/>

</dict>

<key>LimitLoadToSessionType</key>

<string>Aqua</string>

<key>ProgramArguments</key>

<array>

<string>/usr/bin/ssh</string>

<string>-a</string>

<string>-x</string>

<string>-k</string>

<string>-C</string>

<string>-D</string>

<string>10080</string>

<string>ip-or-name-of-remote-server</string>

</array>

<key>RunAtLoad</key>

<true/>

</dict>

</plist>

This is equivalent to executing the following cmd in a terminal window:

ssh -axkC -D10080 ip-or-name-of-remote-server

The -a and -k tells SSH not to forward the authentication agent connection and the GSSAPI credentials. This is used as a precaution. -x tells SSH not to forward X11 connections. This is because if your default does forward, it will save you a little bandwidth. You should of course replace ip-or-name-of-remote-server with your servers domain name or ip address.
The plist itself should be saved as (for example):

~/Library/LaunchAgents/com.ssh.tunnels.plist

It will run automatically after you restart, but, if you're impatient, you can tell launchd to load it by typing:

launchctl load -S Aqua ~/Library/LaunchAgents/com.ssh.tunnels.plist

That's it!

Note, if you have problems, you can unload the plist:

launchctl unload ~/Library/LaunchAgents/com.ssh.tunnels.plist

and use the following plist instead, which will dump into the console a lot of debugging information:

<?xmlversion="1.0"encoding="UTF-8"?>

<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"

"http://www.apple.com/DTDs/PropertyList-1.0.dtd">

<plistversion="1.0">

<dict>

<key>Label</key>

<string>com.ssh.tunnels</string>

<key>KeepAlive</key>

<dict>

<key>NetworkState</key>

<true/>

</dict>

<key>LimitLoadToSessionType</key>

<string>Aqua</string>

<key>ProgramArguments</key>

<array>

<string>/usr/bin/ssh</string>

<string>-a</string>

<string>-x</string>

<string>-k</string>

<string>-C</string>

<string>-v</string>

<string>-D</string>

<string>10080</string>

<string>ip-or-name-of-remote-server</string>

</array>

<key>RunAtLoad</key>

<true/>

</dict>

</plist>

Note the extra "debug" key and -v option for the SSH. Once edited, load the plist again.

Setting up Firefox

The third step (and last step) is to set up Firefox, so that any browsing through it will be through the tunnel. Alternatively, you can set up a PAC file (uncollapse the following text box for that).

All you have to do is to open the Preferences in the Firefox menu. Then open Network -> Settings, and you get the following screen:

In it, click on "Manual proxy configuration", and fill in "localhost" and port "10080" under SOCKS Host.

Alternatively, setting up a PAC file

Instead of using firefox for the tunneled connection and Chrome/safari/whatever for the rest, it is possible to set an automatic proxy configuration file (proxy.pac). For example:

This proxy.pac will check whether the host is the American Physical Society or Nature, and if so, ensure that the connection is through the tunnel opened on the local post 10080, otherwise, it forces a direct connection. The what-is-my-ip host is there so that you can check that the automatic proxy works. If it does, then the ip that will appear in www.whatismyip.com will be the IP of your remote server.

You can add to the list many more hosts for which your institute library has subscriptions. To get such lists, simply google FindProxyForURL "nature.com" and you will easily find.

Once you have the proxy.pac file, you have to tell the system to use it. This is done by going to Apple Menu -> System Preferences -> Network -> Advanced -> Proxies, and then you click "Automatic Proxy Configuration" and choose your file.

Note that in system 10.7 (at least up to 10.7.2), there is a bug in which the automatic proxy configuration doesn't work for local files (at least for Safari, it might for other browsers). However, if you put your file on a web server (it could also be your own local host), then it works fine.