Skip to content

How to Fix Nginx 404 for Static Files (CSS, JS, Images)

DodaTech 2 min read

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 root for the main document root, alias for off-root directories
  • Always check sudo nginx -t before reloading
  • Set correct permissions (644 for files, 755 for directories) during deployment
  • Include mime.types in the http block to serve correct content types
  • Use try_files $uri $uri/ /index.html for single-page applications
  • Add access_log and error_log directives per location for easier debugging

Built by the developers of DodaTech

Doda Browser, DodaZIP & Durga Antivirus Pro