Skip to content

Instantly share code, notes, and snippets.

@thomasfr
Last active November 18, 2024 03:37
Show Gist options
  • Save thomasfr/9707568 to your computer and use it in GitHub Desktop.
Save thomasfr/9707568 to your computer and use it in GitHub Desktop.
Systemd service for autossh
[Unit]
Description=Keeps a tunnel to 'remote.example.com' open
After=network.target
[Service]
User=autossh
# -p [PORT]
# -l [user]
# -M 0 --> no monitoring
# -N Just open the connection and do nothing (not interactive)
# LOCALPORT:IP_ON_EXAMPLE_COM:PORT_ON_EXAMPLE_COM
ExecStart=/usr/bin/autossh -M 0 -N -q -o "ServerAliveInterval 60" -o "ServerAliveCountMax 3" -p 22 -l autossh remote.example.com -L 7474:127.0.0.1:7474 -i /home/autossh/.ssh/id_rsa
[Install]
WantedBy=multi-user.target
@korneil
Copy link

korneil commented Mar 29, 2017

Also add

Environment=AUTOSSH_GATETIME=0

in the [Service] section if you experience problems like autossh.service: Start request repeated too quickly..

@IvanTurgenev
Copy link

Will this work on fedora 26? with SELinux

Copy link

ghost commented Oct 28, 2017

For completeness, you should also add:

ExecStop=kill -9 autossh

Without it systemctl stop autossh won't do anything.

@comperem
Copy link

comperem commented Dec 3, 2017

elFua, the kill command as you have written will not work. Kill takes PID's only, not process names.
Use this instead:
ExecStop=killall -s KILL autossh

@comperem
Copy link

comperem commented Dec 3, 2017

Also, this link had a line that, I believe, solved the problem of restarting too quickly:
https://gist.github.com/drmalex07/c0f9304deea566842490

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

@guettli
Copy link

guettli commented Dec 22, 2017

Since systemd cares for the restarting, I don't understand why the executable autossh is needed.

Could someone please explain this. I would like to understand the benefit of using autossh.

@Iiridayn
Copy link

Iiridayn commented Feb 8, 2018

@guettli thank you for the question, I can now remove another dependency. I'd been using autossh for so long that I didn't think about that.
@jeroenvermeulen thank you for the link - my munged version seems to be working great :).

@sean9999
Copy link

Could this be modified to take advantage of systemd's socket activation? I'd like to have an SSH tunnel only open when I need it (ex: when i make a request to localhost:1080).

@eldog
Copy link

eldog commented Jun 3, 2018

Consider adding -o "ExitOnForwardFailure=yes" as if the client cuts the connection to the server (like power goes off), the port may still be considered in use on the server. Been having this problem when rebooting a Raspberry Pi via unplugging the USB power.

@matthijskooijman
Copy link

One reason for using autossh, rather than normal ssh, is to have incremental backoff in the restart delays when the connection fails (e.g. the destination host is temporarily down). Systemd supports a fixed restart delay (RestartSec), but does not support increasing the restart delay (yet, see systemd/systemd#6129)

@llamafilm
Copy link

llamafilm commented Jul 25, 2018

@comperem that won't work either because you have to specify the full binary path like this. Also, I found that a SIGKILL will leave the child ssh process running. If you use SIGTERM then it gracefully stops both autossh and ssh. On my distro (Raspbian), this works:
ExecStop=/usr/bin/killall autossh

@ttimasdf
Copy link

@llamafilm @comperem This is not the best practice in case of systemd.

By default, systemd.kill will send SIGTERM to all processes and subprocesses of the control group with or without an ExecStop command. If there is one, it will be executed first(So it's no need after all).

autossh receiving SIGTERM will start to kill ssh subprocess in its way, and systemd will wait for it (by default 90s) and send SIGKILL after timeout.

In that case, no ExecStop command is needed and systemd will handle it gracefully by default. If you have no patience, tuning TimeoutStopSec is all you need.

@ttimasdf
Copy link

ttimasdf commented Sep 5, 2018

https://gist.github.com/ttimasdf/ef739670ac5d627981c5695adf4c8f98
Check out my fork if needed. Added:

  • ExitOnForwardFailure.
  • Handle restart automatically. (you can even replace autossh with ssh)
  • Multiple tunnels open simultaneously.
  • Move tunnel settings (key, user, port, etc) to a separate user's ~tunnel/.ssh/config. Easier to manage and test with sudo -u tunnel ssh example.com -v

@Hukkinen
Copy link

For completeness, you should also add:

ExecStop=kill -9 autossh

Without it systemctl stop autossh won't do anything.

I'd put instead:

ExecStop=/bin/kill $MAINPID

..as in sshd service. This way you can cleanly stop/kill only this particular process (of possibly many instances of autossh, for example).

@dimasmamot
Copy link

I get this error

mamot@pg-1-mamot-dawn:/etc/systemd/system$ systemctl start autossh-mamot-hook.service Failed to start autossh-mamot-hook.service: Interactive authentication required. See system logs and 'systemctl status autossh-mamot-hook.service' for details.

this is my script

ExecStart=/usr/bin/autossh -M 0 -N -o "ServerAliveInterval 60" -o "ServerAliveCountMax 3" -R mamot-hook.serveo.net:80:localhost:80 serveo.net

any idea ?

@jgrevich
Copy link

jgrevich commented Jul 8, 2019

@dimasmamot Interactive authentication required seems to be the key part of the error msg to me. Try executing the command first as sudo to see what interactive prompts are required. Most likely you need to add a new host key to /root/.ssh/known_hosts.

@ROBERT-MCDOWELL
Copy link

dynamic auttossh@.service
[Unit]
Description=autossh: %I
Documentation=file:///usr/share/doc/autossh/README.service man:autossh(1)
After=network.target

[Service]
User=autossh
Environment="AUTOSSH_GATETIME=0"
EnvironmentFile=/etc/autossh/%i.conf
ExecStart=/usr/bin/autossh $OPTIONS

[Install]
WantedBy=multi-user.target

@kegwell
Copy link

kegwell commented Mar 25, 2020

Running into a strange problem....

/etc/systemd/system/autossh.service


[Unit]
Description=AutoSSH tunnel
After=network.target

[Service]
Environment="AUTOSSH_GATETIME=0"
ExecStart=/usr/bin/autossh -N -M 10984 -o "PubkeyAuthentication=yes" -o "PasswordAuthentication=no" -i ~/.ssh/id_rsa -R 6666:localhost:22 ********@********** -p 22

[Install]
WantedBy=multi-user.target

After running daemon-reload and sudo systemctl start autossh I can see it running after issuing a ps ax | grep autossh with the exact command in the ExecStart listed above. However, when I check my remote host, nothing is listening on port 6666.

However, if I copy/paste that exact ExecStart line into a terminal and run it manually, it connects fine. I can reverse SSH to port 6666 without issue. So the command runs fine, when entered manually....but with systemd I see the service running, no errors, but no connection. Any ideas?

This is on CentOS 7....

@Strykar
Copy link

Strykar commented Jan 14, 2021

There's some unsound advice in the comments here, see https://gist.github.com/Strykar/a65cf6461fdcc41a3e78f5fbbf9e18f9

@haelix888
Copy link

Some stuff is overkill, e.g.

  • you don't need the ExecStop, systemctl stop autossh will work just fine out of the box
  • you don't need the AUTOSSH_GATETIME setting

@ScumCoder
Copy link

ScumCoder commented Jul 12, 2022

Some stuff is overkill, e.g.

* you don't need the AUTOSSH_GATETIME setting

Of course you do, without it autossh will give up if the very first connection attempt fails.

You USED to not need it, because it was implied by the -f flag. Except that systemd does not support the -f flag.

@haelix888
Copy link

@ScumCoder this wasn't my experience of it, I never used AUTOSSH_GATETIME but I use autossh and it does retry. It's been a while since I looked at it though, so stuff may have changed.

@jotakar
Copy link

jotakar commented Dec 27, 2022

Hi, I have this service for tunnel with autossh

[Unit]
Description=Open my Tunnel
After=network.target

[Service]
ExecStart=autossh -M 12000 -N -f -o "PubkeyAuthentication=yes" -o "PasswordAuthentication=no" -o ServerAliveInterval=60 -o ServerAliveCountMax=3 -i /home/usrtunel/.ssh/clavetunel -R 7090:localhost:7080 usrremote@100.xxx.xxx.xxx -p YYY
WorkingDirectory=/opt/run
RestartSec=5
Restart=always

[Install]
WantedBy=multi-user.target

If I run the autossh by hand, in command line, the tunnel remains open and working fine.
But with the service I found that every a while the service restart
My log shows this:

Dec 27 19:26:51 myserver autossh[24726]: starting ssh (count 1)
Dec 27 19:26:51 myserver autossh[24726]: ssh child pid is 24727
Dec 27 19:26:51 myserver autossh[24726]: received signal to exit (15)
Dec 27 19:26:57 myserver autossh[24732]: starting ssh (count 1)
Dec 27 19:26:57 myserver autossh[24732]: ssh child pid is 24733
Dec 27 19:26:57 myserver autossh[24732]: signalled to exit
Dec 27 19:28:32 myserver autossh[24897]: starting ssh (count 1)
Dec 27 19:28:32 myserver autossh[24897]: ssh child pid is 24898
Dec 27 19:28:32 myserver autossh[24897]: signalled to exit
Dec 27 19:30:08 myserver autossh[25106]: starting ssh (count 1)
Dec 27 19:30:08 myserver autossh[25106]: ssh child pid is 25107
Dec 27 19:30:08 myserver autossh[25106]: signalled to exit
Dec 27 19:31:43 myserver autossh[25278]: starting ssh (count 1)
Dec 27 19:31:43 myserver autossh[25278]: ssh child pid is 25279
Dec 27 19:31:43 myserver autossh[25278]: signalled to exit

What I see is that service stop autossh every few minutes, why? where is the error?

@Iiridayn
Copy link

@jotakar I've been using:

[Unit]
Description=Keep open a reverse tunnel to my computer via the DMZ server
After=network.target

[Service]
ExecStart=/usr/bin/ssh -NT tunnel
RestartSec=5
Restart=always

[Install]
WantedBy=multi-user.target

With tunnel defined in /root/.ssh/config as

Host                    tunnel
HostName                <redacted>
User                    <redacted>
IdentityFile    ~/.ssh/id_tunnel
ProxyCommand    ssh bastion -W %h:%p
RemoteForward   <redacted port> localhost:22
ExitOnForwardFailure yes
ServerAliveCountMax 5

And the bastion host also defined in the same file as

Host           bastion
HostName       <redacted>
User           <redacted>
IdentityFile   ~/.ssh/id_tunnel
ForwardAgent yes

I also have

Host *
ServerAliveInterval 60
IdentitiesOnly yes

at the top of my /root/.ssh/config, on the off-chance that's relevant.

I've found this to be very consistent and stable, and easy to test (ssh bastion, ssh -NT tunnel) when setting it up. Perhaps removing autossh and setting it up this way might help?

@mikkorantalainen
Copy link

mikkorantalainen commented Mar 22, 2023

For completeness, you should also add:

ExecStop=kill -9 autossh

Without it systemctl stop autossh won't do anything.

I think it would be better idea to add

KillMode=control-group

to the .service file because that will kill everything that was started (recursively) and nothing more. In addition, it will first send SIGTERM and use SIGKILL only if the process will not stop nicely.

If you randomly kill one or all autossh processes in the system, you might kill more than expected if autossh is used for other stuff, too.

See https://www.freedesktop.org/software/systemd/man/systemd.kill.html#KillMode= for details

@MestreLion
Copy link

MestreLion commented Jun 16, 2023

@jotakar :

What I see is that service stop autossh every few minutes, why? where is the error?

Don't use -f when using autossh as a systemd simple service. It will fork autossh (put in the background) and confuse systemd into thinking it ended.

@ScumCoder

Of course you do, without it autossh will give up if the very first connection attempt fails.

Systemd's Restart=always and RestartSec=60 can take care of that. You usually want autossh to fail fast if it can't do the first connection, as it usually means misconfiguration or authentication issues, and giving up after first attempt helps highlighting that on the journalctl logs.

@stokito
Copy link

stokito commented Jul 4, 2023

JFYI: I created an SSH tunnel SystemD service that works without the autossh github.com/yurt-page/sshtunnel

@zhangw
Copy link

zhangw commented Dec 31, 2023

@jotakar :

What I see is that service stop autossh every few minutes, why? where is the error?

Don't use -f when using autossh as a systemd simple service. It will fork autossh (put in the background) and confuse systemd into thinking it ended.

@ScumCoder

Of course you do, without it autossh will give up if the very first connection attempt fails.

Systemd's Restart=always and RestartSec=60 can take care of that. You usually want autossh to fail fast if it can't do the first connection, as it usually means misconfiguration or authentication issues, and giving up after first attempt helps highlighting that on the journalctl logs.

Yes, I just remove the '-f' option, it seems fine.

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