systemd offers users the ability to run an instance of systemd to manage their session and services. This allows users to start, stop, enable, and disable units found within certain directories when systemd is run by the user. This is convenient for daemons and other services that are commonly run as a user other than root or a special user, such as mpd.
Using systemd --user To Manage Your Session
Systemd has many amazing features, one of which is the ability to track programs using cgroups (by running
systemctl status). While awesome for a pid 1 process to do, it is also extremely useful for users, and having it set up and initialize user programs, all the while tracking what is in each cgroup is even more amazing.
I began using gtmanfred's guide to setting this up. I rewrote it partially to be of more help, and partially to help get this into my head even more.
All of your systemd user units will go to $HOME/.config/systemd/user. These units take precedence over units in other systemd unit directories.
There are two packages you need to get this working, both currently available from the AUR:AUR and AUR.
Next is setting up your targets. I set up two, one for my window manager (i3) and another as a default target. The window manager target, i3wm.target as I called it, should be populated like so:
[Unit] Description=i3wm Wants=xorg.target Wants=myStuff.target Requires=dbus.socket AllowIsolate=true [Install] Alias=default.target
This will be the target for your graphical interface. (Replace i3wm with your choice of window manager/desktop environment.)
I put together a second target called mystuff.target. This will be 'WantedBy' all services but your window manager:
[Unit] Description=Xinitrc Stuff Wants=i3wm.target [Install] Alias=default.target
Link this unit to default.target. When you start
systemd --user, it will start this target.
Next you need to begin writing services. First you should throw together a service for your window manager. I named mine i3.service:
[Unit] Description=i3wm Before=mystuff.target After=xorg.target [Service] Requires=xorg.target Environment=PATH=/home/wgiokas/.cabal/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/home/wgiokas/bin Environment=DISPLAY=:0 ExecStart=/usr/bin/i3 Restart=always RestartSec=10 [Install] WantedBy=i3wm.target
Note the [Install] section includes a 'WantedBy' part. When using
systemctl --user enable it will link this as $HOME/.config/systemd/user/i3wm.target.wants/i3.service, allowing it to be started at login. I would recommend enabling this service, not linking it manually.
You can fill your user unit directory with a plethora of services, I currently have ones for mpd, gpg-agent, offlineimap, parcellite, pulse, tmux, urxvtd, xbindkeys and xmodmap to name a few.
Doing this will not allow you to run
systemd --user, though. If you installed user-session-units as listed above, then you must copy user-session@.service to your user unit directory and use
systemctl --user enable email@example.com (replace the obvious). Next, edit the user-session@.service (not the firstname.lastname@example.org) and edit this line:
to this: (Note the subtle change where the
Last but not least, add this line to /etc/pam.d/login or /etc/pam.d/systemd-auth (whichever exists):
session required pam_systemd.so
/usr/lib/systemd/systemd --user to your shell's $HOME/.*profile file and you are ready to go! (This takes a lot of tweaking, so when I say that, I mean that you are ready to debug and find spelling mistakes.)
One of the most important things you can add to the service files you will be writing is the use of Before= and After= in the [Unit] section. These two parts will determine the order things are started. Say you have a graphical application you want to start on boot, you would put `After=xorg.target' into your unit. Say you start ncmpcpp, which requires mpd to start, you can put `After=mpd.service' into your ncmpcpp unit. You will eventually figure out exactly how this needs to go either from experience or from reading the systemd manual pages. I would recommend starting with systemd.unit(5).
Once all of this is up and running, you can type
systemctl --user status i3.service (or whatever your window manager or desktop environment is called) and see something like this:
i3.service - i3wm Loaded: loaded (/home/wgiokas/.config/systemd/user/i3.service; enabled) Active: active (running) since Wed 2012-12-19 20:28:24 CST; 3h 8min ago Main PID: 11115 (i3) CGroup: name=systemd:/user/wgiokas/3/systemd-11047/i3.service ├─11115 /usr/bin/i3 ├─11127 i3bar --bar_id=bar-tyxnbu --socket=/run/user/1000/i3/ipc-socket.11115 ├─11133 i3status -c /home/wgiokas/.i3/status.conf ├─27069 /bin/zsh ├─27088 luakit ├─29306 /bin/zsh └─29317 dwb
<unit>@.services too, and in that service
%iwill expand to the text between the
.servicepart, so if I wanted to have multiple instances of a window manager, for example on different displays, I could set the
email@example.com:5.serviceif that tickled my fancy.
Users should first set up systemd-logind to manage their session. If systemd is running as the system init daemon, then this is already happening.
Next, the user must launch systemd by putting the following in their
~/.xinitrc before the exec line:
systemd --user &
After starting X, the user can check whether their session is now being managed by systemd-logind with the following command:
$ loginctl --no-pager show-session $XDG_SESSION_ID | grep Active
If this command prints
Active=yes, then the user is now using systemd-logind to manage their session. The user should remove any instances of ck-launch-session or dbus-launch from their
~/.xinitrc, as those commands are unneeded.
All of the major display managers are now using systemd-logind by default, so the
loginctl command from the previous section should work as stated. A user simply has to add
systemd --user as a program to be started by their desktop environment.
Users may now interact with units located in the following directories just as they would with system services (ordered by ascending precedence):
To control the systemd instance, the user must use the command
Installed by packages
A unit installed by a package that is meant to be run by a systemd user instance should install the unit to
/usr/lib/systemd/user/. The system adminstration can then modify the unit by copying it to
/etc/systemd/user/. A user can then modify the unit by copying it to
The following is an example of a user version of
[Unit] Description=Music Player Daemon [Service] ExecStart=/usr/bin/mpd --no-daemon [Install] WantedBy=default.target
Example with variables
The following is an example of a user version of
sickbeard.service, which takes into account variable home directories where SickBeard can find certain files:
[Unit] Description=SickBeard Daemon [Service] ExecStart=/usr/bin/env python2 /opt/sickbeard/SickBeard.py --config %h/.sickbeard/config.ini --datadir %h/.sickbeard [Install] WantedBy=default.target
As detailed in
man systemd.unit, the
%h variable is replaced by the home directory of the user running the service. There are other variables that can be taken into account in the systemd manpages.