Ubuntu – How to automatically create a runtime folder with a systemd service or tmpfiles.d

pythonsocketsystemdUbuntu

I'm trying to create a runtime folder at /run/gunicorn for some Gunicorn socket / PID files, which are for a Django application. I can get everything working if I manually create directories. However, I'm trying to make this a robust setup, and eventually use Ansible to automate everything.

I think I have 2 options, based on this question.

Option 1 – RuntimeDirectory

I think the first option is to use RuntimeDirectory= within my systemd service file, but I can't get it to create the folder. The service files contains:

#/etc/systemd/system/gunicorn_django_test.service
[Unit]
Description=gunicorn_django daemon
After=network.target

[Service]
User=gunicorn
Group=www-data
RuntimeDirectory=gunicorn #This line is supposed to create a directory
RuntimeDirectoryMode=755
PIDFile=/run/gunicorn/django_test_pid
WorkingDirectory=/vagrant/webapps/django_venv/django_test
ExecStart=/vagrant/webapps/django_venv/bin/gunicorn --pid /run/gunicorn/django_test_pid --workers 3 --bind unix:/run/gunicorn/django_test_socket django_test.wsgi --error-logfile /var/log/gunicorn/django_test_error.log
ExecReload=/bin/kill -s HUP $MAINPID
ExecStop=/bin/kill -s TERM $MAINPID
PrivateTmp=true

[Install]
WantedBy=multi-user.target

When I run systemctl start gunicorn_django_test.service, the service fails to start. When I snip out the exec line, and run it manually, I get Error: /run/gunicorn doesn't exist. Can't create pidfile. If I create the /run/gunicorn folder manually, I can get things to work.

Option 2 – tmpfiles.d

The second option is to use tmpfiles.d to have a folder created on boot, ready for the pid / socket files. I've tried this file:

#/etc/tmpfiles.d/gunicorn.conf
d /run/gunicorn 0755 gunicorn www-data -

This creates a directory, but it is quickly deleted somehow, and by the time I start the service, the folder isn't available.

I can manually add some PreExec mkdir commands into the service file, but I'd like to get to the bottom of why RuntimeDirectory / tmpfiles.d aren't working. Thanks.

Versions / Info:
Ubuntu 16.04 Server / systemd 229 / Gunicorn 19.7.1 / runtime dir = /run

Best Answer

I added in PermissionsStartOnly=True and set a runtime folder per service, as suggested. I also added 0 to the start of the folder mode.

[Unit]
Description=gunicorn_django daemon
After=network.target

[Service]
PermissionsStartOnly=True
User=gunicorn
Group=www-data
RuntimeDirectory=gunicorn_django
RuntimeDirectoryMode=0775
PIDFile=/run/gunicorn_django/django_test_pid
WorkingDirectory=/vagrant/webapps/django_venv/django_test
ExecStart=/vagrant/webapps/django_venv/bin/gunicorn --pid /run/gunicorn_django/django_test_pid --workers 3 --bind unix:/run/gunicorn_django/django_test_socket django_test.wsgi --error-logfile /var/log/gunicorn/django_test_error.log
ExecReload=/bin/kill -s HUP $MAINPID
ExecStop=/bin/kill -s TERM $MAINPID

[Install]
WantedBy=multi-user.target

It's now creating a folder with the correct permissions.

drwxrwxrw-  2 gunicorn www-data   40 Mar 30 07:11 gunicorn_django/

Thanks @quixotic and @mark-stosberg

Related Question