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 · · 9 min read Last reviewed Jul 2026

NGINX Error Guide: 'open() failed (2: No such file or directory)' — fix root, alias, and try_files

Quick answer

Fix NGINX 'open() failed (2: No such file or directory)' 404s: diagnose wrong root, alias trailing-slash mangling, broken try_files, SPA fallbacks, and index paths, then reload safely.

  • #nginx
  • #web-server
  • #troubleshooting
  • #errors
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.

Overview

NGINX logs this whenever a worker tries to open a static file at a computed path that does not exist on disk. It is the classic source of a 404 for a file you are certain is there — the file exists, but NGINX is looking somewhere else because root, alias, index, or try_files built the wrong path.

2026/07/08 14:22:07 [error] 8420#8420: *91233 open() "/var/www/app/staticassets/app.css" failed (2: No such file or directory), client: 203.0.113.44, server: app.example.com, request: "GET /static/assets/app.css HTTP/1.1", host: "app.example.com"

The key is the quoted path in the log: that is the exact filesystem path NGINX built from your config. Compare it to where the file actually lives, and the misconfiguration is usually obvious — a doubled segment, a missing slash, or a wrong root.

Symptoms

  • Browser gets a 404 Not Found for a file that clearly exists on disk.
  • error.log shows open() "..." failed (2: No such file or directory).
  • The logged path has a doubled or mangled segment (e.g. /static/assets becomes staticassets).
  • A single-page app deep link (e.g. /dashboard/settings) 404s on refresh, but works when navigating in-app.
  • Some paths serve fine while one location consistently 404s.
curl -sI https://app.example.com/static/assets/app.css | head -1
HTTP/1.1 404 Not Found
sudo tail -5 /var/log/nginx/error.log
[error] 8420#8420: *91233 open() "/var/www/app/staticassets/app.css" failed (2: No such file or directory)

Common Root Causes

1. alias missing a trailing slash (path mangling)

With location /static/ and alias /var/www/app/assets; (no trailing slash), NGINX concatenates the leftover URI onto the alias without a separator, producing a mangled path.

location /static/ {
    alias /var/www/app/assets;   # BUG: no trailing slash
}

Request GET /static/app.css becomes open() "/var/www/app/assetsapp.css". The rule: when location ends in /, the alias must end in / too.

2. Wrong or doubled root

root is appended with the entire request URI, so a root that already includes the URI prefix doubles it.

location /static/ {
    root /var/www/app/static;   # BUG: root gets the FULL uri appended
}

GET /static/app.css becomes open() "/var/www/app/static/static/app.css". For a prefix you want stripped, use alias; root is for serving the URI as-is under a base directory.

3. Actual wrong document root

The root points at a directory that does not contain the deployed files at all — a stale path after a deploy moved the release, or a typo.

root /var/www/html;   # but the build deployed to /var/www/app/current

Every static request 404s because the tree simply is not there.

4. Broken try_files / missing SPA fallback

A single-page app needs unmatched paths to fall back to index.html. Without it, a deep-link refresh looks for a real file that does not exist.

location / {
    try_files $uri $uri/ =404;   # deep links 404 on refresh
}

GET /dashboard/settings finds no /var/www/app/dashboard/settings file, so it returns 404 instead of serving the SPA shell.

5. Missing index file

A directory request resolves via index, but the named index file is not present, so NGINX tries to open a file that does not exist.

index index.html;
# but the build outputs index.htm or main.html

Diagnostic Workflow

Step 1: Read the exact path NGINX tried

sudo tail -20 /var/log/nginx/error.log

Copy the quoted path from open() "..." failed. This is ground truth — NGINX built this path from your config. Everything else is comparing it to reality.

Step 2: Check whether that exact path exists

ls -l /var/www/app/staticassets/app.css   # the path from the log
ls -l /var/www/app/static/assets/app.css   # where you think it is

If the logged path is mangled or doubled, you have a root/alias bug (causes 1 and 2). If the logged path is correct but missing, the file was not deployed there (cause 3).

Step 3: Find the matching location and its root/alias

grep -RnE 'root|alias|index|try_files' /etc/nginx/conf.d/ /etc/nginx/sites-enabled/

Identify the location serving the failing URI and confirm root vs alias is used correctly:

# Correct alias: trailing slashes on BOTH, leftover URI appended cleanly
location /static/ {
    alias /var/www/app/assets/;
}

# Correct root: full URI appended under the base
location / {
    root /var/www/app/public;
    try_files $uri $uri/ /index.html;   # SPA fallback
}

Step 4: Validate and reload

sudo nginx -t && sudo systemctl reload nginx
curl -sI https://app.example.com/static/app.css | head -1

Example Root Cause Analysis

After a front-end deploy, every asset under /static/ returns 404 while index.html serves fine.

The error log:

[error] 8420#8420: *91233 open() "/var/www/app/assetsapp.css" failed (2: No such file or directory), request: "GET /static/app.css HTTP/1.1"

The logged path is /var/www/app/assetsapp.cssassets and app.css are fused with no slash. That fingerprint points straight at an alias trailing-slash bug.

Checking the config:

grep -RnE 'location /static|alias' /etc/nginx/conf.d/app.conf
location /static/ {
    alias /var/www/app/assets;
}

The location ends in / but the alias does not, so NGINX appends app.css directly to .../assets. Fix by matching the trailing slash:

location /static/ {
    alias /var/www/app/assets/;
}
sudo nginx -t && sudo systemctl reload nginx
curl -sI https://app.example.com/static/app.css | head -1   # now 200

The assets serve correctly, and the logged open() path is now /var/www/app/assets/app.css.

Prevention Best Practices

  • When a location prefix ends in /, make the alias end in / too — mismatched trailing slashes are the number-one cause of mangled static paths.
  • Use alias when you want a prefix stripped and root when you want the full URI served under a base directory; do not reach for root to strip a prefix.
  • For single-page apps, always add a try_files $uri $uri/ /index.html; fallback so deep-link refreshes serve the shell instead of 404ing.
  • After every deploy, curl -sI one asset and the index as a smoke test so a moved release directory fails the deploy, not the users.
  • Trust the quoted path in open() ... failed — it is exactly what NGINX built; diff it against the real filesystem path before touching anything else.

Quick Command Reference

# The exact path NGINX tried to open
sudo tail -20 /var/log/nginx/error.log

# Compare logged path vs reality
ls -l <path-from-log>
ls -l <path-you-expect>

# Find the location's root/alias/try_files
grep -RnE 'root|alias|index|try_files' /etc/nginx/conf.d/ /etc/nginx/sites-enabled/

# Validate, reload, smoke test
sudo nginx -t && sudo systemctl reload nginx
curl -sI https://app.example.com/static/app.css | head -1

Conclusion

open() failed (2: No such file or directory) is NGINX telling you the precise filesystem path it looked for and did not find. The usual root causes:

  1. An alias missing its trailing slash, mangling the path.
  2. A root that doubles the URI prefix (use alias to strip it).
  3. A genuinely wrong document root after a deploy or typo.
  4. A missing try_files SPA fallback, 404ing deep-link refreshes.
  5. A missing or misnamed index file.

Read the quoted path from the log first, compare it to where the file actually lives, then fix root/alias/try_files accordingly and nginx -t before reloading. Nearly every case is a trailing-slash mismatch or a root vs alias mix-up.

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.