Nginx Location Priority Explained

Published June 30, 2024

This article examines Nginx location directives. It explains what location directives are, their syntax, and how they process requests for specific URIs. The article describes different types of location matches, including exact, prefix, and regular expression matches. It also discusses the priority order of these matches and gives practical examples of their use in various scenarios.

Key Takeaways

  • Nginx location directives define how to process requests for specific URIs
  • Location blocks use modifiers like =, ~, ~*, and ^~ to determine matching behavior
  • Nginx processes location blocks in order: exact match, preferential prefix, regex match, prefix match
  • Nested locations allow more specific rules within broader contexts
  • Rewrite rules can modify request URIs before processing, useful for URL changes and redirects

Nginx Location Directives 101

What is an Nginx Location Directive?

A location directive in Nginx is a configuration block that defines how the server should process requests for specific URIs. It sets rules for different URL patterns, determining how Nginx handles requests that match those patterns.

Location blocks in Nginx configuration:

  • Route requests to resources or applications
  • Apply settings based on the requested URI
  • Rewrite or redirect URLs
  • Control access to parts of your website
  • Optimize performance for different content types

Examples

  1. Serving static files:

    location /images/ {
       root /var/www/static;
    }

    This directive serves image files from the /var/www/static/images/ directory.

  2. Proxying requests to an application server:

    location /api/ {
       proxy_pass http://backend_server;
    }

    This directive forwards requests starting with /api/ to a backend application server.

  3. Redirecting old URLs:

    location /old-page {
       return 301 /new-page;
    }

    This directive redirects requests for /old-page to /new-page with a permanent (301) redirect.

  4. Denying access to sensitive files:

    location ~ /\.ht {
       deny all;
    }

    This directive blocks access to .htaccess and .htpasswd files.

Syntax of Nginx Location Blocks

The basic structure of a location block is:

location [modifier] pattern {
    # Directives specific to this location
}

The pattern is a string that matches against the request URI. The optional modifier changes how Nginx interprets the pattern.

Modifiers and Their Functions

Modifier Description Example
(none) Prefix match (default) location /docs/ { ... }
= Exact match location = /favicon.ico { ... }
~ Case-sensitive regex match location ~ \.php$ { ... }
~* Case-insensitive regex match location ~* \.(jpg\|jpeg\|png)$ { ... }
^~ Preferential prefix match location ^~ /images/ { ... }

Modifier Priority

Nginx processes location blocks in this order:

  1. Exact Match =
  2. Preferential Prefix ^~
  3. Regex Match ~ or ~*
  4. Prefix Match (none)

Practical Applications

Serving Different Content Types

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

location ~* \.(css|js)$ {
    root /var/www/static;
    expires 30d;
}

This configuration serves HTML files from /var/www/html and CSS/JS files from /var/www/static with a 30-day cache expiration.

Load Balancing

upstream backend {
    server backend1.example.com;
    server backend2.example.com;
}

location /app/ {
    proxy_pass http://backend;
}

This setup distributes requests to /app/ between two backend servers.

Security Rules

location ~* \.(sql|bak)$ {
    deny all;
}

location /admin/ {
    auth_basic "Admin Area";
    auth_basic_user_file /etc/nginx/.htpasswd;
}

These rules block access to SQL and backup files, and protect the admin area with basic authentication.

Advanced Techniques

Nested Locations

Nginx allows nesting location blocks for more specific rules:

location /api/ {
    location ~* \.(json|xml)$ {
        add_header Content-Type application/json;
    }
}

This adds a Content-Type header for JSON and XML files within the /api/ directory.

Using Variables

Nginx variables can make location blocks more dynamic:

location / {
    set $mobile_rewrite do_not_perform;

    if ($http_user_agent ~* "(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino") {
        set $mobile_rewrite perform;
    }

    if ($mobile_rewrite = perform) {
        rewrite ^ /mobile$uri redirect;
    }
}

This configuration redirects mobile users to a mobile-specific version of the site.

Types of Nginx Location Matches

Exact Match Location Blocks

Exact match location blocks in Nginx use the = modifier to specify a precise URI match. The syntax for an exact match location is:

location = /path {
    # Directives
}

Nginx processes exact match directives by comparing the requested URI with the specified path. If there's an exact match, Nginx stops searching and uses that location block.

Examples

  • Serving a specific file:

    location = /favicon.ico {
      root /var/www/images;
    }
  • Handling an API endpoint:

    location = /api/v1/status {
      proxy_pass http://backend_server;
    }
  • Custom error page for a URI:

    location = /404.html {
      internal;
    }

Prefix Match Location Blocks

A prefix match in Nginx is the default behavior when no modifier is used. It matches the beginning part of the URI.

location /docs {
    # Directives
}

This block matches any URI starting with /docs, such as /docs, /docs/, or /docs/nginx/.

Examples

  • Serving static files:

    location /static/ {
      root /var/www/myapp;
      expires 30d;
    }
  • Proxying requests to an application:

    location /app/ {
      proxy_pass http://app_server;
    }
  • Handling user uploads:

    location /uploads/ {
      client_max_body_size 10M;
      client_body_temp_path /tmp/nginx_uploads;
    }

Regular Expression Match Location Blocks

Nginx supports both case-sensitive and case-insensitive regular expression matches.

Case-Sensitive Examples

location ~ \.php$ {
    fastcgi_pass unix:/var/run/php/php7.4-fpm.sock;
}
location ~ ^/blog/(\d+)/(\w+)$ {
    return 200 "Blog post $2 from year $1";
}

Case-Insensitive Examples

location ~* \.(jpg|jpeg|png|gif)$ {
    expires 30d;
}
location ~* ^/download/.*\.(zip|tar\.gz)$ {
    root /var/www/files;
    add_header Content-Disposition "attachment";
}

Special Modifiers in Location Blocks

Preferential Prefix Matching (^~)

location ^~ /assets/ {
    root /var/www/static;
}

This block takes precedence over regular expression matches if the prefix matches.

Named Location Blocks (@)

location @fallback {
    proxy_pass http://backend;
}

location / {
    try_files $uri $uri/ @fallback;
}

Named locations are not used for regular request processing but can be referenced by other directives.

Location Match Priority

Nginx processes location blocks in this order:

  1. Exact Match =
  2. Preferential Prefix ^~
  3. Regular Expression ~
  4. Prefix Match
  5. Default Location /

Comparison Table

Match Type Modifier Example Use Case
Exact = location = /logo.png Specific file or endpoint
Preferential Prefix ^~ location ^~ /assets/ Static file directories
Regular Expression (Case-Sensitive) ~ location ~ \.php$ File type handling
Regular Expression (Case-Insensitive) ~* location ~* \.(jpg\|png)$ File type handling (ignore case)
Prefix (none) location /api/ General path matching
Named @ location @fallback Internal redirects

Best Practices

  • Use exact matches for specific files or API endpoints.
  • Use preferential prefix matches for static asset directories.
  • Use regular expressions for file type handling and complex URL patterns.
  • Use prefix matches for general path handling.
  • Order your locations from most specific to least specific.
  • Use named locations for reusable internal redirects.

Nginx Location Priority Order

Location Block Matching Order

Nginx follows a specific order when checking location types to handle requests. This order is important for request routing and processing.

Priority Order

Priority Location Type Modifier
1 Exact match =
2 Preferential prefix match ^~
3 Regular expression match ~ and ~*
4 Prefix match No modifier

This order affects how requests are handled by deciding which location block's directives apply to a request. Nginx stops searching once it finds a match, unless it's a prefix match without the ^~ modifier.

graph TD A[Request] --> B{Exact match?} B -->|Yes| C[Use exact match block] B -->|No| D{Preferential prefix match?} D -->|Yes| E[Use preferential prefix match block] D -->|No| F{Regular expression match?} F -->|Yes| G[Use first matching regex block] F -->|No| H[Use longest matching prefix block]

Exact Match Priority

Exact matches have the highest priority. When Nginx finds an exact match, it stops searching and uses that location block.

Examples of Exact Match Scenarios

location = / {
    # Handles only the request for the root URL
}

location = /about.html {
    # Processes only requests for /about.html
}

location = /api/v1/status {
    # Manages requests for this API endpoint
}

These blocks are used only for the exact URIs specified, providing fast routing for common resources.

Prefix Match Considerations

Nginx handles prefix locations by checking if the start of the request URI matches the specified prefix. If multiple prefix matches are found, Nginx uses the location with the longest matching prefix.

Example of Prefix Matching

location /app/ {
    # Handles /app/, /app/index.html, /app/images/, etc.
}

location /app/admin/ {
    # Takes precedence for /app/admin/ and its subdirectories
}

In this configuration, requests for /app/admin/ will be handled by the second block because it has a longer matching prefix.

Benefits of Longest Matching Prefix

  • Allows for specific handling of nested URI structures
  • Enables control over different sections of your website or application
  • Improves request routing efficiency

Regular Expression Match Sequence

Regular expression locations are evaluated after exact matches and preferential prefix matches (^~), but before standard prefix matches.

Example of Regular Expression Matching

location ~* \.(jpg|jpeg|png)$ {
    # Handles image files
}

location ~ \.php$ {
    # Processes PHP files
}

location / {
    # Catches all other requests
}

In this setup, Nginx first checks for image file extensions, then for PHP files, and finally uses the catch-all location for any remaining requests.

Optimizing Regular Expression Locations

  • Place specific or common regex patterns before general ones
  • Consider the order of regular expression locations for correct routing
  • Use named capture groups for readability and maintenance

Real-Life Application Scenarios

Content Delivery Optimization

location = /favicon.ico {
    log_not_found off;
    access_log off;
}

location ~* \.(css|js|jpg|jpeg|png|gif)$ {
    expires 30d;
    add_header Cache-Control "public, no-transform";
}

location / {
    try_files $uri $uri/ /index.php?$query_string;
}

This configuration:

  • Handles favicon requests
  • Applies caching headers to static assets
  • Uses a fallback mechanism for dynamic content

API Version Routing

location = /api {
    return 301 /api/v1;
}

location ~ ^/api/v1 {
    proxy_pass http://api_server_v1;
}

location ~ ^/api/v2 {
    proxy_pass http://api_server_v2;
}

location /api {
    return 404;
}

This setup:

  • Redirects bare API requests to the latest version
  • Routes different API versions to specific backend servers
  • Returns a 404 for undefined API paths

Security Implementation

location = /wp-login.php {
    limit_req zone=one burst=1 nodelay;
    include fastcgi_params;
    fastcgi_pass unix:/var/run/php/php7.4-fpm.sock;
}

location ~* /wp-admin/.*\.php$ {
    auth_basic "Restricted Access";
    auth_basic_user_file /etc/nginx/.htpasswd;
    include fastcgi_params;
    fastcgi_pass unix:/var/run/php/php7.4-fpm.sock;
}

location / {
    try_files $uri $uri/ /index.php?$args;
}

This configuration:

  • Applies rate limiting to the WordPress login page
  • Adds basic authentication to wp-admin PHP files
  • Handles normal requests with a standard WordPress setup

Practical Examples of Nginx Location Priority

Configuring Location Blocks for Static Content

HTML, CSS, and JavaScript Files

location / {
    root /var/www/html;
    index index.html index.htm;
}

location ~* \.(css|js)$ {
    root /var/www/static;
    expires 7d;
    add_header Cache-Control "public, max-age=604800";
}

This configuration:

  • Serves HTML files from /var/www/html
  • Serves CSS and JS files from /var/www/static
  • Adds caching headers to CSS and JS files (7 days expiration)

Image Files

location ~* \.(jpg|jpeg|png|gif|ico|webp)$ {
    root /var/www/images;
    expires 30d;
    add_header Cache-Control "public, no-transform";
    try_files $uri =404;
}

Benefits of this configuration:

  • Serves image files from a directory
  • Sets a longer expiration time (30 days)
  • Prevents image transformation by CDNs or proxies
  • Returns a 404 error if the file is not found

Fonts

location ~* \.(woff|woff2|ttf|otf|eot)$ {
    root /var/www/fonts;
    expires 1y;
    add_header Cache-Control "public";
    add_header Access-Control-Allow-Origin "*";
}

This block:

  • Serves font files from /var/www/fonts
  • Sets a long expiration time (1 year)
  • Allows cross-origin access for better browser compatibility

Handling Dynamic Content with Location Blocks

PHP Processing with FastCGI

location ~ \.php$ {
    fastcgi_pass unix:/var/run/php/php7.4-fpm.sock;
    fastcgi_index index.php;
    include fastcgi_params;
}

This configuration passes PHP requests to a PHP-FPM socket for processing.

Proxy Passing to Backend Application Server

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

This block forwards requests starting with /api/ to a backend server, adding headers.

WebSocket Support

location /websocket/ {
    proxy_pass http://websocket_server;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
}

This configuration enables WebSocket support for real-time applications.

Combining Different Location Types

Here's a strategy for mixing exact, prefix, and regex matches:

# Exact match for favicon
location = /favicon.ico {
    log_not_found off;
    access_log off;
}

# Preferential prefix match for static files
location ^~ /static/ {
    root /var/www;
}

# Regular expression match for PHP files
location ~ \.php$ {
    fastcgi_pass unix:/var/run/php/php7.4-fpm.sock;
    include fastcgi_params;
}

# Prefix match as a catch-all
location / {
    try_files $uri $uri/ /index.php?$query_string;
}

Best Practices for Location Block Organization

  1. Place exact matches first
  2. Use preferential prefix matches for static content directories
  3. Include regex matches for file type processing
  4. End with a prefix match to catch all remaining requests

Common Location Block Use Cases

Use Case Location Type Example
Favicon Exact location = /favicon.ico { ... }
Static Files Preferential Prefix location ^~ /static/ { ... }
PHP Files Regex location ~ \.php$ { ... }
API Requests Prefix location /api/ { ... }
Catch-all Prefix location / { ... }

Troubleshooting Nginx Location Issues

Common Mistakes in Location Block Configuration

Overlapping Location Blocks

Overlapping location blocks can cause unexpected behavior in Nginx. Here's an example:

location /images/ {
    root /var/www/static;
}

location ~ \.(jpg|jpeg|png|gif)$ {
    expires 30d;
}

In this case, a request for /images/logo.png could match both blocks. To fix this, you can:

  1. Use more specific locations
  2. Adjust the order of the blocks
  3. Combine the rules

Here's a solution:

location /images/ {
    root /var/www/static;
    location ~ \.(jpg|jpeg|png|gif)$ {
        expires 30d;
    }
}

This nested configuration sets the correct root path and expiration headers for image files in the /images/ directory.

Incorrect Use of Modifiers

Misusing location block modifiers can lead to routing errors. Here's a table of common modifiers and their usage:

Modifier Description Example
(none) Prefix match location /api/ { ... }
= Exact match location = /favicon.ico { ... }
~ Case-sensitive regex location ~ \.php$ { ... }
~* Case-insensitive regex location ~* \.(jpg|jpeg|png)$ { ... }
^~ Preferential prefix location ^~ /static/ { ... }

Example of correct modifier usage:

# Exact match for homepage
location = / {
    fastcgi_pass unix:/var/run/php/php7.4-fpm.sock;
}

# Preferential prefix for static files
location ^~ /static/ {
    root /var/www;
}

# Case-insensitive regex for image files
location ~* \.(jpg|jpeg|png|gif)$ {
    expires 30d;
}

# Default handling
location / {
    try_files $uri $uri/ /index.php?$query_string;
}

Debugging Location Match Problems

Using Nginx Logs to Identify Matching Issues

To use Nginx logs for troubleshooting:

  1. Enable debug logging:

    error_log /var/log/nginx/error.log debug;
  2. Use a custom log format:

    log_format debug_format '$remote_addr - $remote_user [$time_local] '
                           '"$request" $status $body_bytes_sent '
                           '"$http_referer" "$http_user_agent" '
                           '"$request_filename" "$request_completion"';
    
    access_log /var/log/nginx/access.log debug_format;
  3. Analyze the logs:

    tail -f /var/log/nginx/error.log | grep 'using location'

    This command shows which location blocks are being matched in real-time.

Tools for Testing Location Block Configurations

Here's a Mermaid.js diagram showing the workflow for testing Nginx configurations:

graph TD A[Start] --> B[Edit Nginx Config] B --> C[Nginx -t] C --> D{Syntax OK?} D -- No --> B D -- Yes --> E[Reload Nginx] E --> F[Test with Curl] F --> G{Expected Result?} G -- No --> H[Check Logs] H --> B G -- Yes --> I[Configuration Valid]

Practical Debugging Steps

  1. Isolate the problem:

    • Comment out all location blocks except the one you're troubleshooting.
    • Gradually add back other blocks to identify conflicts.
  2. Use add_header for debugging:

    location / {
       add_header X-Debug-Location "Root location" always;
       # ...
    }
    
    location /api/ {
       add_header X-Debug-Location "API location" always;
       # ...
    }
  3. Test with curl:

    curl -I http://yourdomain.com/path/to/test
  4. Check for "using location" messages in error logs:

    grep "using location" /var/log/nginx/error.log

Advanced Nginx Location Techniques

Nested Location Blocks

Nested location blocks in Nginx allow for more specific configurations within broader location contexts. They help apply different settings to subsets of requests that fall under a more general location block.

Uses for Nested Locations

  • Add specific rules for subdirectories
  • Override parent location settings for certain requests
  • Create organized configurations

Example of Nested Locations

location /api/ {
    proxy_pass http://api_server;

    location ~* \.(jpg|jpeg|png)$ {
        expires 30d;
        add_header Cache-Control "public, no-transform";
    }
}

This configuration proxies all /api/ requests to an API server, while setting caching headers for image files within /api/.

Points to Consider

  • Nested locations inherit directives from parent locations unless overridden
  • Avoid too much nesting for readability
  • Regular expression locations cannot contain nested location blocks

Rewrite Rules within Location Blocks

Rewrite rules in Nginx change the URI of a request before processing. They're often used within location blocks to handle URL changes or redirects.

Basic Rewrite Syntax

rewrite regex replacement [flag];

Rewrite Flags

Flag Description
last Stops processing current rewrites and searches for a new matching location
break Stops processing current rewrites and uses the changed URI in the current location
redirect Issues a temporary (302) redirect
permanent Issues a permanent (301) redirect

Practical Rewrite Examples

  1. Redirecting www to non-www:
server {
    server_name www.example.com example.com;
    if ($host = www.example.com) {
        return 301 $scheme://example.com$request_uri;
    }
    # ... other configurations
}
  1. Handling old blog URLs:
location /blog/ {
    rewrite ^/blog/(\d{4})/(\d{2})/(.*)$ /articles/$1-$2-$3 permanent;
}
  1. API version handling:
location /api/ {
    rewrite ^/api/v1/(.*)$ /api.php?version=1&request=$1 break;
    rewrite ^/api/v2/(.*)$ /api.php?version=2&request=$1 break;
}

Advanced Configuration Flow

The following Mermaid.js diagram shows the flow of request processing in Nginx with nested locations and rewrites:

graph TD A[Incoming Request] --> B{Match Server Block} B --> C{Match Location Block} C --> D{Nested Location?} D -->|Yes| E[Apply Nested Rules] D -->|No| F{Rewrite Rule?} F -->|Yes| G[Apply Rewrite] G --> H{Rewrite Flag} H -->|last| C H -->|break| I[Process Request] H -->|redirect/permanent| J[Send Redirect] F -->|No| I E --> F

This diagram shows how Nginx processes requests through server blocks, location blocks, nested locations, and rewrite rules, showing the paths a request can take based on the configuration.

Real-Life Scenarios

E-commerce Site URL Structure

An e-commerce site might use nested locations and rewrites to handle product categories and old URLs:

location /shop/ {
    # General shop settings
    index index.php;

    location ~* ^/shop/category/([^/]+)/$ {
        # Category-specific settings
        try_files $uri $uri/ /shop/category.php?name=$1;
    }

    location ~* ^/shop/product/([^/]+)$ {
        # Product-specific settings
        try_files $uri $uri/ /shop/product.php?id=$1;
    }

    # Handle old product URLs
    rewrite ^/old-shop/item/(\d+)$ /shop/product/$1 permanent;
}

This configuration:

  • Handles different URL structures for categories and products
  • Rewrites old product URLs to the new structure

Multi-language Website

For a website supporting multiple languages:

location / {
    rewrite ^/(\w{2})/(.*)$ /$2?lang=$1 last;

    location ~* \.(js|css|png|jpg|jpeg|gif|ico)$ {
        expires 30d;
    }
}

location @language_fallback {
    rewrite ^/(.*)$ /en/$1 redirect;
}

location @php {
    fastcgi_pass unix:/var/run/php/php7.4-fpm.sock;
    include fastcgi_params;
}

try_files $uri $uri/ @language_fallback;

This setup:

  • Rewrites URLs to include language as a query parameter
  • Sets long expiration for static assets
  • Redirects to English version if no language is specified
  • Passes PHP requests to FastCGI