248

I just upgraded from Ubuntu server 14 to version 15. I had trouble getting my upstart script working after the upgrade, and read that systemd is the new default. I'm far from a linux expert, so please go easy on me :-)

Here is what my upstart script was before:

description "NZBGet upstart script"

setuid robert
setgid robert

start on runlevel [2345]
stop on runlevel [016]

respawn

expect fork

script
    exec nzbget -D
end script

pre-stop script
    exec nzbget -Q
end script

Based on the upstart to systemd wiki page, I used the tables provided there to map things as closely as I could in my new systemd service file:

[Unit]
Description=NZBGet Service

[Service]
Type=forking
ExecStart=/usr/local/bin/nzbget -D
ExecStop=/usr/local/bin/nzbget -Q
Restart=on-failure

This file is located at /home/robert/.config/systemd/user/nzbget.service. To start the service manually, I've been doing:

$ systemctl --user start nzbget

This works great. However, when I log out of my SSH session, the service shuts down. Also, it does not start on bootup or user login. I want it to behave the same as it did as an upstart service: I want it to start at boot, run constantly, and as a specific user.

What do I need to do to get this configuration?

Braiam
  • 67,791
  • 32
  • 179
  • 269
void.pointer
  • 2,655
  • 2
  • 15
  • 12

2 Answers2

299

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 that 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/lib/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.

Yamaho
  • 4,413
  • This worked. I had to specify the absolute path to the service filename in the systemctl enable command though, this was not obvious to me at first. Also enabling gave me some warning about a missing [Install] section. I ignored it, but I'm not sure if it will impact its ability to start at boot time. – void.pointer Sep 19 '15 at 17:28
  • 3
    The Install warning was actually really important. It won't start on boot without WantedBy=multi-user.target under the [Install] section. After adding this to the .service file, then you can enable it. – void.pointer Oct 11 '15 at 02:37
  • 6
    I apologize about leaving the answer unattended for such a long time. I fixed the location where the unit file should go, added the missing information about the [Install] section. Hope it's now more helpful for anyone looking for it. – Yamaho Feb 18 '16 at 19:50
  • 9
    This becomes much easier when the username is templated, i.e. your service is defined with a filename in the format something@.service then enabled like something@username.service the setting becomes User=%i meaning the user is not hard-coded and multiple users can use the same definition. An example. – Walf May 06 '17 at 12:38
  • 2
    Will it start if I put it under /etc/systemd/user/ ? – Khurshid Alam Sep 04 '17 at 13:50
  • 3
    Your unit files belong in /usr/local/lib/systemd/system and you run systemctl enable [service], which links them into /etc/systemd/system. You're not supposed to drop files in /etc/systemd/system. See: man systemd and look under DIRECTORIES – fbicknel Dec 17 '19 at 13:11
  • 3
    @fbicknel - according to Arch distro that's not correct: https://wiki.archlinux.org/index.php/Systemd/User "/etc/systemd/user/ where system-wide user units are placed by the system administrator." (not that there is necessarily a universal truth value here ... I would just like to do it in the most straightforward way for myself) – some bits flipped Jun 13 '20 at 22:22
  • I'm not sure I understand all this correctly. 1. I got an app installed as non root that I'd like to autostart as specific technical user vs root. Where do I place the .service file and where and how do I tell the system to call systemctl start on boot as that user vs. root? 2. I would like the technical user to start/stop the app using systemctl. I assume changing the permissions of the /lib/systemd/system/ dir is not the right way to go? How can I achieve this? – Thomas Jan 13 '22 at 12:56
  • Regarding "To make the service run on boot, you should not put it in your home folder.": This is wrong; it is fine for a Unix user robert to have a user service nzbget.service located at their ~/.config/systemd/user/nzbget.service. robert can then enable this service with systemctl --user enable nzbget. – Abdull Nov 02 '22 at 10:59
108

You might be interested in using systemd's user lingering functionality. It is enabled via loginctl enable-linger USERNAME.

It causes a separate service manager for the respective user being started at boot, so your user-defined units in ~/.config/systemd/user will be picked up and processed at boot and shutdown times according to your service configuration.

You can also use systemctl --user for managing and configuring the service(s), which will operate on your user's service manager, not the one of the system.

byteborg
  • 1,645
  • 1
  • 13
  • 8
  • 13
    systemctl --user is a fantastic finding. Thanks! – Anwar May 14 '17 at 04:35
  • @byteborg Maybe you can contribute to https://unix.stackexchange.com/questions/409900/user-lingering-systemd-dependency-on-postgresql? I need dependency on PostgreSQL in user lingering service, but database remains system service, not user's one. – Michał F Dec 15 '17 at 09:10
  • 1
    Once the services are running, is there any techniques that can allow the user to see the logs of the service? An unprivileged user wouldn't be able to get to /var/log/syslog. – mpr Mar 16 '18 at 17:27
  • 4
    Note that systemctl --user doesn't seem to work for SSH sessions though. – Mark K Cowan Apr 16 '18 at 12:06
  • 1
    @MarkKCowan it does, you only have to make sure you can run it. In some instances you might get the error systemd[29239]: PAM unable to dlopen(pam_systemd.so): /lib/security/pam_systemd.so: cannot open shared object file: No such file or directory and PAM adding faulty module: pam_systemd.so when doing systemctl start user@$USER.service in that case just install libpam-systemd and you'll get that working and starting at boot – Treviño Jun 17 '18 at 09:40
  • 1
    @mpr have a look at journalctl, unprivileged users can run that. – Terry Brown Apr 30 '20 at 17:00