How to Configure Nginx to Use Different Index Files for Subdirectories


2 views

When working with Nginx configurations, a common requirement is to specify different index files for different directory levels. In this case, we need:

  • /index.html as the default index file for the root directory
  • /foo/bar.html as the index file for the /foo subdirectory

The initial configuration has several issues:

location /foo {
  root  /usr/share/nginx/mysite/public/foo;
  index  bar.html;
}

The main problems are:

  1. The root directive is incorrectly specified with the full path
  2. Missing proper handling of trailing slashes and URI variations
  3. Potential conflicts with other location blocks

Here's the proper way to implement this:

server {
  listen 80;
  server_name domain.tld;
  
  # Root location
  location / {
    root /usr/share/nginx/mysite/public;
    index index.html;
    
    # HTTPS redirect (if needed)
    if ($http_x_forwarded_proto != 'https') {
      return 301 https://$host$request_uri;
    }
  }

  # Subdirectory location with custom index
  location ^~ /foo {
    root /usr/share/nginx/mysite/public;
    index bar.html;
    
    # Handle both /foo and /foo/ requests
    rewrite ^/foo/?$ /foo/bar.html last;
    
    # Handle requests with any path after /foo/
    try_files $uri $uri/ /foo/bar.html;
  }

  # Static assets caching
  location ~* \.(ico|css|js|gif|jpe?g|png)(\?[0-9]+)?$ {
    root /usr/share/nginx/mysite/public;
    expires 30d;
    add_header Cache-Control "public";
  }
}
  • Use ^~ prefix for location to prioritize this block over regex matches
  • Keep the root directive consistent with parent location
  • Use try_files for flexible URI handling
  • The rewrite rule ensures both /foo and /foo/ work

After making changes:

sudo nginx -t
sudo systemctl reload nginx

For more complex scenarios, consider using alias:

location /foo {
  alias /usr/share/nginx/mysite/public/foo;
  index bar.html;
  try_files $uri $uri/ /foo/bar.html;
}

When working with Nginx configurations, a common requirement is to specify different index files for root and subdirectories. The default behavior of using index.html everywhere might not suit all project structures.

Consider this typical scenario:

server {
  root /var/www/html;
  index index.html; # Default for all locations
}

This forces all directories to use index.html, which doesn't work when you need:

  • /index.html for root
  • /foo/bar.html for a subdirectory

The correct approach uses separate location blocks with proper root directives:

server {
  listen 80;
  server_name example.com;

  # Root location
  location / {
    root /usr/share/nginx/mysite/public;
    index index.html;
  }

  # Subdirectory location
  location /foo {
    root /usr/share/nginx/mysite/public;
    index bar.html;
  }
}

1. The root directive in the subdirectory location should point to the parent directory, not the subdirectory itself.

2. Nginx automatically appends the URI to the root path when searching for files.

Problem: Requests to /foo don't serve bar.html as expected.

Solution: Ensure the location block matches all variations:

location ~ ^/foo(/|$|/.*) {
  root /usr/share/nginx/mysite/public;
  index bar.html;
  try_files $uri $uri/ /foo/bar.html;
}

For complete URL handling, add this rewrite rule:

rewrite ^/foo$ /foo/ permanent;

Here's a complete production-ready configuration:

server {
  listen 80;
  server_name domain.tld;

  location / {
    root /usr/share/nginx/mysite/public;
    index index.html;
    add_header Cache-Control "public max-age=600";
  }

  location /foo {
    root /usr/share/nginx/mysite/public;
    index bar.html;
    try_files $uri $uri/ /foo/bar.html;
    add_header Cache-Control "public max-age=3600";
  }

  # Static assets
  location ~* \.(ico|css|js|gif|jpe?g|png)(\?[0-9]+)?$ {
    expires 30d;
    add_header Cache-Control "public";
  }
}

Always validate your Nginx config before applying changes:

nginx -t

Then reload the configuration:

nginx -s reload