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
-
Serving static files:
location /images/ { root /var/www/static; }
This directive serves image files from the
/var/www/static/images/
directory. -
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. -
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. -
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:
- Exact Match =
- Preferential Prefix ^~
- Regex Match ~ or ~*
- 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:
- Exact Match =
- Preferential Prefix ^~
- Regular Expression ~
- Prefix Match
- 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.
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
- Place exact matches first
- Use preferential prefix matches for static content directories
- Include regex matches for file type processing
- 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:
- Use more specific locations
- Adjust the order of the blocks
- 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:
-
Enable debug logging:
error_log /var/log/nginx/error.log debug;
-
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;
-
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:
Practical Debugging Steps
-
Isolate the problem:
- Comment out all location blocks except the one you're troubleshooting.
- Gradually add back other blocks to identify conflicts.
-
Use
add_header
for debugging:location / { add_header X-Debug-Location "Root location" always; # ... } location /api/ { add_header X-Debug-Location "API location" always; # ... }
-
Test with curl:
curl -I http://yourdomain.com/path/to/test
-
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
- 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
}
- Handling old blog URLs:
location /blog/ {
rewrite ^/blog/(\d{4})/(\d{2})/(.*)$ /articles/$1-$2-$3 permanent;
}
- 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:
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