Introduction: Before configuring Nginx, it's essential to understand the structure of Nginx configuration files, including directives, contexts, location modifiers, and the try_files directive. This guide will help you read and understand Nginx configuration files effectively.
Nginx consists of modules controlled by directives specified in configuration files. A directive is an option with a specific value, always ending with a semicolon.
Structure: option_name option_value;
listen 80;
server_name example.com www.example.com;
root /var/www/html;
index index.html index.php;
In the example above:
listen is the directive, 80 is the valueserver_name is the directive, example.com www.example.com are the values;)# are commentsA context is a special type of directive that encloses other directives within curly brackets
{ }. It's also called a context block.
events {
worker_connections 1024;
multi_accept on;
}
http {
include mime.types;
default_type application/octet-stream;
server {
listen 80;
server_name example.com;
location / {
root /var/www/html;
index index.html;
}
}
}
| Context | Purpose | Parent Context |
|---|---|---|
| Main | Global configuration affecting entire application | None (top-level) |
| Events | Connection handling options | Main |
| HTTP | HTTP service configuration | Main |
| Server | Virtual host (server block) configuration | HTTP |
| Location | Resource request handling | Server |
Child contexts can override parent contexts. For example, a directive in the Server context can override a directive in the HTTP context. This allows for flexible configuration at different levels.
# Incorrect directive (will cause error)
routes /var/www/html;
# Correct directive
root /var/www/html;
The location context defines how Nginx responds to requests for resources. Modifiers determine the matching behavior.
https://example.com/images/photo.jpg
↓ ↓ ↓
protocol domain request URI
| Modifier | Symbol | Match Type | Priority |
|---|---|---|---|
| Exact Match | = |
Exact value match | 1 (Highest) |
| Prefix Value | ^~ |
Prefix match (stops regex search) | 2 |
| Case-Sensitive Regex | ~ |
Regular expression (case-sensitive) | 3 |
| Case-Insensitive Regex | ~* |
Regular expression (case-insensitive) | 3 |
| No Modifier | (none) | Prefix match | 4 (Lowest) |
location = /xmlrpc.php {
return 403;
}
Matches: /xmlrpc.php (exact, case-sensitive)
Does NOT match: /XMLRPC.php, /xmlrpc.php?param=1,
/xmlrpc.php/
location ^~ /images {
return 301 /new-images;
}
Matches: /images, /images/photo.jpg,
/images/gallery/pic.png
Note: Stops further regex matching
location ~ \.ico$ {
return 403;
}
Matches: /favicon.ico, /images/icon.ico
Does NOT match: /favicon.ICO, /images/icon.ICO
location ~* \.php$ {
fastcgi_pass unix:/var/run/php/php-fpm.sock;
}
Matches: /index.php, /INDEX.PHP, /page.PhP
location /blog {
root /var/www/html;
}
Matches: /blog, /blog/post1, /blog/2024/article
1. Check for Exact Match (=)
↓ If no exact match found
2. Check for Prefix Value Match (^~)
↓ If no prefix value match found
3. Check Regular Expressions (~ and ~*) in order
↓ If no regex match found
4. Use best Prefix Match (no modifier)
The try_files directive checks for the existence of files in the specified order and uses the
first found file for request processing.
try_files file1 file2 ... fallback;
location / {
root /var/www/example.com/public_html;
try_files $uri $uri/ /other/index.html;
}
Step 1: Check if /var/www/example.com/public_html/image.jpg exists
✓ If YES → Serve the file
✗ If NO → Go to Step 2
Step 2: Check if /var/www/example.com/public_html/image.jpg/ directory
exists
✓ If YES → Look for index.html in that directory
✗ If NO → Go to Step 3
Step 3: Serve /var/www/example.com/public_html/other/index.html
(fallback)
✓ If EXISTS → Serve it
✗ If NOT → Return 404
location / {
try_files $uri $uri/ /index.php$is_args$args;
}
Breakdown:
$uri - Check if the requested file exists$uri/ - Check if the requested directory exists/index.php$is_args$args - Pass request to index.php with query parameterslocation / {
try_files /wp-content/cache/page_enhanced/$uri/_index.html
$uri
$uri/
/index.php$is_args$args;
}
Flow:
location ~ \.php$ {
try_files $uri =404;
fastcgi_pass unix:/var/run/php/php-fpm.sock;
fastcgi_index index.php;
include fastcgi_params;
}
This configuration checks if the PHP file exists before processing it. If the file doesn't exist, it returns a 404 error instead of passing a non-existent file to PHP-FPM.
server {
listen 80;
server_name example.com www.example.com;
root /var/www/example.com/public_html;
index index.php index.html;
# Exact match - deny xmlrpc.php
location = /xmlrpc.php {
return 403;
}
# Deny access to any .php files in uploads
location ~* ^/uploads/.*\.php$ {
return 403;
}
# Main location with try_files
location / {
try_files $uri $uri/ /index.php$is_args$args;
}
# PHP processing
location ~ \.php$ {
try_files $uri =404;
fastcgi_pass unix:/var/run/php/php-fpm.sock;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
# Deny access to hidden files
location ~ /\. {
deny all;
}
# Cache static files
location ~* \.(jpg|jpeg|png|gif|ico|css|js)$ {
expires 30d;
add_header Cache-Control "public, immutable";
}
}
sudo nginx -t| Error | Cause | Solution |
|---|---|---|
| Unknown directive | Typo or wrong context | Check spelling and context placement |
| Conflicting server names | Duplicate server_name | Ensure unique server names |
| 404 errors | Wrong root or try_files | Verify paths and file existence |
| 502 Bad Gateway | PHP-FPM not running | Start PHP-FPM service |
Now that you understand Nginx configuration fundamentals, you're ready to proceed with hardening and optimizing your hosting stack components. This knowledge forms the foundation for implementing advanced security measures and performance optimizations.