The try_files
directive in Nginx serves as a conditional file existence checker, but crucially does not terminate request processing when used within location blocks that have additional processing instructions. Here's what happens step-by-step for a request to domain.com/test.php
:
1. Nginx receives request for test.php
2. try_files checks if /usr/share/nginx/html/test.php exists
3. If exists, continues processing (does NOT serve statically)
4. Executes remaining directives in location block (fastcgi_pass)
The try_files $uri =404
line primarily serves two security purposes:
- Prevents arbitrary code execution by verifying file existence before processing
- Returns 404 if the PHP file doesn't exist (rather than passing to FastCGI)
This becomes clearer when we examine the processing flow:
location ~ \.php$ {
try_files $uri =404; # Security check only
fastcgi_pass unix:/var/run/php-fpm.sock;
# Other FastCGI params...
}
For different use cases, you might see these variations:
Basic Security Configuration:
try_files $uri =404;
With Fallback to Index:
try_files $uri $uri/ /index.php?$args;
Framework-Friendly (Laravel/Symfony):
try_files $uri /index.php$is_args$args;
Issue: try_files seems to bypass FastCGI
Solution: This usually indicates missing the PHP location block regex modifier (~
or ~*
)
Issue: 404 errors on valid PHP files
Solution: Verify $document_root
matches your file paths:
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
While try_files adds a filesystem check, the overhead is minimal because:
- Nginx caches negative lookups
- Modern SSDs handle stat operations efficiently
- The security benefit outweighs micro-optimization
For high-traffic sites, consider adding:
open_file_cache max=2000 inactive=20s;
open_file_cache_valid 30s;
In the given Nginx configuration, the try_files $uri =404
directive within the PHP location block serves a crucial security purpose. Contrary to initial assumptions, it doesn't simply serve static PHP files - rather, it performs a file existence check before proceeding with FastCGI processing.
location ~ \.php$ {
try_files $uri =404; # Checks if file exists
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass unix:/var/run/php5-fpm.sock;
# ... other fastcgi params ...
}
Here's what happens step-by-step when requesting domain.com/test.php
:
The try_files $uri =404
line prevents arbitrary code execution vulnerabilities that could occur if:
- Someone uploads malicious PHP files to upload directories
- Path traversal attempts are made to execute system PHP files
- Symlink attacks try to reference sensitive files
For more complex setups, you might see variations like:
location ~ \.php$ {
try_files $uri /index.php$is_args$args;
fastcgi_pass php-fpm;
# ... fastcgi params ...
}
Be careful with these problematic patterns:
# UNSAFE: Missing try_files check
location ~ \.php$ {
fastcgi_pass unix:/var/run/php5-fpm.sock;
}
# RISKY: Overly permissive try_files
location ~ \.php$ {
try_files $uri /index.php;
fastcgi_pass unix:/var/run/php5-fpm.sock;
}