DriversRecommendedOutdated drivers can make a good PC feel brokenScan driver issues before chasing fixes manually.Scan NowHalloween DealsAmazon USHalloween week deals: useful picks before month-endAmazon US: current deals, useful picks and tech finds.Check DealsWindows FixRecommendedWindows errors stealing your time? Find the fix fastScan stability, cleanup and performance issues.Fix Now×
Skip to content
World desk8 min

Fixing Static Content on an Nginx Reverse Proxy Subdirectory

A practical guide to serving static files correctly under an NGINX /app/ subdirectory, with working proxy, alias, root, SPA fallback, and troubleshooting configurations.
Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Static files fail behind an NGINX subdirectory when the browser URL, NGINX’s filesystem mapping, and the upstream application disagree about the path. The fix is to decide where each asset is served, map /app/ deliberately, and prevent missing assets from falling into an application fallback. The critical distinction is simple: a proxy_pass URL with a URI replaces the matching location prefix; one without a URI generally preserves the request path.

Why assets break under /app/

A page loaded at https://example.com/app/ may request /app/css/site.css, /css/site.css, or even /static/app.css. Those are different URLs. NGINX then has to do one of two things with each request: construct a local filesystem path, or construct a new request for an upstream server. A deployment works only when both transformations match the actual directory tree and the application’s expectations.

As an Amazon Associate I earn from qualifying purchases.

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

There are therefore two independent questions:

  • What path did the browser request? Copy the complete URL, including the /app/ prefix, before changing configuration.
  • What path does NGINX use next? For local files it is derived from root or alias; for proxied files it is derived from the proxy_pass form.

For example, with location /app/ { proxy_pass http://backend/; }, a request for /app/css/site.css is sent upstream as /css/site.css. With proxy_pass http://backend;, the request path is generally preserved as /app/css/site.css. The trailing slash is not cosmetic.

Choose where static files are served

Make this decision before editing directives. It determines the correct location block and the path the application must generate.

Design Where files live Expected upstream path Best fit
Local static directory On the NGINX host, such as /srv/app/static/ None for those files Stable assets that should not consume application workers
Upstream serves static files Inside the application server or its container /css/... and /js/... when the public prefix is stripped The application already owns its asset pipeline
SPA entry plus proxy fallback Built files on NGINX, application handles other routes Only requests that fail local checks Single-page applications with client-side routing

Also check whether generated HTML uses prefix-aware URLs. A root-relative URL such as /static/app.css starts at the domain root and bypasses /app/. The application may need an external base URL or a build-time public path that includes /app/.

How NGINX constructs local paths

root appends the complete URI

With:

location /app/ {
    root /var/www/html;
}

a request for /app/css/site.css makes NGINX look for /var/www/html/app/css/site.css. This is correct only when the on-disk tree really contains an app/ directory beneath /var/www/html. If the file is actually /var/www/html/css/site.css, the public prefix has been duplicated in the filesystem lookup.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

alias maps the location directly

Use alias when the URL prefix should point directly at another directory. A location of /app/static/ with alias /srv/app/static/; maps /app/static/site.css to /srv/app/static/site.css, rather than appending the whole URI. Match the slash form: a location ending in / should use an alias directory ending in /.

try_files is the existence gate

try_files checks candidate files or directories using the active root or alias. It processes arguments in order; the final argument can be an internal redirect target or a status such as =404. For assets, an explicit =404 is important because it stops a missing stylesheet or script from being replaced with an HTML page.

Pattern 1: serve a local static directory and proxy the application

Separate the asset prefix from the broader application prefix. NGINX selects the more specific /app/static/ location for those requests, so they never reach the proxy block.

location ^~ /app/static/ {
    alias /srv/app/static/;
    try_files $uri =404;
}

location /app/ {
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_pass http://app_backend/;
}

The two trailing slashes have distinct jobs. The slash in proxy_pass http://app_backend/; tells NGINX to replace the matching /app/ location prefix, so /app/dashboard reaches the upstream as /dashboard. The slash on the alias directory makes the /app/static/ URL map cleanly into /srv/app/static/. Confirm that the files really exist there and that the NGINX worker can read them.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

^~ gives the static prefix priority over regular-expression locations. Keeping the static block more specific than location /app/ avoids accidentally proxying assets. If your configuration has other exact or regex locations, inspect those as well; location selection can change the result.

Pattern 2: let the upstream application serve assets

If the upstream already serves /css/, /js/, and image paths, proxy those requests instead of creating a second static tree:

location /app/ {
    proxy_set_header Host $host;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_pass http://app_backend/;
}

This form strips the public prefix. The application must therefore expect /css/site.css, not /app/css/site.css. If the upstream is configured with the latter as its base path, omit the URI from proxy_pass:

location /app/ {
    proxy_set_header Host $host;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_pass http://app_backend;
}

Without a URI parameter, NGINX generally passes the original request path, including /app/. Another valid solution is to keep the slash form and configure the application’s external base path so it serves and generates URLs consistently. Do not mix the two assumptions: an upstream expecting /app/ will commonly return 404 when it receives /css/, while an upstream expecting the stripped path will commonly 404 when it receives /app/css/.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Pattern 3: SPA files with a safe application fallback

A single-page application often needs local files for the shell and a fallback for client-side routes. Check assets before invoking the fallback:

location /app/ {
    root /srv/app/dist;
    try_files $uri $uri/ @app;
}

location @app {
    proxy_pass http://app_backend;
}

Here, try_files tests the requested path and directory first. A request for an existing JavaScript bundle is served locally; an application route that is not a local file is sent to the named location. For known asset prefixes, a stricter block is safer:

location ^~ /app/assets/ {
    alias /srv/app/dist/assets/;
    try_files $uri =404;
}

location /app/ {
    root /srv/app/dist;
    try_files $uri $uri/ @app;
}

location @app {
    proxy_pass http://app_backend;
}

Without this separation, a missing .css or .js file can receive index.html. The browser then reports a misleading MIME-type or JavaScript parse error instead of the useful fact that the asset path is wrong.

Diagnose one failing URL from browser to disk or upstream

  1. Capture the exact request. Open browser developer tools, reload the page, and copy one failing asset URL. Record its status and response content type. Include the subdirectory prefix; /app/css/site.css and /css/site.css are different tests.
  2. Determine the winning location. Review exact, prefix, regex, and named locations. A broad location /app/ may not win, and regex locations can affect whether NGINX can determine a proxy URI replacement. If a regex location is involved, avoid relying on a URI parameter in proxy_pass; the official behavior is indeterminate for some such combinations.
  3. Compute a local filesystem path. For root, append the request URI to the root directory. For alias, replace the matching location prefix with the alias directory. Check for a duplicated /app/ or an omitted directory, then verify permissions and spelling.
  4. Compute the upstream path. If proxy_pass includes a URI, NGINX replaces the matching location portion with that URI. If it has no URI, compare the original request path with what the application expects. Check whether a trailing slash changed the result.
  5. Read both sets of logs. NGINX access and error logs show whether the failure occurred during local lookup or proxying. An NGINX-generated 404 points toward filesystem mapping or a restrictive try_files; an upstream 404 points toward the forwarded path or application base-path handling. Then inspect the upstream log for the exact route it received.
  6. Inspect generated URLs. View the HTML source and CSS references. Root-relative links beginning with / bypass /app/. Relative links, absolute links generated by the server, and JavaScript build paths can each produce a different public URL.
  7. Validate and reload safely. Run nginx -t. Only after a successful syntax check reload NGINX, then retest the application entry page and one asset. A command-line check such as curl -I https://example.com/app/static/site.css confirms the status and headers without relying on browser caching.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Common failure modes and precise fixes

The prefix is duplicated on disk

root /var/www/html; under location /app/ searches for /var/www/html/app/.... If deployment files are under /var/www/html/..., use an appropriate alias, move the files into an app/ directory, or change the root layout. Do not “fix” this by adding another rewrite until the intended mapping is explicit.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

An unexpected prefix appears upstream

proxy_pass http://backend/app/; replaces the matching location with /app/. Depending on the location and original URI, this can add or retain a prefix the application does not serve. Use the exact URI the upstream expects, or omit the URI to preserve the request path.

A regex location makes rewriting unpredictable

In regex and some named locations, NGINX may not have a determinate matching prefix to replace. The safer configuration is a proxy_pass without a URI, followed by explicit application base-path configuration if needed.

HTML is returned for a missing asset

An SPA fallback that returns index.html for every unknown path masks missing files. Put a specific static location first and use try_files $uri =404 for asset prefixes. Confirm the response content type as well as the status.

The upstream redirects to the site root

An application may generate an absolute redirect to / instead of /app/. Forward Host and X-Forwarded-Proto, and configure the application’s external base path. Otherwise the first page may load while subsequent redirects and asset URLs escape the subdirectory.

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Configuration checklist before you declare it fixed

  • The public prefix is settled: /app/ is used consistently in links, redirects, and documentation.
  • Each static URL has one owner: the NGINX host or the upstream application.
  • Every root lookup and alias substitution has been calculated for a real failing URL.
  • The proxy_pass trailing-slash choice matches the upstream’s expected path.
  • A specific static location precedes the broad application proxy where both are needed.
  • Asset misses return 404 instead of an SPA document.
  • Forwarded host and protocol headers are present when the upstream creates redirects or absolute URLs.
  • nginx -t succeeds, logs show the expected path, and a fresh request to the entry page plus one CSS or JavaScript file succeeds.

Which design should you use?

Keep files on NGINX when the directory is known, the assets are mostly immutable, and you want requests for them isolated from application failures. Let the upstream serve them when its framework, authentication, or asset pipeline already owns those paths. Use the SPA pattern when local build output and application routes share the same public prefix; the explicit asset check is what keeps a typo in a bundle URL from being hidden by a successful HTML response.

Whichever design you select, document the public prefix, the on-disk directory (if any), the exact upstream path, and whether the application emits prefix-aware URLs. That four-part contract prevents most future 404s when a build or deployment changes.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

Leave a Reply

Your email address will not be published. Required fields are marked *

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

More from the Wire

  1. World desk4 min
    How to Spot an AI Voice Scam Before Sending MoneyDon’t rely on how a caller sounds. Pause, call back through a known number, and verify the emergency with another trusted person before sending money.
  2. Mountain View desk4 min
    Google’s SynthID Detector: How to Check AI-Generated Images, Video and AudioGoogle’s SynthID Detector looks for an embedded watermark in supported images, video and audio. Here is what its results do—and do not—show.
  3. Redmond desk20 min
    How to create a link to File or Folder in Windows 11Windows 11 gives you several ways to point to a file or folder without moving or duplicating it. You can create a desktop shortcut,…
Recommended PC Tool
Recommended PC Tool
Windows Errors? Fix Them Before They SpreadFree repair scan
Outdated Drivers Are Slowing You DownFree scan - exact matches

Two free Windows tools

One Free Minute Could Fix That PC

Before you go - each of these free tools takes about a minute and tackles what quietly slows a Windows PC down.

Special offer. View Outbyte info, uninstall instructions, EULA, and Privacy Policy.