First problem
You can specify the directives User=
and Group=
in the [Service]
section of the unit file.
Second problem
To make the service run on boot, you should not put it in your home folder. Instead, put it under /etc/systemd/system/
. This is the folder meant to be used by the system administrator (i.e. you) to add new system-wide services.
Other folders include:
/usr/lib/systemd/system/
is meant for packages which want to install unit files, though under Debian and Ubuntu the folder is actually /lib/systemd/system/
because the various bin
and lib
folders have not been merged into a unified /usr/
prefix yet.
/usr/local/systemd/system/
is for installing units by locally compiled packages.
Testing the unit
Once the unit file is in an appropriate location, you can try starting the unit immediately by typing systemctl start <UNIT_FILENAME>
as usual. It should work without having to type the unit's full path. The extension also doesn't have to be specified if it's .service
.
Enabling the unit
Before you can enable your unit, you need to add an [Install]
section, under which you should add the directive WantedBy=multi-user.target
. This directive specifies the stage of the boot-up process during which the service should be started (if it were enabled). multi-user.target
is appropriate for most services.
Once that information is added, you can use systemctl enable <UNIT_FILENAME>
, which enables the unit, making systemd from now on automatically start it during boot up at the specified stage.
Edit: it turns out my specific case/problems were related to my encrypted home dir and using only systemd was all that was needed for it to work, although the unit has to be started on each login. For more info see here.
Looking into this more, it appears that using only systemd isn't the best approach anyway, since I'd like to have the backup to USB triggered any time USB drives with "backup" partitions are mounted (potentially multiple times per session). Instead, it's better to have udev "want" a systemd user unit that will then trigger the actual backup script. Here's what I did:
Label the drives in GParted (e.g. to be called "backup") so they will always be mounted at the same mountpoint.
Add a user systemd unit in ~/.config/systemd/user/auto-usb-backup.service with:
[Unit]
Description=Autobackup to USB drive
[Service]
ExecStart=/home/david/Documents/computer/backup/scripts/backup_to_usb.sh
Reload the daemon: systemctl --user daemon-reload
so it's aware of the new unit.
Then, add a udev rule to trigger the unit when a USB drive with a "backup" partition is mounted. Create a udev rule at /etc/udev/rules.d/90-auto-usb-backup.rules containing
SUBSYSTEM=="block", ACTION=="add", ENV{ID_FS_LABEL}=="backup", TAG+="systemd", ENV{SYSTEMD_USER_WANTS}="auto-usb-backup.service"
The ID_FS_LABEL parameter name and value were obtained using udevadm monitor --environment --udev
and plugging in the drive, but the lsusb
(and its -v
option) and udevadm info -a -p $(udevadm info -q path -n /dev/sda)
may also be useful to fine-tune rules (e.g. have the udev rule trigger only for a specific drive based on its serial number).
Reload udev for the new rule to apply: sudo udevadm control --reload
Check the rule will trigger for the drive with udevadm test /block/sda
(where sda
is the current drive mountpoint): you should see TAGS=:systemd:
among the output.
Finally, turn remove and add the drive: the script in the systemd user unit defined above should get executed. You can double-check this (and debug) using journalctl --user-unit auto-usb-backup -r -b
(note that on some systems the --user-unit
option may be -u
instead).
Note: it appears the script gets triggered before the drive is done mounting, so the backup script called by the systemd unit has a wait loop to sleep until the folders its looking for are available.
Resources that were helpful:
https://vic.demuzere.be/articles/using-systemd-user-units/
https://borgbackup.readthedocs.io/en/stable/deployment/automated-local.html
Best Answer
Apparently the behaviour changes if User= is specified before ExecStart=.
Don't know whether that's a feature or an accident, but as a feature it's pretty dumb and moreover it seems undocumented which is actively annoying.