Laurens Duijvesteijn

SSH tunnels and Proxy Auto Configuration

Reach internal web-based tools in a private network without a VPN or proxying all your web-traffic through your internal network. Use this to get to a Grafana dashboard, the Consul mananagement UI, the Hadoop admin panel, or whatever else strikes your fancy.

Problem

This post is useful if you have the following problems:

Additionally, you'd like to only proxy the requests that need it. The rest of your browsing traffic should just be treated like normal.

There are two components to this solution: SSH tunnels, and using SSH tunnels as a proxy.

SSH Tunnels

OpenSSH can function as a proxy and forward a local port.

$ ssh -q -T -n -N -D 7890 user@your-server &

This opens a SOCKS proxy to on localhost:7890, which will pass all traffic through your-server. This command assumes you have SSH keys set up — you won't be prompted for a password.

The & tells your shell to run the ssh command in the background, so you can continue to work in the same terminal. Your tunnel will stop working once you close your terminal.

Now for the flag soup:

-q
Be quiet. Do not print uninteresting stuff. (Leave this out if you try to set this up for the first time; debug output is gone too).
-T
Don't allocate a pseudo-terminal. Fancy words for: "don't prompt me for commands".
-n
Don't accept any input from stdin. This means we can put the ssh command in the background without fear.
-N
Do not execute a remote command. If this is ommitted, ssh seems to connect, and immediately close the connection again.
-D
The local port to forward to the server. You can pick whatever you like (< 1024 requires root). Just remember to be consistent when we write the PAC file in the next section.

I can never remember all these flags. Sometimes, the server also varies. So I have the following function in my shell config:

function proxy() {
  ssh -q -T -n -N -D 7890 $1 &
}

Which let's you type:

$ proxy user@server

Configure your browser

So that gives you a tunnel (if you take my word for it). Now let's configure the browser.

Remember we had a requirement to only proxy the requests for the internal services over this tunnel? The browsers I'm aware of don't let you configure this nicely in a GUI. (You can have a "don't proxy" list, but not an "only proxy" list in both Firefox and Chrome.)

Fortunately, the solution lies in the Proxy auto-config format. It's a JavaScript file in which the function FindProxyForUrl(url, host) has to return a specific string with the config based on the url and/or host.

Save the following JavaScript code under ~/.proxy.pac:

function FindProxyForURL(url, host) {
  // If you don't have internal DNS, you can do IP
  // and subnet based configuration.
  if (isInNet(host, "10.0.0.0", "255.255.255.0")) {
      return 'SOCKS localhost:7890';
  }

  // Otherwise, you can do something like this:
  if (host.endsWith('.yourcompany.internal')) {
      return 'SOCKS localhost:7890';
  }

  // All other traffic treated like normal.
  return 'DIRECT';
}

Make any modifications you like. The MDN documentation has the details and a list of the functions you can use.

If using Firefox, make your proxy settings look like this (substitute your own home directory):

Firefox proxy
  settings

Chrome has an almost equivalent menu.

After all this is done, you should have a working proxy setup for only the hosts/addresses you want!

N.B.: This apparently also happens to be the format that is used when you "automatically discover proxy settings". Apparently, DHCP servers can advertise a URL with a file in this format. (With the kind of security implications you'd expect — use/demand HTTPS.)