Systemd – Setup User Autostart and Configure Systemd User Services

arch linuxsystemdsystemd-unitusers

On my arch server, I was setting up users restricted to their home directories. I ran:

useradd -m -s /bin/bash username and passwd username

I've read this wiki article…

I figured I should use systemd user services to make each user run a node server on startup. So i logged into one user account su username and created a file ~/.config/systemd/user/serve.service containing:

[Unit]
Description=One of the servers

[Service]
ExecStart=/usr/bin/node /home/username/server.js

[Install]
WantedBy=default.target

then I ran systemctl --user enable serve.service which responded with Failed to connect to bus: Permission denied

As far as I understand I should run systemctl --user ... command logged in as a user and not as root.

So what did I miss in this configuration?

Best Answer

So I logged into one user account su username

No, you did not.

You are not logging in. You are augmenting the privileges of your existing login session with su username.

systemctl with the --user option locates your per-user Desktop Bus, managed by you per-user Desktop Bus dæmon, and via that bus communicates with your per-user instance of systemd that manages your per-user servics.

su is not a login mechanism. It works within an existing interactive login session. In that session, your processes have environment variables that tell them where your per-user runtime directory is (XDG_RUNTIME_DIR), where the per-user Desktop Bus is (DBUS_SESSION_BUS_ADDRESS), and indeed other things like where your X server is (DISPLAY).

In particular, DBUS_SESSION_BUS_ADDRESS can implicitly reference XDG_RUNTIME_DIR or can explicitly name the same path. That path will generally be something like /run/user/1001/bus for the Desktop Bus broker's access socket (presuming that your user ID is 1001, for example).

These variables are not changed by su. There's been a whole back and forth for many years over this, including the behaviours of other similar commands such as pkexec.

The consequence of this is that if you su to a second user in your login session, running systemctl as that second user tries to connect to a Desktop Bus broker access socket located in a directory private to the first user. User 1002 (to pick a user ID for your second user for the sake of example) cannot access /run/user/1001 or anything within it, and even if xe had read+execute access to that directory xe cannot access /run/user/1001/bus because that only grants access to user 1001 also.

Of course, this is not the right Desktop Bus broker to be talking to in the first place. You want to talk to the second user's Desktop Bus broker, and through it to the second user's per-user instance of systemd.

The simple solution is as part of the su to set those environment variables to the ones appropriate for the second user account, pointing to the second user's Desktop Bus:

DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1002/bus su username -c 'systemctl --user'

I of course in such circumstances use a handy tool for setting this, userenv, which enables me not to have to type that bus address longhand:

su username -c 'userenv --set-dbus systemctl --user'

Further reading