SSH Socks Proxy as VPN Replacement
2024-05-10 09:39 WIB - Hendrik Lie
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:
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-flagsTherefore 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-mThen we included in our autostart file:
Note: The script
set_tmuxis a convenience script provided here. To use it, I recommend you to read the script carefully and understand what it is doing. See the repositoryxadfsh/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.