How to Fix Nginx 404 for Static Files (CSS, JS, Images)
In this tutorial, you'll learn about How to Fix Nginx 404 for Static Files (CSS, JS, Images). We cover key concepts, practical examples, and best practices.
The Problem
Your web application's HTML loads, but CSS, JavaScript, and image files return 404 errors. The browser console shows:
GET http://example.com/css/style.css 404 (Not Found)
GET http://example.com/js/app.js 404 (Not Found)
Nginx isn't serving static files because the root or alias directive points to the wrong directory, or file permissions prevent Nginx from reading them. The error is usually in the Nginx configuration or file system permissions, not in your application code.
Quick Fix
1. Check Nginx error logs
sudo tail -f /var/log/nginx/error.log
Expected output:
2025/06/23 10:30:00 [error] 1234#1234: *42 open() "/var/www/html/css/style.css" failed (2: No such file or directory)
The log reveals the exact path Nginx is trying to read. Compare this path to where your files actually are.
2. Fix the root directive
server {
listen 80;
server_name example.com;
root /var/www/myapp/public;
index index.html;
location / {
try_files $uri $uri/ /index.html;
}
}
The root directive sets the base directory for all locations. Nginx appends the URI to the root path. For a request to /css/style.css, Nginx looks for /var/www/myapp/public/css/style.css.
3. Use alias for different root directories
server {
root /var/www/myapp/public;
# Static files in a different directory
location /static/ {
alias /var/www/myapp/static-files/;
}
}
alias replaces the matched location prefix with a different path. /static/style.css maps to /var/www/myapp/static-files/style.css. Unlike root, alias does NOT append the location prefix to the path.
4. Set correct file permissions
# Nginx runs as www-data user; files must be readable by it
sudo chown -R www-data:www-data /var/www/myapp
sudo find /var/www/myapp -type f -exec chmod 644 {} \;
sudo find /var/www/myapp -type d -exec chmod 755 {} \;
Nginx's worker processes run as www-data (or nginx on some distributions). If files are owned by root with restrictive permissions, Nginx can't read them.
5. Add proper MIME types
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
server {
...
}
}
Without include /etc/nginx/mime.types, Nginx serves CSS files as text/plain and JS files as application/octet-stream, causing the browser to reject them even if the file is found.
6. Test configuration and reload
sudo nginx -t
sudo systemctl reload nginx
Expected output:
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
7. Verify the file exists at the expected path
ls -la /var/www/myapp/public/css/style.css
Expected output:
-rw-r--r-- 1 www-data www-data 12345 Jun 23 10:30 /var/www/myapp/public/css/style.css
6. Use try_files with named locations
location /assets/ {
try_files $uri $uri/ /assets/index.html =404;
}
location /images/ {
alias /var/www/myapp/uploads/;
try_files $uri =404;
}
Use try_files $uri =404 to explicitly return 404 when a file doesn't exist, preventing Nginx from falling back to other locations that might serve the wrong content.
Prevention
- Use
rootfor the main document root,aliasfor off-root directories - Always check
sudo nginx -tbefore reloading - Set correct permissions (644 for files, 755 for directories) during deployment
- Include
mime.typesin thehttpblock to serve correct content types - Use
try_files $uri $uri/ /index.htmlfor single-page applications - Add
access_loganderror_logdirectives per location for easier debugging
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro