systemd is useful for system initialization, but it it also useful from a user
systemctl --system to do anything requires root privileges
and is therefore not useful to unprivileged users. Starting their personal
services either requires them to be enabled or to be started by someone with
root privileges. Recently, I have begun working with the user part of systemd.
This allows me to use systemd to start unprivileged services, such as my
window manager, tmux session, music player daemon and more.
I began using gtmanfred's guide to set this up. I am going to rewrite 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: xorg-launch-helper and user-session-units. You should also have at least the ability to apply patches and edit pkgbuilds. Just remember that this is no easy feat. Though once you get it working you will be rewarded with a damn beautiful system.
Creating some starting units
Next is setting up your targets. I set up two, one for my window manager (dwm)
and another as a default target. The window manager target,
populated it like so:
[Unit] Description=Window manager target Wants=xorg.target Wants=mystuff.target Requires=dbus.socket AllowIsolate=true [Install] Alias=default.target
This will be the target for your graphical interface.
I put together a second target called
mystuff.target. You can call it whatever
you want, but this is what I have in my service files and this wiki. This will
be 'WantedBy' all services but your window manager:
[Unit] Description=Xinitrc Stuff Wants=wm.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
[Unit] Description=Simple tiling/stacking/tabbed window manager Before=mystuff.target After=xorg.target Requires=xorg.target [Service] ## uncomment this if you want to have a non-default path #Environment=PATH=%h/.cabal/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:%h/bin ExecStart=/usr/bin/dwm Restart=always RestartSec=10 [Install] WantedBy=wm.target
Note the [Install] section includes a 'WantedBy' part. When using
--user enable it will link this as
$HOME/.config/systemd/user/wm.target.wants/dwm.service, allowing it to be
started at login. I would recommend enabling this service, not linking it
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. This allows these programs to be tracked by systemd individually.
Some actual important stuff
Last but not least, add this line to /etc/pam.d/login and /etc/pam.d/system-auth:
session required pam_systemd.so
/usr/lib/systemd/systemd --user to your shell's
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.)
Using these services and target will give you a very minimal user environment. I would recommend making service files for as many applications as possible and then using those to start the applications. That way things can be tracked and managed easily. I would also recommend following the next section in this wiki, though it requires patching systemd or using a git version. (When 197 is released, this will no longer be necessary)
You can also have systemd --user track your login shell. This is quite useful,
in my opinion. To do so, you can use a display manager that is started with
systemd (usually enabled and started at boot) or you can autologin with
user-session@.service. Copy the
user-session@.service to your
/etc/systemd/system/ directory and edit it there. You will also need to
firstname.lastname@example.org for this to work correctly.
You will need to patch systemd to do this, so either using systemd-git from after commit 067d851d or patch it into systemd with the ABS. Then edit this line:
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
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).
Just as a note to readers and users, I am by no means an expert on this stuff. It's not easy, and it made me work. If you don't get it to work the first time, don't just pass it off as a failed attempt. I completely botched it my first try, and only got it working with some more reading and excellent help. Don't give up!
A quick graph of how my units start:
systemd-analyze --fuzz=1 critical-chain
The time after the unit is active or started is printed after the "@" character. The time the unit takes to start is printed after the "+" character.
mystuff.target @358ms ├─xbindkeys.service @296ms │ ├─xorg.target @295ms │ │ └─xorg.service @23ms +271ms │ │ ├─sockets.target @22ms │ │ │ ├─dbus.socket @22ms │ │ │ │ └─-.mount @11ms │ │ │ └─mpd.socket @22ms │ │ ├─timers.target @22ms │ │ └─paths.target @22ms │ ├─sockets.target @22ms │ │ └─... │ ├─timers.target @22ms │ │ └─... │ └─paths.target @22ms │ └─... ├─xautolock.service @295ms │ ├─xorg.target @295ms │ │ └─... │ ├─sockets.target @22ms │ │ └─... │ ├─timers.target @22ms │ │ └─... │ └─paths.target @22ms │ └─... ├─gpg-agent.service @23ms +26ms │ ├─sockets.target @22ms │ │ └─... │ ├─timers.target @22ms │ │ └─... │ └─paths.target @22ms │ └─... ├─udiskie.service @24ms │ ├─sockets.target @22ms │ │ └─... │ ├─timers.target @22ms │ │ └─... │ └─paths.target @22ms │ └─... ├─urxvtd.service @23ms │ ├─sockets.target @22ms │ │ └─... │ ├─timers.target @22ms │ │ └─... │ └─paths.target @22ms │ └─... └─mpd.socket @22ms └─...