keepcalculator

06 Numbers and Powers

Fix Django Gunicorn Permission Denied Errors

Card No. 06·15418 · Updated · Standard formula, shown below

Permission denied errors when running Django with Gunicorn usually stem from file ownership, socket permissions, or user/group mismatches. This guide walks through diagnosing and fixing the most common causes so your app runs smoothly.

What You’ll Need

  • Access to the server (SSH or terminal)
  • sudo privileges (for chown, chmod, systemctl commands)
  • Basic familiarity with your Django project structure
  • Gunicorn already installed (if not, install it with pip)

Step-by-Step

  1. Identify the exact error message. Run Gunicorn in the foreground (e.g., gunicorn myproject.wsgi) and note the full error. Look for phrases like “Permission denied”, “[Errno 13]”, or “Can’t connect to …”. The error will tell you which file or socket is causing the problem.
  2. Check file ownership. Use ls -l on your project directory and on the socket file (if you use one). The user that runs Gunicorn must have read (and often write) access to the project files. If not, change ownership:
    sudo chown -R www-data:www-data /path/to/your/project

    Replace www-data with the user you run Gunicorn as (e.g., ubuntu, deploy).

  3. Verify directory permissions. Ensure the project directory is traversable (execute permission) for the Gunicorn user. Set reasonable permissions:
    sudo chmod -R 755 /path/to/your/project

    For directories where Django needs to write (like media or static), use chmod -R 775 or chmod -R 770 depending on your group setup.

  4. Check the socket file and its directory. If you’re using a Unix socket (e.g., in a systemd service file), the directory containing the socket must be writable by the Gunicorn user. Common locations: /run/gunicorn/ or /tmp/. Create the directory and set ownership:
    sudo mkdir -p /run/gunicorn
    sudo chown www-data:www-data /run/gunicorn
    sudo chmod 775 /run/gunicorn

    Also ensure the socket file itself (if it already exists) is owned by the Gunicorn user.

  5. Review your Gunicorn service file. If using systemd, open the service file (e.g., /etc/systemd/system/gunicorn.service) and check the User=, Group=, and WorkingDirectory= directives. They must match the ownership you set. Example:
    [Service]
    User=www-data
    Group=www-data
    WorkingDirectory=/path/to/your/project
    ExecStart=/path/to/venv/bin/gunicorn --workers 3 --bind unix:/run/gunicorn/myproject.sock myproject.wsgi:application

    After editing, run sudo systemctl daemon-reload and restart Gunicorn.

  6. Check SELinux or AppArmor. On some distributions, security modules block Gunicorn from accessing certain paths. Temporarily disable SELinux to test: sudo setenforce 0. If it works, you’ll need to adjust SELinux policies or set the correct context. For AppArmor, check if Gunicorn is confined and adjust accordingly.
  7. Test with a simple static file. Create a temporary file in your project root (e.g., touch test.txt) and try to read it with the Gunicorn user: sudo -u www-data cat test.txt. If that fails, the issue is with directory permissions, not Gunicorn itself.
  8. Check for read-only file systems. If your project is on a read-only mount (like some container setups), you’ll see permission errors even with correct ownership. Check with mount | grep /path and remount with write access if needed.
  9. Verify Python environment access. Ensure the Gunicorn user can read the virtual environment. Run sudo -u www-data /path/to/venv/bin/python -c "import django; print(django.get_version())" to confirm.
  10. Restart everything. After making changes, restart Gunicorn and your web server (Nginx/Apache) to apply the changes: sudo systemctl restart gunicorn and sudo systemctl restart nginx.

Common Mistakes

  • Running Gunicorn as root but the socket is owned by another user.
  • Forgetting to set execute permission on parent directories (e.g., /home/user/project – if /home/user is 700, others can’t traverse).
  • Using a socket path in a directory that doesn’t exist.
  • Mixing up the user in the systemd service file with the one that owns the files.
  • Ignoring SELinux – it can cause mysterious permission denials even when file permissions look correct.

Tips

  • Use a dedicated system user for Gunicorn (e.g., www-data or gunicorn) to minimize security risks.
  • Keep static and media files in a separate directory with appropriate permissions, and let Nginx serve them directly.
  • Use --bind 127.0.0.1:8000 for testing to avoid socket issues during development.
  • Document your file ownership and permission scheme in your project README.
  • Use sudo -u <user> -i to simulate the Gunicorn user’s environment and test commands.

Troubleshooting

If the error persists after following the steps:

  • Check logs. Look at Gunicorn’s error log (often in /var/log/gunicorn/) and the web server’s error log. The exact line number and file path will guide you.
  • Run Gunicorn in the foreground as the target user. Use sudo -u www-data /path/to/venv/bin/gunicorn --bind 127.0.0.1:8000 myproject.wsgi to see the error directly.
  • Use strace to trace system calls. If you have root access, run strace -f -e trace=file -p <gunicorn_pid> to see exactly which file is denied.
  • Check if the socket is already in use. If the socket file exists but is stale, remove it: sudo rm /run/gunicorn/myproject.sock and restart.
  • Verify Nginx proxy_pass. If Nginx is proxying to Gunicorn, ensure the proxy_pass URL matches the socket or port Gunicorn is bound to.

Frequently Asked Questions

Why does Gunicorn get permission denied even though I set chmod 777?

chmod 777 gives read/write/execute to everyone, but if the parent directory lacks execute permission, the user still can’t traverse to the file. Also, SELinux can override file permissions.

Should I run Gunicorn as root?

No. Running as root is a security risk. Use a dedicated user with minimal privileges.

How do I fix permission denied when binding to a port below 1024?

Ports below 1024 require root privileges. Use a port above 1024 (e.g., 8000) and let Nginx or Apache handle the low port.

What if my project is in a directory owned by another user?

You can either change ownership with chown or add the Gunicorn user to the group that owns the directory and set group permissions.

Can I use a TCP socket instead of a Unix socket to avoid permission issues?

Yes, binding to 127.0.0.1:8000 avoids file permission issues, but you must ensure the port is not blocked by a firewall.

Why does Gunicorn work in development but fail in production?

Often the production environment uses a different user, stricter SELinux, or a systemd service that doesn’t set the correct working directory.

Related

Method: the standard formula for this calculation, rounded as each result states. See how the calculators work or report an error.

More cards in this drawer

The whole Numbers and Powers drawer →