How to Serve a Single File in Nginx Without Changing the URL Path for SPA Routing


2 views

When building a single-page application (SPA), you often need Nginx to serve static assets directly while routing all other requests to your index.html file without modifying the URL. This is crucial for client-side routing to work properly.

Here's how to configure Nginx to handle this scenario:

server {
    listen 80;
    server_name example.com;

    # Serve static files directly
    location /static/ {
        alias /path/to/your/static/files/;
        try_files $uri =404;
    }

    # All other requests serve index.html without redirect
    location / {
        root /path/to/your/spa;
        try_files $uri /index.html;
    }
}

The configuration uses several important Nginx directives:

  • alias: Maps requests to the exact file system path for static assets
  • try_files: Attempts to serve the requested file, falling back to index.html
  • root: Sets the base directory for the SPA files

After making changes, always test your Nginx configuration:

sudo nginx -t
sudo systemctl reload nginx

For SPAs using HTML5 history mode (like Vue Router or React Router), this setup ensures:

# All these will serve index.html while preserving the URL:
example.com/about
example.com/user/123/profile
example.com/any/nested/path

For production environments, consider adding caching headers:

location /static/ {
    alias /path/to/your/static/files/;
    expires 1y;
    add_header Cache-Control "public";
    try_files $uri =404;
}

When building single-page applications (SPAs), we often need Nginx to serve static assets from specific directories while routing all other requests to a single HTML file (typically index.html) without altering the URL. This is crucial because:

  • SPAs use client-side routing (React Router, Vue Router, etc.)
  • Direct URL access should work without server redirection
  • Static assets need separate optimization (caching, compression)
server {
    listen 80;
    server_name yourdomain.com;

    # Static assets handling
    location /static/ {
        alias /path/to/your/static/files/;
        expires 1y;
        add_header Cache-Control "public";
        try_files $uri =404;
    }

    # All other requests go to index.html while preserving URL
    location / {
        root /path/to/your/app;
        try_files $uri /index.html;
    }
}

The magic happens with try_files:

try_files $uri /index.html;

This attempts to serve the requested file first, then falls back to index.html while maintaining the original URL in the browser.

Handling API Proxying

location /api/ {
    proxy_pass http://backend-api;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
}

Gzip Compression for Static Files

location /static/ {
    gzip on;
    gzip_types text/plain text/css application/json application/javascript;
    # ... rest of static config
}
  • Trailing slashes matter: "/static" vs "/static/" behave differently
  • Root vs alias: Use alias when the URI doesn't match the filesystem path
  • Caching headers: Set different Cache-Control for assets vs HTML

Always validate your config before applying:

nginx -t

And reload after changes:

nginx -s reload