Handling /var/run with systemd
Tuesday, August 6. 2013
Previously I've studied the init.d replacement systemd.
Update 4th Jun 2017: See the new version
To my surprise, my contraption from the previous article didn't survive a reboot. WTF?! It turned out that in Fedora 19 the /var/run/
is a symlink into /run/
which has been turned into tmpfs. Goddamnit! It literally means, that it is pointless to create /var/run/<the daemon name here>/
with correct permissions in RPM spec-file. Everything will be wiped clean on next reboot anyway.
So, I just had to study the systemd some more.
This is my version 2 (the Unit
and Install
-parts are unchanged):
[Service]
Type=forking
PrivateTmp=yes
User=nobody
Group=nobody
# Run ExecStartPre with root-permissions
PermissionsStartOnly=true
ExecStartPre=-/usr/bin/mkdir /var/run/dhis
ExecStartPre=/usr/bin/chown -R nobody:nobody /var/run/dhis/
# Run ExecStart with User=nobody / Group=nobody
ExecStart=/usr/sbin/dhid -P /var/run/dhis/dhid.pid
PIDFile=/var/run/dhis/dhid.pid
The solution is two-fold. First an ExecStartPre
-directive is required. It allows to run stuff before actually executing the deamon. My first thing to do is create a directory, the minus sign before the command says to ignore any possible errors during creation. The target is mainly to ignore any errors from the fact that creation would fail due to the directory already existing. Anyway, all errors are ignored regardless of the reason.
The second command to run is to make sure that permissions are set correctly for my daemon to create a PID-file into the directory created earlier. That must succeed or there will be no attempt to start the daemon. chown
ing the directory will fail if the directory does not exist, or any other possible reason.
Sounds nice, huh? Initially I couldn't get that working. It was simply due to reason, that the entire Service
-part is run as the user pointed by the User=nobody
and Group=nobody
-directives. That user was intentionally chosen, because it has very limited permission anywhere or anything. Now it cannot create any new directories into/var/run/
. Darn!
This where the solution's 2nd part comes in. Somebody designing the systemd thought about this. Using the PermissionsStartOnly
-directive does the security context switch at the last moment before starting the daemon. This effectively changes the default behavior to allow running Service
-part as root, except for the daemon. Exactly what I was looking for! Now my daemon starts each and every time. Even during boot.
Another thing which I noticed, is that when I edit a systemd service-file, the changes really don't affect before I do a systemctl --system daemon-reload
. It was a big surprise to me, after all in traditional init.d everything was effective immediately.
PS.
Why cronie does not create a PID-file? I had an issue in CentOS where I had not one, but two cron-daemons running at the same time. This is yet another reason to go systemd, it simply works better with ill-behaving deamons like cronie.
erick j on :
http://fedoraproject.org/wiki/Packaging:Tmpfiles.d
man tmpfiles.d
Essentially you can just add an entry to /etc/tmpfiles.d/foo.conf like this:
$ cat /etc/tmpfiles.d/fail2ban.conf
D /var/run/fail2ban 0755 fail2ban fail2ban
egmont on :
PermissionsStartOnly has the drawback that you can't run e.g. an ExecStartPost with the desired non-root user (unless you do a manual "su").
tmpfiles.d is cumbersome to maintain, it's nicer if the required directory can be specified in the .service file.
Seems that there's a new directive RuntimeDirectory=, designed specifically to create a directory under /run. If you have a recent enough systemd (>= 211), probably that's the simplest way to go.
Jari Turkia on :
It is obvious, that everybody have been having the same problem. The obvious fix is to add the new directive, just as they did into newer versions.
Eric on :
http://www.freedesktop.org/software/systemd/man/tmpfiles.d.html
Jari Turkia on :
I already updated my RPM-package with tmpfiles.d. I'll get back to this subject to explain my recent changes.
Jack on :
ExecStartPre=/usr/bin/install -o nobody -g nobody -d /var/run/dhis
Jari Turkia on :
Anyway, as number of people pointed out, using the systemd-tmpfiles is the kosher way of handling the issue.
Andy on :
You'd better used it than skipped all errors by - flag.
Jari Turkia on :
Prashant on :
I had a different sequence earlier and the system wouldn't let me use 'mkdir'
Only after adjusting the sequence as shown in the example, it was successful.
Charlie on :
/usr/lib/tmpfiles.d/
do the create job on boot.
Jari Turkia on :
The thing is, I've learned couple of new tricks since August 2013. It's another thing to update this article.
SegFaulty on :
RuntimeDirectory=dhis
see: https://www.freedesktop.org/software/systemd/man/systemd.exec.html#RuntimeDirectory=
Jari Turkia on :
Confirmed!
https://github.com/systemd/systemd/commit/5732a7dbb0efa79cc36c6864a4af2e98685b53d6#diff-f3f577c0bbbeb92b4c86bf42eb2a83be
Is dated 2 Nov 2015.
But thanks for letting me know about that. I've been planning a re-visit post about that subject anyway. Now there are enough reasons to actually do it.
Jim Ciallella on :
https://www.orangecoat.com/how-to/run-memcached-as-a-socket-under-systemd-in-centos-or-rhel-7
Thanks again,
Jim
Attila Kreiner on :
Kelran on :
[Service]
Type=forking
PrivateTmp=yes
User=nobody
Group=nobody
RuntimeDirectory=dhis
RuntimeDirectoryMode=0750
# Run ExecStart with User=nobody / Group=nobody
# because User and group have been set
ExecStart=/usr/sbin/dhid -P /var/run/dhis/dhid.pid
PIDFile=/var/run/dhis/dhid.pid
Best regards,
Kelran
Jari Turkia on :
Kelran on :
No doubt, you're right. RuntimeDirectory and RuntimeDirectoryMode have been introduced with systemd 211 in march 2014.
I posted a valid and full configuration just to help other users with the same problem and a recent version of systemd.
- Kelran
löchlein deluxe on :
F on :
- F
Ap.Muthu on :
Daniels on :
As pointed by Andy, it's better to use 'mkdir -p'. The '-p' only ignore errors if the directory already exists. It will return an error if other problem rises (like permission denied).
This way if you do a "systemctl status" in your service, you will not have a "failure" status in the PreExecStart phase.
Thank you for the post. It was very helpful. Regards.
Jari Turkia on :
M on :
I completely missed out on the PermissionsStartOnly option.
Brandon Leroux on :