The ownership of log files in /opt/openwisp2/log/ can be set to root:root during deployment. This affects most log files created in the log directory and can prevent www-data processes (uWSGI, celery, nginx worker) from writing to them.
Affected Files
| Log File |
Created By |
Root Ownership Cause |
uwsgi.log |
supervisord |
supervisor runs as root |
celery.log |
supervisord |
supervisor runs as root |
celerybeat.log |
supervisord |
supervisor runs as root |
celery-network.log |
supervisord |
supervisor runs as root |
celery-monitoring.log |
supervisord |
supervisor runs as root |
celery-firmware-upgrader.log |
supervisord |
supervisor runs as root |
daphne.log |
supervisord |
supervisor runs as root |
nginx.access.log |
nginx master |
nginx master runs as root |
nginx.error.log |
nginx master |
nginx master runs as root |
openwisp2.log |
Django RotatingFileHandler |
Created as www-data by uWSGI, but can become root-owned when load_initial_data.py or cron jobs run as root first |
Steps To Reproduce
- Deploy OpenWISP2 using this role with
become: true.
- Supervisord (running as root) creates all supervisor log files (
uwsgi.log, celery.log, etc.) with root:root ownership.
- Nginx master (running as root) creates
nginx.access.log and nginx.error.log with root:root ownership.
- The
load_initial_data task (tasks/django.yml:226) runs as root, causing Django's RotatingFileHandler (templates/openwisp2/settings.py:487-494) to create openwisp2.log as root:root 0644.
- Alternatively, any of the cron jobs (
tasks/cron.yml:1-29) run as root and can trigger a log rollover, creating a new file as root.
www-data processes (uWSGI, celery, nginx worker) fail to write to root-owned log files.
Expected behavior
All log files in /opt/openwisp2/log/ should be owned by {{ www_user }}:{{ www_group }} so that application processes running as www-data can write to them.
Root Cause Analysis
- Log directory missing
owner (tasks/django.yml:16-24):
- name: Create openwisp2 log directory
ansible.builtin.file:
path: "{{ openwisp2_path }}/log"
state: directory
group: "{{ www_group }}"
mode: "0770"
recurse: true
No owner is specified, so the directory is created as root:{{ www_group }} when running with become: true.
-
Supervisor log files created as root (templates/supervisor/*.j2):
All supervisor templates specify stdout_logfile in the log directory. Supervisord runs as root and therefore creates these log files as root:root, even though child processes run as www-data.
-
Nginx log files created as root (templates/nginx/site-conf.j2:25-26):
Nginx master (root) creates nginx.access.log and nginx.error.log with root ownership.
-
load_initial_data runs as root (tasks/django.yml:226-236):
The task uses ansible.builtin.command without become_user: "{{ www_user }}". When django.setup() runs it instantiates RotatingFileHandler which may create openwisp2.log as root:root.
-
Cron jobs run as root (tasks/cron.yml:1-29):
All three cron tasks use become: true without become_user, so they execute as root and can create or roll over openwisp2.log as root.
-
No logrotate for supervisor/Django logs:
Logrotate is configured for nginx logs with a create 0640 {{ www_user }} {{ www_group }} directive, but there is no equivalent logrotate configuration for the 7 supervisor log files or openwisp2.log.
The ownership of log files in
/opt/openwisp2/log/can be set toroot:rootduring deployment. This affects most log files created in the log directory and can preventwww-dataprocesses (uWSGI, celery, nginx worker) from writing to them.Affected Files
uwsgi.logcelery.logcelerybeat.logcelery-network.logcelery-monitoring.logcelery-firmware-upgrader.logdaphne.lognginx.access.lognginx.error.logopenwisp2.logwww-databy uWSGI, but can become root-owned whenload_initial_data.pyor cron jobs run as root firstSteps To Reproduce
become: true.uwsgi.log,celery.log, etc.) withroot:rootownership.nginx.access.logandnginx.error.logwithroot:rootownership.load_initial_datatask (tasks/django.yml:226) runs as root, causing Django'sRotatingFileHandler(templates/openwisp2/settings.py:487-494) to createopenwisp2.logasroot:root 0644.tasks/cron.yml:1-29) run as root and can trigger a log rollover, creating a new file as root.www-dataprocesses (uWSGI, celery, nginx worker) fail to write to root-owned log files.Expected behavior
All log files in
/opt/openwisp2/log/should be owned by{{ www_user }}:{{ www_group }}so that application processes running aswww-datacan write to them.Root Cause Analysis
owner(tasks/django.yml:16-24):No
owneris specified, so the directory is created asroot:{{ www_group }}when running withbecome: true.Supervisor log files created as root (
templates/supervisor/*.j2):All supervisor templates specify
stdout_logfilein the log directory. Supervisord runs as root and therefore creates these log files asroot:root, even though child processes run aswww-data.Nginx log files created as root (
templates/nginx/site-conf.j2:25-26):Nginx master (root) creates
nginx.access.logandnginx.error.logwith root ownership.load_initial_dataruns as root (tasks/django.yml:226-236):The task uses
ansible.builtin.commandwithoutbecome_user: "{{ www_user }}". Whendjango.setup()runs it instantiatesRotatingFileHandlerwhich may createopenwisp2.logasroot:root.Cron jobs run as root (
tasks/cron.yml:1-29):All three cron tasks use
become: truewithoutbecome_user, so they execute as root and can create or roll overopenwisp2.logas root.No logrotate for supervisor/Django logs:
Logrotate is configured for nginx logs with a
create 0640 {{ www_user }} {{ www_group }}directive, but there is no equivalent logrotate configuration for the 7 supervisor log files oropenwisp2.log.