When deploying Django with Nginx, we often encounter a strange situation where regular static files work perfectly, but admin static files mysteriously fail to load. Here's what I observed in my deployment:
# Working fine
http://example.com/static/css/base.css
# Returns 404
http://example.com/static/admin/css/base.css
The core issue stems from how Nginx handles the location
directive for admin static files. The Django admin static files typically reside in:
/path/to/virtualenv/lib/pythonX.X/site-packages/django/contrib/admin/static/admin/
But here's the catch - any directory containing "admin" in its name seems to trigger this behavior, suggesting Nginx has special handling for paths containing "admin".
Solution 1: Proper alias configuration
Modify your Nginx configuration to explicitly handle admin static files:
location /static/admin/ {
alias /path/to/your/virtualenv/lib/pythonX.X/site-packages/django/contrib/admin/static/admin/;
autoindex off;
}
location /static/ {
alias /path/to/your/staticfiles/;
autoindex off;
}
Solution 2: Symbolic link workaround
If the above doesn't work, create a symbolic link:
ln -s /path/to/django/contrib/admin/static/admin /path/to/your/staticfiles/admin
Then run collectstatic
again.
Always verify permissions for both the static directory and Nginx process:
chmod -R 755 /path/to/your/staticfiles
chown -R www-data:www-data /path/to/your/staticfiles
After making changes, always:
nginx -t # Test configuration
systemctl restart nginx # Reload server
If you're using Docker, you might need to adjust your setup:
# docker-compose.yml snippet
volumes:
- ./staticfiles:/app/staticfiles
- /path/to/django/contrib/admin/static/admin:/app/staticfiles/admin
Check Nginx error logs for detailed information:
tail -f /var/log/nginx/error.log
Verify file accessibility by testing with curl:
curl -I http://localhost/static/admin/css/base.css
When deploying Django with Nginx, one peculiar issue that frequently trips up developers is the failure to serve admin static files while other static files work perfectly. The symptom manifests when:
# These work fine
http://example.com/static/css/app.css
http://example.com/static/js/main.js
# But admin assets return 404
http://example.com/static/admin/css/base.css
The root cause typically stems from Nginx's path resolution conflicting with Django's admin media handling. Here's what's happening under the hood:
- The
collectstatic
command properly gathers admin files toSTATIC_ROOT/admin/
- Django's development server serves them correctly
- Nginx mysteriously blocks requests to paths containing "admin"
The most common problematic configuration looks like this:
location /static/ {
alias /path/to/static_root/;
expires max;
add_header Cache-Control public;
}
While this works for regular static files, it fails for admin assets due to path traversal security measures in Nginx.
Here's the corrected Nginx configuration that works reliably:
# Regular static files
location /static/ {
alias /path/to/static_root/;
expires max;
add_header Cache-Control public;
}
# Explicit admin static files - note the trailing slash!
location /static/admin/ {
alias /path/to/python/site-packages/django/contrib/admin/static/admin/;
}
Key technical points:
- The
location
block must end with a slash - The
alias
must point to the original admin static files in your Python environment - Order matters - more specific paths should come before generic ones
For more flexible setups, consider this pattern:
location /static/ {
root /path/to/static_root;
try_files $uri $uri/ @django_admin_static;
}
location @django_admin_static {
root /path/to/python/site-packages/django/contrib/admin;
try_files /static$uri =404;
}
After making changes, always:
- Test with
nginx -t
for configuration validity - Reload Nginx:
systemctl reload nginx
- Clear browser cache and test with direct URL access
Check file permissions on both locations:
ls -la /path/to/static_root/admin/
ls -la /path/to/python/site-packages/django/contrib/admin/static/admin/
If the issue persists, consider these nuclear options:
# Option 1: Symbolic link workaround
ln -s /path/to/python/site-packages/django/contrib/admin/static/admin \
/path/to/static_root/admin_assets
# Then use this in settings.py
STATICFILES_DIRS = [
('admin_assets', '/path/to/static_root/admin_assets'),
]
Remember that the Django admin interface is mission-critical for many applications, so getting this configuration right is worth the effort.