1

I am trying to setup a service which requires access to X-Windows and DBus. First I tried it as a background application, but that just doesn't work. I use the "auto-log user" feature. Now I think that the service needs to run as that auto-log user (say alexis). My problem is that I can easily create a service running as that user (i.e. setting the User=alexis and Group=alexis variables). I also had to add an environment variable (DISPLAY=:0). However, the service is still started as a system service.

What I was thinking is to create a service in a way that it get started when the user logs in. I see many systemd entries when I run:

systemctl --user list-units

but I'm not too sure how to create such a service file and get the Ubuntu package creation tool chain to create a service which is for users and not the OS at large.

The following is my current my-daemon.service file which lingers in the debian folder of the project:

# Documentation available at:
# https://www.freedesktop.org/software/systemd/man/systemd.service.html

[Unit]
Description=Daemon

[Service]
Type=simple
WorkingDirectory=~
ProtectHome=false
NoNewPrivileges=true
ExecStart=/usr/sbin/my-daemon
ExecStop=kill "$MAINPID"
Restart=on-failure
RestartSec=1min
User=alexis
Group=alexis
LimitNPROC=1000

[Install]
WantedBy=xsession.target

So the service file gets installed under /lib/systemd/system and I think that's wrong in my situation. Otherwise it looks like it works as expected... but I'm not really 100% sure the settings are correct for a per-user unit. I've been looking around and I was not able to find much about user units. It's like something that must be top secret...

Alexis Wilke
  • 2,697
  • 2
  • 19
  • 42
  • 1
    Try putting the .service file in `$HOME/.config/systemd/user`. – ajgringo619 Nov 05 '20 at 00:58
  • @ajgringo619 For a Debian package, though, that doesn't make sense... That is, the package could have a path that specifically places the service file in that location, but I don't think that would be considered clean in any way... – Alexis Wilke Nov 05 '20 at 01:05
  • It's not like packages don't put things in `$HOME/.config` as it is, right? – ajgringo619 Nov 05 '20 at 01:06
  • @ajgringo619 Actually, thinking about it, I'm working on an embedded system so I create the user that will run that daemon... therefore I have the exact path. That can work, I think. – Alexis Wilke Nov 05 '20 at 02:14
  • 1
    User units are looked for in `/usr/lib/systemd/user/` as well, which is more suitable for a distributed package. See [archlinux](https://wiki.archlinux.org/index.php/Systemd/User#How_it_works). – meuh Nov 05 '20 at 10:48

1 Answers1

1

From the comments by @ajgringo619 and @meuh, I ended up using the following solution:

  1. Manually install the my-daemon.service file

    I moved my-daemon.service out of my project's debian directory to another directory (I used conf directory).

  2. Added a line to my project .install file to install the service as a user service

     conf/my-daemon.service      /usr/lib/systemd/user/.
    

    See also this archlinux page (link provided by @meuh)

  3. Enable the service

    To do that, I could not use the systemctl because there is no dbus running for that user when I run the installation (i.e. I install from my account and the installation packages create a "newuser" which exists, but is not active). So to enable the service I have to manually create the softlink.

    This requires a little bit of work. First make sure that the folder exists, create the softlink, then fix the user ownership:

     mkdir -p /home/newuser/.config/systemd/user/default.target.wants
     ln -s /usr/lib/systemd/user/my-daemon.service /home/newuser/.config/systemd/user/default.target.wants/.
     chown -R newuser:newuser /home/newuser/.config/systemd
    
  4. Cleanup

    If you want to do the opposite of (3) you have to delete the softlink and remove the folders. Use the -f option in case it was already removed and on the rmdir, use the --ignore-fail-on-non-empty. For the rmdir, make sure to delete each one, the deepest one first, that you get a state similar to what you'd have before installation.

  5. Autostart?

    Creating the link in (3) is the autostart (enable), restart the computer or log out and back in as that new user and the unit will be started automatically. This assumes that the service functions, of course. Make sure that your wants is correctly defined:

     [Install]
     WantedBy=default.target
    

    There are other options that will not work in a user service. For example, you can't specify the User=... nor the Group=... options. Such mistakes will appear in the corresponding journal

     journalctl --user -u my-daemon
    

    Important Note: the --user is very important, if you ran your service as a system service earlier, with the --user you'll see the logs from the system service and nothing from your user's logs.

Another detail, I had to open a window and for that to work, I had to add an environment variable:

Environment="DISPLAY=:0"

You'll want to do such tweaks depending on the errors you can see in your unit's journal.

Alexis Wilke
  • 2,697
  • 2
  • 19
  • 42
  • 1
    Reading `man systemd.preset` I note that you can list what services to enable by default (the "vendor" preset message you see in systemctl status output). The only examples however are for system services, but the man page lists directories for `user-preset` files. Good luck if you try to get that working. – meuh Nov 05 '20 at 20:32