16

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

5
  • 1
    It's something to do with group permissions in the /run/ folder. I can create a 0755 folder with the group as www-data, but I need the folder to be group writeable, so both the Nginx user and the Gunicorn user can access the socket file. In order to do that, I need sudo-level permissions. For some reason, sudo systemctl... etc isn't passing the sudo permissions to the service.
    – geonaut
    Mar 29, 2017 at 15:47
  • 3
    i'll bet it's trying to create the directory with the uid from User= and failing. try adding PermissionsStartOnly=true. see unix.stackexchange.com/a/207493/222377
    – quixotic
    Mar 29, 2017 at 17:07
  • hmm. actually i'll bet it's failing because the runtime directory is made but isn't /run/gunicorn. it's probably $XDG_RUNTIME_DIR/gunicorn which might resolve to /run/user/$UID/gunicorn for the gunicorn user UID. (same question, next answer.)
    – quixotic
    Mar 29, 2017 at 17:16
  • Are you trying to use the same directory for multiple Gunicorn instances? You could be running into this related issue> Mar 29, 2017 at 17:22
  • Your Option 2 would have worked. However, the tmpfiles.d and RuntimeDirectory=... definitions are not compatible. You should not have both turned on at the same time. Oct 26, 2018 at 8:02

2 Answers 2

15

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

3

My problem was that I had two services using same RuntimeDirectory (isc-dhcp-server and isc-dhcp-server6), but I configured only one to work. So when the second one died, its runtime directory got removed, making it a problem for the first service.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.