SSH Socks Proxy as VPN Replacement

Problem

Our browser is google-chrome, and we want it to connect to our cloud server via a proxy. Therefore we can configure google-chrome to connect to the internet via the configured proxy. The configuration should make google-chrome dependent on the proxy to be present, otherwise it should not be able to connect to the internet.

Solution

There are multitude of layers in our solution. First we need to run a command to initiate the SOCKS5 proxy connection. Then we need to configure google-chrome to make use of the SOCKS5 proxy port as its web proxy. For convenience reasons, we have to automate the setup since the first time our shell starts.

Start the connection

It can be done in as simple as:

$ ssh -TND <PORT> user@host

The choice of port is arbitrary. I selected one that is unlikely to be used by any existing services. Argument -T disables pseudo-tty allocation, while -N disables interactive prompt. Argument -D PORT is the one that actually do the creation of an encrypted SOCKS5 tunnel. It might also be useful to have -v passed for verbosity, so we can check that we are actually connected.

We also want it to be kept alive, and ideally to simplify the invocation. To keep our connection alive after running it, we can actually add ServerAliveInterval 120 to our ~/.ssh/config. It simply tells our ssh client that in case it receives no data from the server after a specified interval (here our interval is 120 seconds), it would send a message to server to get a response.

The full command we needs to reach our server to initiate our proxy is then:

$ ssh -TNvD <PORT> username@domain.tld

However to simplify that we just need to specify our user name and host name in our ~/.ssh/config file. The equivalent of -D <PORT> in the config file is the line DynamicForward <PORT>. Therefore we can compose the following config file:

# file ~/.ssh/config
Host proxy
    User                username
    HostName            domain.tld
    ServerAliveInterval 120
    DynamicForward      <PORT>

Then all we need to connect to our server is simplified to:

$ ssh -TNv proxy

Configure Google Chrome to use proxy

Apparently, it is rather trivial to force Google Chrome to honor proxy setting. Arch Linux Wiki suggests to make the following function:

function secure_chromium {
    port=<PORT>
    export SOCKS_SERVER=localhost:$port
    export SOCKS_VERSION=5
    chromium &
    exit
}

or:

function secure_chromium {
    port=<PORT>
    chromium --proxy-server="socks://localhost:$port" &
    exit
}

then source them from our ~/.bashrc.

In that manner, whenever we want to have a secure connection, we can just run secure_chromium, and enjoy our secure internet connection.

However our requirement is that we must make chrome dependent on it, that it would not be able to connect to the internet without it. The most obvious solution is to pass --proxy-server=socks://localhost:<PORT> for each run of google chrome. But it was too much work, and setting up a custom script for it is just superfluous.

The solution is actually rather simple, we just have to create the following line with that argument passed within:

# file ~/.config/chrome-flags.conf
--proxy-server=socks://localhost:<PORT>

# Note that for chromium it is ~/.config/chromium-flags

Therefore our google chrome is constrained to use the proxy server.

Automatic configuration

Currently we are using our tmux configuration with convenience scripts provided by xadfsh/xadf. We use set_tmux at the start of our session to launch a single or a series of named tmux session, and when there’s a corresponding config file for that named session, it would also be autoloaded.

Inside a named tmux session’s custom config file ssh.conf, we included the following lines:

# file ~/.tmux.conf.d/sessions/ssh.conf
new-window -t ssh:1 -n 'socks'
send-keys -t ssh:1 'clear;ssh -TNv proxy' C-m

Then we included in our autostart file:

# Launch named session ssh among other named sessions
set_tmux ... ssh ...

Note: The script set_tmux is a convenience script provided here. To use it, I recommend you to read the script carefully and understand what it is doing. See the repository xadfsh/xadf, study it, and adapt it to your case if necessary.

Therefore our connection will automatically be initiated upon entering our terminal.

However the limitation is that if the connection is severed, we would be left without a proxy. Therefore one more solution to that is to have a systemd user service:

# file ~/.config/systemd/user/proxy.service
[Unit]
Description=SSH tunnel to proxy

[Service]
Type=simple
Restart=always
RestartSec=10
ExecStart=/usr/bin/ssh -F %h/.ssh/config -N proxy

Then we can enable and start it with:

systemctl --user enable proxy
systemctl --user start proxy

If this is configured, then we no longer need our tmux based solution.

Sources