Help with systemd unit to shutdown router on system shutdown

if i run ssh user@<ip> i’m asked for a password, whereas if i run ssh router.lan i’m not, so i guess that’s one problem

i also tried dumping the unit file in /etc/systemd and recreating it in ~/.config/systemd/user as suggested in the Arch wiki followed by sudo systemctl enable '~/.config/systemd/user/shutdown-router.service' and sudo systemctl daemon-reload

i figured that might solve the problem of systemd running ssh as root but that doesn’t work either

ps: current unit file…

[Unit]
Description=Shutdown router on system shutdown
DefaultDependencies=no
Before=poweroff.target halt.target shutdown.target
Requires=poweroff.target

[Service]
Type=oneshot
ExecStart=/usr/bin/ssh 192.168.1.1 'poweroff' -i '/home/user/.ssh/Linksys_id_ed25519'
RemainAfterExit=yes

[Install]
WantedBy=shutdown.target

That is the correct order:

ExecStart=/usr/bin/ssh -i /home/user/.ssh/Linksys_id_ed25519 user@192.168.1.1 'poweroff'

Look at man ssh

2 Likes

Order of options and arguments does not normally matter, and does not here.

Anyways; it is assumed that “user” was placeholder for your actual username. Just try manually what happens when you try to login as root with e.g.

sudo ssh -v 192.168.1.1 poweroff

and/or with user@192.168.1.1 and/or with that -i option. You’d supposedly be shown what doesn’t work.

[Service]
User=yourUser

Anyways; it is assumed that “user” was placeholder …

yes

$ sudo ssh -v 192.168.1.1 ultimately results in no key found for root user and falls back to asking for a password

same for $ ssh root@192.168.1.1

as mentioned, $ ssh router.lan works fine with ~/.ssh/config as so…

Host router.lan
    HostName 192.168.1.1
    Port 22
    User root
    IdentityFile /home/majik/.ssh/Linksys_id_ed25519

is there a way to run the systemd unit file in the console while the system is up so i can see the output?

Given that ~/.ssh/config (and assumedly no /root/.ssh/config interfering again) it really should work to do

sudo ssh -v -i /home/majik/.ssh/Linksys_id_ed25519 192.168.1.1

Does this not give you a normal login as “root” on your router? If it doesn’t the “-v” again supposedly says why not. If it does, then

ExecStart=/usr/bin/ssh -v -i /home/majik/.ssh/Linksys_id_ed25519 192.168.1.1 poweroff

should work just as well from the systemd unit – assuming of course that your /home/majik/.ssh is not on some at the time of its execution already unmounted filesystem, i.e., assuming you haven’t split off your /home. I’ve left in the “-v” in the above so you can after booting up again check what’s up with

journalctl -b-1 -xu shutdown-router.service

It is assumed that you’ve placed your service file in /etc/systemd/system/shutdown-router.service and have used

systemctl enable shutdown-router.service

to enable it. You’d of course remove the “-v” once things work.

As to your direct question, and if the above isn’t yet helping: your service file as is pulls in poweroff.target, i.e., shuts down, so if you want to test “live” you need to comment that out:

#Requires=poweroff.target

You can then run it immediately as

systemctl start shutdown-router.service

and in case of failure again look at things with

journalctl -xu shutdown-router.service

FWIW I grabbed your service file from above and things just work here:

$ cat /etc/systemd/system/shutdown-router.service 
[Unit]
Description=Shutdown router on system shutdown
DefaultDependencies=no
Before=poweroff.target halt.target shutdown.target
Requires=poweroff.target

[Service]
Type=oneshot
ExecStart=/usr/bin/ssh -v -i /home/rene/.ssh/id_rsa rene@hp8k poweroff
RemainAfterExit=yes

[Install]
WantedBy=shutdown.target

I’m logging in as “rene@” whereas you want “root@” or simply nothing but I don’t see why things would be different for you given that things work from the command line as your user as you stated – again at the time of shutdown modulo a potentially already unmounted /home.

[EDIT] Oh, let me by the way add that if you do have a split-off /home you may want to copy that key file to /root/.ssh/ and refer to it there with the “-i” parameter, or also duplicate the shown ~/.ssh/config in /root/.ssh/

Just been playing with a raspberry pi - for all intent and purpose - the result should be similar for your router.

You need to ensure you have a keypair - where the keypair resides on the client system is irrelevant - but for a system service I suggest storing it in /etc with /etc/ssh/secrets as possible storage point.

You will also need to ensure the router’s sshd_config allows root to login using password. After you have copied the keyfile you can disable root password access.

 ...
#PermitRootLogin prohibit-password
 ...
man sshd_config
...
    PermitRootLogin
            Specifies whether root can log in using ssh(1).  The argument
            must be yes, prohibit-password, forced-commands-only, or no.
            The default is prohibit-password.

            If this option is set to prohibit-password (or its deprecated
            alias, without-password), password and keyboard-interactive
            authentication are disabled for root.

            If this option is set to forced-commands-only, root login
            with public key authentication will be allowed, but only if
            the command option has been specified (which may be useful
            for taking remote backups even if root login is normally not
            allowed).  All other authentication methods are disabled for
            root.

            If this option is set to no, root is not allowed to log in.
...

Start with switching to root context

$ su -l root

Create the storage folder

mkdir -p /etc/ssh/secrets

Change permissions on the secrects folder

chmod 700 /etc/ssh/secrets

Now generate a keypair (press Enter twice to create the keypair witout passphrase)

ssh-keygen -b 2048 -t ed25519 -f /etc/ssh/secrets/router.key

Copy the public part to your router

ssh-copy-id -i /etc/ssh/secrects/router.key.pub root@ip.x.y.z

Create your service file

$ cat /etc/systemd/system/shutdown-router.service 
[Unit]
Description=Shutdown router on system shutdown
DefaultDependencies=no
Before=poweroff.target halt.target shutdown.target
Requires=poweroff.target

[Service]
Type=oneshot
ExecStart=/usr/bin/ssh -i /etc/ssh/secrects/router.key root@ip.x.y.z 'poweroff'
RemainAfterExit=yes

[Install]
WantedBy=shutdown.target

Enable and start the service

systemctl enable --now shutdown-router.service
2 Likes

While not aiming to be overly argumentative as a new (manjaro) forum user certainly, I’d be a little careful with linux-aarhus’ reply just above. I.e., you already showed that you can login as root on the router and with that Linksys_id_ed2551 key by doing so as your user, so things will already be setup correctly as to any of that. If you now start reconfiguring sshd and/or generate new keys you would upset things.

The only intention is to lay out the requirements and what is required for running this as root on the router.

There is clearly an issue with the understanding of how a systemd unit works.

The command defined in ExecStart is equivalent to doing it on the commandline.

It is fine as a user to define the host in .ssh/config but when you want to run it as a system service - you need to be specific as the service will have no knowledge of predefined hosts.

It it possible to define the the task as a user service

Disable the system wide service

systemctl disable --now shutdown-router.service

Create the folder

mkdir -p ~/.config/systemd/user

Copy the service definition into the folder (to avoid confusion - delete the service definition from /etc/systemd/system)

cp /etc/systemd/system/shutdown-router.service ~/.config/systemd/user

Edit the file to look like

[Unit]
Description=Shutdown router on system shutdown
DefaultDependencies=no
Before=poweroff.target halt.target shutdown.target
Requires=poweroff.target

[Service]
Type=oneshot
ExecStart=/usr/bin/ssh -i /home/%u/.ssh/Linksys_id_ed25519 user@ip.x.y.z 'poweroff'
RemainAfterExit=yes

[Install]
WantedBy=shutdown.target

Then enable the service using the --user prefix

systemctl --user enable --now shutdown-router.service
1 Like

Again… why not just specify

User=

and be done with it?

Unless I’m quite seriously mistaken User= in a unit file would run ssh as said user but would not e.g. have ssh find the user’s $HOME/.ssh configuration, and certainly it would not help as to not having that home directory mounted anymore at the time of its execution just before shutdown if that’s the issue, as I’m somewhat expecting. Hence my advise/insistence of just being explicit as per linus-aarhus’ first reply, i.e., with “-i” in this case to supply the key.

If only there was an easy way to test that…

There is and I did test that above shutdown-router.service file with “User=rene”. It fails and still looks for its configuration in /root/.ssh – as expected what with running still in root’s environment. Moreover and as also said, certainly it wouldn’t help with an unmounted /home.

I’ll not comment furrher until OP’s back and confirmed/denied Help with systemd unit to shutdown router on system shutdown - #12 by rene1. As said there, given that it works for him as his user and with the by him posted ~/.ssh/config it would seem almost impossible to not work other than as said /home issue.

Then you did something wrong.

I don’t see any unmounted /home mentioned in OP’s post nor what that has to do with systemd service file.

success!
i’ll mark my own (this) post as the solution only because it contains a concise solution free of clutter, however credit goes largely to @rene :slight_smile: - especially this post

requirements: working passwordless ssh access to router using ssh key encryption

assumed key file name: router_id_ed25519
assumed user name: dingaling
assumed router IP/port: 192.168.1.1:22

/etc/systemd/system/shutdown-router.service

[Unit]
Description=Shutdown router on system shutdown
DefaultDependencies=no
Before=poweroff.target halt.target shutdown.target
# comment out below to test unit
Requires=poweroff.target

[Service]
Type=oneshot
ExecStart=/usr/bin/ssh -i /home/dingaling/.ssh/router_id_ed25519 192.168.1.1 poweroff
RemainAfterExit=yes

[Install]
WantedBy=shutdown.target

$ sudo systemctl enable shutdown-router.service
$ sudo systemctl daemon-reload

Great; cheers.

1 Like

ok, now for my next trick!

figured i’d continue this thread since what i have in mind is intimately connected…

we got the router shutting down on system shutdown :partying_face:, but attached to the router is a RPi and i need to kill that before i kill the router

so currently we have…

[Service]
Type=oneshot
ExecStart=/usr/bin/ssh -i /home/majik/.ssh/Linksys_id_ed25519 192.168.1.1 poweroff
RemainAfterExit=yes

is the solution as simple as …

ExecStart=/usr/bin/ssh -i /home/majik/.ssh/RPi_id_ed25519 
ExecStart=/usr/bin/ssh -i /home/majik/.ssh/Linksys_id_ed25519 

there’s a question as to whether the unit can contain multiple ‘ExecStart’ and, if so, given this is shutdown stuff, does the order have to be reversed?

then there’s blah@.service unit files which adds to my confusion

linux - Systemd with multiple execStart - Stack Overflow

You have the answer in your linked stack overflow.

You have that system at your hands - why not just test it and see if it works?

Also this line:

RemainAfterExit=yes

is useless here.

yes - you can.

They are executed in order of appearance

1 Like

As to the ssh part: you have the general format

/usr/bin/ssh -i /where/ever/identity-file [username@]address-or-resolvable-name command-to-run

so as to as user “username” and as identified by private key “/where/ever/identity-file” on system “address-or-resolvable-name” run “command-to-run”.

If you leave out “username@” the default is for ssh to login as its invoking user; in the case of being run through a systemd unit file and unless specifically tweaked this means user “root” (and, careful, any said tweaking changes the invoking user as such but will not e.g. get you that user’s normal environment, and generally you don’t).

In the case of the router your config made it clear that, yes, you needed to login as user “root” which is why you leaving the “username@” part out works. For the Pi I’d however feel it more likely you in fact need to log in as your user on the Pi and run the command as said user? While I don’t know about your Pi often sshd on a somewhat generic system is not even OOTB configured to accept root logins.

I.e., if you from the command line shut down the Pi with, as your user,

ssh address-or-resolvable-name-for-the-pi poweroff

and you have in that case no ~/.ssh/config fragment also naming user “root” for the Pi you may need to from the ExecStart say for example “majik@address-or-resolvable-name-for-the-pi”. So just transpose things in that manner.

As to the .service file: yes, for type oneshot you can specify multiple commands for ExecStart, either as indeed multiple ExecStart= lines or with them on one line separated by " ; " (note: that’s space-semicolon-space). Order is still the normal order in which you want things executed.

It’s of course also possible to e.g. relay to a private executable shell script with

ExecStart=/usr/local/bin/shutdown-my-stuff.sh

or some such if you want to get more involved; if for example you’d want to loop around shutting down your Pi and/or make sure it has shut down before you kill the router. Depends I guess on your scripting tastes and prowess :slight_smile:

The mentioned blah@.service files are not involved here; they exist as a way to parametrize service files. I for example used to use/advise on one for people/systems that had difficulty keeping Wake-on-LAN enabled on their NIC over boot. I.e., you’d have e.g.

/etc/systemd/system/wol@.service:

[Unit]
Description=Wake-on-LAN (%i)
Requires=network.target
After=network.target

[Service]
ExecStart=/sbin/ethtool -s %i wol g
Type=oneshot

[Install]
WantedBy=multi-user.target

and then enable it for specific NICs with e.g.

systemctl enable wol@enp3s0

and/or enp4s2 and/or whatever. Anycase then, not so much related here.