Secure Web Access Through SSH Tunnel (SOCKS Proxy Server)

How to setup a dynamic SSH tunnel (also called SOCKS proxy server) and use it daily with Firefox and Thunderbird.


I'm a kind of "digital nomad" (yeah I just like the expression :)). I use to go around with my laptop on my back, and I connect to the net from various places, like coffees, hotels, swimming-pools (yes :)), or whatever places that provide wifi.

I don't trust these access-points so much, and I've been wondering what kind of trick could be done to improve the security. It turns out that it's quite easy to go with SSH tunnels, and that there's no need of OpenVPN.

Notice that I have nothing against OpenVPN, but it just happens that I have a VPS out there, and of course I already have the OpenSSH daemon up and running on this VPS. I'm not a skilled sysadmin, so I don't want to install too much stuff and add plenty of doors to my server. The less doors the better.

SSH is already there, and it's fit for the job: SSH server can act as a SOCKS proxy server, and it's so simple you won't believe it...

One last word, this post provides specific solutions for Firefox and Thunderbird, as they're my favorite apps to surf the web.

SSH tunneling

Creating a tunnel to your remote server is achieved with only one line:

ssh -N -D 5222 user@vps

Let's quote the SSH manual page:

This simple command opens a tunnel to vps, aka the host where a friendly SSH server is waiting for you to connect.

If you want to know more, I recommend this Linux Journal article:
SSH Tunneling - Poor Techie's VPN

Testing with Firefox

In order to test that, you must configure your web browser to use a proxy. Here is the procedure with Firefox:

And that's all. Now Firefox sends its traffic to localhost:5222, which is the entrance of the SSH encrypted tunnel. Data goes through the tunnel and ends up on your VPS, where the SSH daemon forwards it to the web...

Daily usage with Firefox and Thunderbird

Now that things work, what I want is a convenient way to use it. That is, I don't need to go through a proxy when I'm home, but as soon as I'm out, I'd like to enable the proxy easily. A one-line shell command would be sweet.

Basically, there are only two applications that should use the proxy: Firefox for web browsing, and Thunderbird for emails.

Of course, I can change the settings of both apps each time I'm out, and change it back when I'm home. But, how tedious is that!

Furthermore, if I do that manually, I must be careful to do things in the right order:

  1. Launch the apps, enable the proxy
  2. Connect to the WLAN (Wireless LAN)
  3. Open the SSH tunnel
  4. Start doing stuff

The key is to enable the proxy before connecting to the WLAN! If I do it the other order, when I launch Thunderbird, the first thing it does is to send my password out on the LAN before I have time to change the proxy settings. Enabling the proxy after that is quite useless, passwords have been leaked already...

Doing things manually is always error prone, but you already knows that if you're an IT guy like me.

So it's better to automate things. Somehow, I would like to declare my proxy settings system wide, so that applications can automatically know it, and use the proxy to go on the WAN.

Attempt 1: pure environment variables [FAILURE]

Ok, so after browsing the web, I found what seems to be the perfect solution: declaring the proxy settings in environment variables, and letting applications handle that by themselves. For example, Firefox can be configured to Use system proxy settings, as they say.

So the idea is to declare the proxy in the environment, but what variables should we use? It seems that there is no consensus about that. If you have a look at the ArchLinux wiki, you can see that the guys define plenty of variables, just to be sure. Then you pray that your favorite application picks up one of these and honor it...

So here we go:

export all_proxy=socks://localhost:5222
export http_proxy=$all_proxy
export https_proxy=$all_proxy
export ftp_proxy=$all_proxy
export rsync_proxy=$all_proxy
export ALL_PROXY=$all_proxy
export HTTP_PROXY=$all_proxy
export HTTPS_PROXY=$all_proxy
export FTP_PROXY=$all_proxy
export RSYNC_PROXY=$all_proxy

Then, you launch Firefox from the same shell (since environment variables only live in the shell where they're defined, and its sub-processes), and Firefox should pick up these values and use it.

But somehow, it just doesn't work, Firefox ignores all the stuff we defined in the environment. If you like to read, there's a good discussion about that on the Ubuntu forums:
Configuring Firefox to use a proxy from the command line

So long for the environment variables...

Attempt 2: environment variables & add-ons [SUCCESS]

So I kept on googling around, and it just happens that someone wrote an add-on for Firefox to fix that. It's named "Environment Proxy", and there's a version for Firefox and for Thunderbird.

I'm not a big fan of the add-on solution. Simply because the add-on can break at any Firefox/Thunderbird update. If you update your system steadily like me, you probably noticed that there's a new Firefox version every two months. So the add-on may let you down on a regular basis, and it's a little bit scary. Furthermore, if the add-on is not maintained thoroughly by its author, you're screwed, and you find yourself with the same problem to solve all over again...

Well, that's just my point of view on it. Anyway, I made an exception for this time, I tried this add-on, it works!

Have a look at the documentation page, it says which environment variable you should define. For SSH tunnel and SOCKS proxy, just one variable is needed:

export SOCKS_SERVER=localhost:5222

But beware! Exporting a variable is nice, but don't forget it lives only in the shell and its sub-processes. So now you must start Firefox from this shell, otherwise you won't use the proxy.

OK, so because I'd like to avoid mistakes, and don't want to type too many commands, I wrote a script! Here it is:

# Ssh command, thanks to:


pgrep iceweasel >/dev/null 2>&1 && \
        { echo >&2 "Iceweasel already running, please stop it..."; exit 1; }
pgrep icedove >/dev/null 2>&1 && \
        { echo >&2 "Icedove already running, please stop it..."; exit 1; }
[[ -e $SOCKET ]] && \
        { echo >&2 "SSH tunnel already opened, please close it..."; exit 1; }

echo "Opening SSH tunnel, please wait..."
ssh -f -N -D $PORT -M -S $SOCKET -o ExitOnForwardFailure=yes $USER@$HOST || \
        { echo >&2 "Failed to open SSH tunnel"; exit 1; }

echo "Exporting environment variables..."
export SOCKS_SERVER=localhost:$PORT

echo -n "Starting iceweasel... "
(iceweasel >/dev/null 2>&1) &
echo $weasel_pid

echo -n "Starting icedove... "
(icedove >/dev/null 2>&1) &
echo $dove_pid

echo "To end the session, just close iceweasel & icedove"
wait $weasel_pid $dove_pid

echo "Unexporting environment variables..."

echo "Closing tunnel..."
ssh -S $SOCKET -O exit $USER@$HOST

echo "Done"

Notice that I use iceweasel and icedove instead of firefox and thunderbird. This is the same thing, just the name is different on Debian.

Another solution: proxychains [SUCCESS]

If you don't like the add-on solution, or if you don't use Firefox and Thunderbird, and prefer a more generic solution, here it is.

I found that there are some pieces of software called proxifiers. They work by intercepting and modifying the network requests sent by a given program. I can mention two of them: tsocks and proxychains. I think both are fit for the job.

I tried proxychains.

Pretty simple to install:

apt-get install proxychains

Pretty simple to configure:

vi /etc/proxychains.conf

Just comment out the last line, and add your own proxy config:

socks5       5222

After that, just use proxychains to start your apps:

proxychains firefox


So as you can see, it was a long way for a simple thing, as often it is when you go through the command-line and want to understand a little bit how things work.

Currently I go with the Firefox/Thunderbird add-ons, it works great. However I need to go through the command-line to use my proxy, I can't launch my applications from the menu icon. So it's not as transparent as I hoped in the beginning,

Using OpenVPN would have make it totally transparent I think...