When running multiple applications under a single NGINX server block, proper log segregation becomes crucial for maintenance and debugging. The common pain point occurs when requests to subdirectories beyond the initial path (like /app2/help
) unexpectedly appear in the parent application's logs.
The original configuration contains a critical oversight: NGINX processes location blocks sequentially, and nested paths may get handled by different blocks. The location /app2
block only captures exact matches, while subsequent paths fall through to the root location.
server {
# ... existing server configuration ...
# Main application logs (app1)
access_log /var/log/nginx/app1.access.log main;
error_log /var/log/nginx/app1.error.log;
# App2 configuration with proper prefix matching
location ^~ /app2 {
alias /var/www/html/app2/public;
try_files $uri $uri/ /app2/index.php$is_args$args;
# Separate logging context
access_log /var/log/nginx/app2.access.log main;
error_log /var/log/nginx/app2.error.log;
# PHP handling specific to app2
location ~ \\.php$ {
fastcgi_pass unix:/var/run/php/php7.0-fpm.sock;
fastcgi_param SCRIPT_FILENAME $request_filename;
include fastcgi_params;
}
}
# ... remaining configuration ...
}
- ^~ prefix: The caret-tilde modifier ensures this location takes precedence over regex matches
- alias directive: Properly maps the subdirectory to its document root
- Nested PHP handling: Creates a dedicated PHP processor within the app2 context
- SCRIPT_FILENAME adjustment: Uses
$request_filename
instead of$document_root
for alias compatibility
After applying the configuration, verify with these test cases:
curl http://localhost/app2
→ Should appear in app2.access.logcurl http://localhost/app2/help
→ Should appear in app2.access.logcurl http://localhost/help
→ Should appear in app1.access.log
For more complex scenarios, consider using NGINX's map directive:
map $uri $loggable {
~^/app2 0;
default 1;
}
map $uri $logname {
~^/app2 'app2';
default 'app1';
}
access_log /var/log/nginx/$logname.access.log combined if=$loggable;
When configuring NGINX to serve multiple applications where one operates as a subdirectory (e.g., /app2), you might encounter logging inconsistencies. While the main application logs properly to its designated files, requests to nested paths within the subdirectory application (/app2/help) mysteriously appear in the parent application's logs.
The issue stems from how NGINX processes location blocks and PHP requests. When a request matches multiple location blocks (like /app2 and the PHP handler), the most specific match takes precedence but inherits the parent context's logging configuration.
Here's the proper way to implement separate logging for subdirectory applications:
server {
# ... other server config ...
# Main app logging (default)
access_log /var/log/nginx/app1.access.log;
error_log /var/log/nginx/app1.error.log;
location /app2 {
alias /var/www/html/app2/public;
try_files $uri $uri/ /app2/index.php$is_args$args;
# Subdirectory-specific logging
access_log /var/log/nginx/app2.access.log app2;
error_log /var/log/nginx/app2.error.log;
# Nested PHP handling
location ~ \\.php$ {
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $request_filename;
fastcgi_pass unix:/var/run/php/php7.0-fpm.sock;
# Important: Maintain the app2 logging context
access_log /var/log/nginx/app2.access.log app2;
error_log /var/log/nginx/app2.error.log;
}
}
# Main PHP handler (outside app2 context)
location ~ \\.php$ {
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_pass unix:/var/run/php/php7.0-fpm.sock;
}
}
1. Use alias instead of root for the subdirectory location to properly map paths
2. Duplicate logging directives in both the main /app2 block and its nested PHP handler
3. Different SCRIPT_FILENAME for each PHP handler context
4. Consider log format names (like 'app2' in the example) for better analysis
Verify the setup works as expected:
curl http://localhost/app2
curl http://localhost/app2/help
tail -f /var/log/nginx/app2.access.log
The log format can be customized in your nginx.conf:
log_format app2 '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent" "$http_x_forwarded_for"';
For more complex setups with multiple subdirectories, consider using a map directive:
map $uri $app_log {
~^/app2/ app2;
~^/app3/ app3;
default app1;
}
access_log /var/log/nginx/$app_log.access.log;