Skip to content

Instantly share code, notes, and snippets.

@drmalex07
Last active November 8, 2024 00:56
Show Gist options
  • Save drmalex07/c0f9304deea566842490 to your computer and use it in GitHub Desktop.
Save drmalex07/c0f9304deea566842490 to your computer and use it in GitHub Desktop.
Setup a secure (SSH) tunnel as a systemd service. #systemd #ssh #ssh-tunnel #ssh-forward

README

Create a template service file at /etc/systemd/system/[email protected]. The template parameter will correspond to the name of target host:

[Unit]
Description=Setup a secure tunnel to %I
After=network.target

[Service]
Environment="LOCAL_ADDR=localhost"
EnvironmentFile=/etc/default/secure-tunnel@%i
ExecStart=/usr/bin/ssh -NT -o ServerAliveInterval=60 -o ExitOnForwardFailure=yes -L ${LOCAL_ADDR}:${LOCAL_PORT}:localhost:${REMOTE_PORT} ${TARGET}

# Restart every >2 seconds to avoid StartLimitInterval failure
RestartSec=5
Restart=always

[Install]
WantedBy=multi-user.target

We need a configuration file (inside /etc/default) for each target host we will be creating tunnels for. For example, let's assume we want to tunnel to a host named jupiter (probably aliased in /etc/hosts). Create the file at /etc/default/secure-tunnel@jupiter:

TARGET=jupiter
LOCAL_ADDR=0.0.0.0
LOCAL_PORT=20022
REMOTE_PORT=22

Note that for the above to work we need to have allready setup a password-less SSH login to target (e.g. by giving access to a non-protected private key).

Now we can start the service instance:

systemctl start [email protected]
systemctl status [email protected]

Or enable it, so it get's started at boot time:

systemctl enable [email protected]
@Robin479
Copy link

Robin479 commented Aug 3, 2023

Instead of setting up the service template to a fixed set of environment variables and to use distinct environments, why not setup the service with minimal default options like timeouts and disabling password prompt, and to use distinct ssh_config.d profiles instead, e.g. /etc/systemd/system/[email protected]:

[Unit]
Description=Auto-SSH to %i
After=network.target

[Service]
ExecStart=/usr/bin/ssh -NT -o PasswordAuthentication=no -o TCPKeepAlive=yes -o ServerAliveInterval=60 %i
Restart=always
RestartSec=5

[Install]
WantedBy=multi-user.target

...and then define your ssh_config in /etc/ssh/ssh_config.d/auto-ssh (name doesn't actually matter):

Host myalias
    User myuser
    HostName hostname.example.org
    ProxyJump [email protected]

...and then activate it:
$ systemctl start [email protected]

...or enable autostart, respectively:
$ systemctl enable [email protected]

@Blaimi
Copy link

Blaimi commented Aug 3, 2023

I'm using this concept since a while ;)

I use this especially to open SOCKS proxies (DynamicForward) to access private kubernetes-API-endpoints via bastion-hosts configured as --user services.

https://gist.github.com/drmalex07/c0f9304deea566842490?permalink_comment_id=3145418#gistcomment-3145418

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment