Skip to content
🎉 Launch sale:50% off everything over $22 — automatically applied at checkout· ends Aug 2Shop the sale →
DevOps AI ToolKit
Newsletter
All guides
AI for NGINX By James Joyner IV · · 8 min read Last reviewed Jul 2026

Nginx Error: 'could not open error log file: open() '/var/log/nginx/error.log' failed (13: Permission denied)' — Cause, Fix, and Troubleshooting Guide

Quick answer

Fix could not open error log file: open() failed (13: Permission denied): create /var/log/nginx, fix its owner and SELinux, and check logrotate.

  • #nginx
  • #web-server
  • #troubleshooting
Free toolkit

Stuck on this NGINX error? Get the free incident triage checklist

A one-page PDF — the exact steps to isolate, fix, and verify a production error like this one. No spam, unsubscribe anytime.

What this error means

This is one of the earliest failures NGINX can hit: before it can even open its normal log, it tries to open the error log file and is denied permission to write to it (or the directory holding it does not exist). Because the error log itself is unavailable, NGINX writes this message to stderr, so you see it on the console or in journalctl, not in error.log:

nginx: [alert] could not open error log file: open() "/var/log/nginx/error.log" failed (13: Permission denied)
nginx: [emerg] open() "/var/log/nginx/error.log" failed (13: Permission denied)

The 13 is EACCES. NGINX cannot start, so the whole service is down. This most often appears right after a fresh install where /var/log/nginx is missing, after someone deleted the log directory, after a logrotate run recreated the file with the wrong owner, or when the log volume has become read-only.

How the server responds

  • systemctl start nginx fails and journalctl -u nginx shows could not open error log file ... (13: Permission denied) on stderr.
  • Nothing is written to error.log itself, because that is precisely the file it cannot open.
  • It appears right after install, after /var/log/nginx was removed, or after a nightly logrotate run.
  • ls -ld /var/log/nginx shows the directory missing, or owned by root with no worker access.
  • The master process starts as root but the failure can still occur if the path or the mount is unwritable.
  • On RHEL-family hosts, getenforce is Enforcing and ausearch shows an AVC denial on the log path.

Testing the server configuration

Because the message goes to stderr, read it from the service journal and by running the binary directly:

# The failure as systemd captured it (stderr)
journalctl -u nginx --since "10 min ago" --no-pager

# Run the config test — it reveals the same open() failure on stderr
sudo nginx -t

Check whether the directory exists and who owns it and the log file:

ls -ld /var/log/nginx
ls -l  /var/log/nginx/
namei -l /var/log/nginx/error.log

Confirm the configured log path (it may not be the default) and the worker user:

sudo nginx -T | grep -E "error_log|access_log|^user"

Rule out a full or read-only mount, and SELinux on RHEL-family hosts:

df -h /var/log
mount | grep " /var"          # look for 'ro' in the options
getenforce
ls -Zd /var/log/nginx
sudo ausearch -m avc -ts recent | grep nginx

Server configuration causes

  • /var/log/nginx does not exist. After a partial install, a manual cleanup, or a stripped container image, the parent directory is simply gone and open() fails.
  • Wrong ownership/permissions on the directory or file. The log dir or error.log is owned by another user or is mode 700 such that the process cannot write to it.
  • logrotate recreated the file with the wrong owner. A create line in the rotate config that omits or mis-sets the owner leaves error.log owned by root:root or an unexpected user after rotation, and the next start/reopen fails.
  • SELinux context on the log path is wrong. The directory lacks the var_log_t type (e.g. a bind-mounted or custom log location), so the httpd_t domain is denied even with correct Unix permissions.
  • Read-only or full filesystem. The /var/log mount is read-only (common after an fsck or a disk error) or /var is full, so no file can be opened for writing.
  • A custom error_log path pointing somewhere unwritable. An error_log /opt/logs/nginx.err; directive aimed at a directory the process cannot write to.

The fix

1. Create the directory and set correct ownership. The log directory should be owned by the worker user (or root with group access) and be writable. On most distros:

sudo mkdir -p /var/log/nginx

# Debian/Ubuntu
sudo chown -R www-data:adm /var/log/nginx
sudo chmod 755 /var/log/nginx

# RHEL/CentOS/Fedora
sudo chown -R nginx:nginx /var/log/nginx
sudo chmod 755 /var/log/nginx

If error.log exists but is owned by the wrong user (a classic post-logrotate state), fix the file too:

sudo chown www-data:adm /var/log/nginx/error.log   # or nginx:nginx on RHEL
sudo chmod 640 /var/log/nginx/error.log

2. Fix the logrotate config so it recreates the file correctly. The create directive must set the owner NGINX expects; otherwise you will hit this again after the next rotation:

# /etc/logrotate.d/nginx
/var/log/nginx/*.log {
    daily
    missingok
    rotate 14
    compress
    delaycompress
    notifempty
    create 0640 www-data adm       # RHEL: create 0640 nginx nginx
    sharedscripts
    postrotate
        [ -f /var/run/nginx.pid ] && kill -USR1 $(cat /var/run/nginx.pid)
    endscript
}

Test the rotation without waiting a day:

sudo logrotate -d /etc/logrotate.d/nginx   # dry run
sudo logrotate -f /etc/logrotate.d/nginx   # force, then confirm ownership

3. Restore the SELinux context (RHEL-family). For a default or custom log path:

sudo semanage fcontext -a -t var_log_t "/var/log/nginx(/.*)?"
sudo restorecon -Rv /var/log/nginx

4. Handle a read-only or full filesystem. If mount shows ro, remount read-write after resolving the underlying disk issue, and clear space if /var is full:

sudo mount -o remount,rw /var
df -h /var/log

5. Validate and start. Since NGINX is not running, start it (a reload has nothing to signal):

sudo nginx -t && sudo systemctl start nginx

Safe configuration practice

  • This message goes to stderr, not error.log — by definition the log is unavailable. Always check journalctl -u nginx, not the file, for this one.
  • logrotate is the usual repeat offender. If the error returns every night around rotation time, the create owner in the rotate config is wrong — fix it there, not just with a one-off chown.
  • Match ownership to the worker user in nginx.conf. Changing the user directive without re-chowning /var/log/nginx reintroduces the failure.
  • Custom error_log paths need the same treatment — directory must exist, be owned/writable, and carry var_log_t under SELinux.
  • Read-only /var masquerades as a permission error. Check mount for ro before chasing ownership; alert on failed NGINX starts via your monitoring dashboard.
  • In containers, prefer logging to stdout/stderr (error_log /dev/stderr;) so there is no log directory to permission at all.

See the NGINX category for more guides.

Free download · 368-page PDF

Fixed it? Get 500 NGINX & DevOps AI prompts — free

500 battle-tested, copy-paste AI prompts engineered by a senior systems engineer — every one with fill-in placeholders and safety/back-out notes. Drop your email and it's yours.

  • 500 prompts: Linux · Kubernetes · Terraform · OpenStack · GitLab · Docker · Monitoring · Incident Response
  • Instant PDF download — yours free, forever
  • Plus one practical AI-workflow email a week (no spam)

Single opt-in · unsubscribe anytime · no spam.

Did this fix your issue?

Free download · 368-page PDF

Get 500 Battle-Tested DevOps AI Prompts — Free

500 battle-tested, copy-paste AI prompts engineered by a senior systems engineer — every one with fill-in placeholders and safety/back-out notes. Drop your email and it's yours.

  • 500 prompts: Linux · Kubernetes · Terraform · OpenStack · GitLab · Docker · Monitoring · Incident Response
  • Instant PDF download — yours free, forever
  • Plus one practical AI-workflow email a week (no spam)

Single opt-in · unsubscribe anytime · no spam.