Skip to content
Foxipa

Suggest an edit

Tell us what should be corrected, clarified, or improved. Submission will be connected to Foxipa’s contribution service later.

No information is sent anywhere yet. Your suggestion is only prepared in your browser.

Learning

3.1 root vs alias: The Filesystem Mapping, Settled

Two directives, one job: turn a URI into a file path. One appends, one replaces — and every confusion you've ever had reduces to that difference plus a trailing slash.

Levels: Beginner ~35 min read

Basic

What you will learn

  1. The one-line rule separating root from alias.

  2. root in depth: inheritance, nesting, and the path-construction formula.

  3. alias in depth: the trailing-slash law and the regex-capture law.

  4. The five classic failures — each reproduced and fixed below.

  5. When neither is the answer ( internal, X-Accel-Redirect preview).


1. The one-line rule

root: final path = <root value> + <entire URI> alias: final path = <alias value> + <URI minus the location prefix>

root says "this directory is the root of the URL space" — the URI, slashes and all, gets glued to the end. alias says "this location is a nickname for that directory" — the matched prefix is cut off and replaced.

Both live in http/ server/ location; alias additionally has a regex-powered form that root lacks. Here is the matrix, live — four URIs, four mappings, all green in the output:

bash
$ for u in /about.html /images/hero.png /downloads/handbook.pdf /dl/handbook.pdf; do
    printf '%-28s %s\n' "$u" "$(curl -s -o /dev/null -w '%{http_code} %{content_type}' \
      -H 'Host: static.example.test' http://127.0.0.1:8300$u)"
  done
/about.html              200 text/html; charset=utf-8
/images/hero.png         200 image/png
/downloads/handbook.pdf  200 application/pdf
/dl/handbook.pdf         200 application/pdf

2. root in depth

Our example server sets root www/main; once at server level, and — via Lesson 2.5's inheritance — most locations borrow it:

nginx
server {
    root  www/main;          # prefix-relative: <prefix>/www/main
    location / { }                       # GET /about.html
    location /images/ { }                # GET /images/hero.png
}

Path construction, mechanically:

text
GET /images/hero.png
URI:      /images/hero.png
root:     …//var/www/main          (symlink -> /var/www)
final:    …/www/main + /images/hero.png  =  …/www/main/images/hero.png  ✓

Properties that make root the default choice:

  • It inherits. Server-level root + silent locations = one mapping for the whole vhost — the flat, obvious arrangement.

  • It's location-order-proof. The full URI survives into the path, so "which prefix matched" doesn't change where files come from; only which other directives apply.

  • Nested locations keep it. A nested block without its own root borrows the outer's — the ladder rule again.

3. alias in depth

The trailing-slash law

nginx
location /downloads/ {          # location prefix ENDS with /
    alias www/main/docs/;       # alias value MUST end with / too
}

Because the final path is alias + (URI − prefix), the slash alignment is mechanical: strip /downloads/ from the URI, glue the rest onto www/main/docs/.

text
GET /downloads/handbook.pdf
URI − prefix:   handbook.pdf
alias:          …/www/main/docs/
final:          …/www/main/docs/handbook.pdf ✓

Miss the slash on either side and you concatenate into a wall: …/docs + handbook.pdf = …/docshandbook.pdf → 404. The matrix above verifies both real files through this mapping (plus a Content-Disposition: attachment header, because a downloads/ location that displays PDFs betrays its own name — Lesson 3.3 covers the header).

The regex-capture law

alias + regex location is where senior engineers sweat. The rule: with a regex location, alias must contain the captures, because there is no fixed prefix to strip. Our working version:

nginx
location ~ ^/dl/(?<file>.+)$ {
    alias www/main/docs/$file;
}
text
GET /dl/handbook.pdf
capture:        handbook.pdf
alias:          …/www/main/docs/ + $file
final:          …/www/main/docs/handbook.pdf ✓   (200, application/pdf)

Omit $file and NGINX silently serves the directory — usually a 404 or, with autoindex inherited, an accidental listing. Two hard-won habits:

  1. Always name the capture ( ?<file> not $1) — regexes get edited, and $1 renumbering is a silent data-loss bug.

  2. Anchor the regex ( ^/dl/) — an unanchored ~ /dl/ would also swallow /old/dl/x and reshape that mapping too.

4. The five classic failures (and their one-glance diagnoses)

Failure 1 — the doubled path segment. location /images/ { root www/main/images/; } → /images/hero.png looks for …/images/images/hero.png. Diagnosis: root appends; you already had /images in the URI. Fix: root www/main; (or use alias).

Failure 2 — the eaten path segment. location /downloads/ { alias www/main/docs; } (no trailing slash) → …/docshandbook.pdf. Diagnosis: read the 404 path; the missing separator is visible. Fix: slash on both sides.

Failure 3 — alias inside a regex location without captures. Covered above: silent directory serves. Fix: $file-style capture.

Failure 4 — root at http level, surprise at server level. http { root /srv/default; } server { server_name b…; } — b serves from /srv/default (inherited) while the author "configured nothing". It's not a bug, it's the ladder (Lesson 2.5) — but it's the classic "works on A, 404s on B" fleet mystery. Fix: explicit root per server, or accept the default consciously.

Failure 5 — symlinked roots and disable_symlinks . By default NGINX happily follows symlinks (our example's www is one!). When a hardened config sets disable_symlinks on; (or if_not_owner), all symlinked roots — including $document_root tricks — start 403ing. Diagnosis: sudden, uniform 403s after a security pass. Fix: real paths or documented exceptions ( disable_symlinks off; where required).

5. When neither is the answer

Two advanced neighbors you'll meet later (previews, not homework):

  • internal — a location that only internal redirects may reach (Module 11): the protected-file pattern pairs internal with X-Accel-Redirect from an app.

  • Variables in root / alias — root /srv/$site; per-tenant mapping. Legal and fast (the value is computed per request), but it converts your filesystem into an API: validate $site (map/regex) before it ever touches a path. Lesson 15.1's njs work shows a safe shape.

Try it yourself

  1. Reproduce the mapping matrix (§1) and then predict before curling: /docs/payload.bin (root-mapped), /downloads/payload.bin (alias-mapped) — same file, two doors. Which returns the Content-Disposition header? Why?

  2. Watch the path-resolver work. Request /images/absent.png and read the resolved path from the error log:

bash
   tail -1 /var/log/nginx/error.log
  1. Build failure #1 live. Change the images location to root www/main/images/;, reload, request /images/hero.png, read the doubled path in the 404. Restore.

  2. Regex-alias surgery. Add location ~ ^/repo/(?<pkg>.+)$ { alias www/main/docs/$pkg; }, reload, fetch /repo/handbook.pdf. Then remove $pkg and fetch again — observe the silent wrongness.

Q&A

Q1. location /static/ { root /srv/web; } — where does /static/js/app.js resolve?

Answer

/srv/web/static/js/app.js. The full URI (including /static/) is appended to the root value.

Q2. Same URI under location /static/ { alias /srv/web/; }?

Answer

/srv/web/js/app.js. The /static/ prefix is stripped and replaced by the alias.

Q3. Why must a regex location's alias use captures?

Answer

alias normally works by subtracting the location prefix — but a regex has no fixed character prefix to subtract. Without captures there's nothing to append, so the alias value is used as-is (a directory) or misroutes. The capture is how you carry the variable part of the URI into the path.

Q4. Your 404 error log shows …/www/main/downloads/handbook.pdf for a request to /downloads/handbook.pdf in an alias location. What's wrong?

Answer

Nothing is wrong with the path shape — that's exactly where alias put it. The file is genuinely missing there (or permissions). The lesson: read the resolved path first, decide "mapping bug or missing file" second — this log line says the latter.

Takeaways

  • root appends the whole URI; alias replaces the matched prefix — everything else is consequences.

  • Prefer root (it inherits and is order-proof); reach for alias when the URL space and disk layout genuinely disagree.

  • The trailing-slash law (both sides) and the regex-capture law (alias in regex locations must carry captures) prevent the classic failures.

  • The 404's resolved path in error.log is free forensics — the fastest root/alias debugging tool you own.

  • disable_symlinks hardening interacts with symlinked roots; our example setup runs on one, which is exactly why it's on this page.

Was this page helpful?

Mark this learning resource complete to track your learning progress.