How to configure logging in Nginx? What are the log formats and optimization methods?
Nginx logs are very important for monitoring, debugging, and security auditing. Proper log configuration can help quickly identify issues and optimize performance.
Access Log Configuration:
nginxhttp { # Custom log format log_format main '$remote_addr - $remote_user [$time_local] ' '"$request" $status $body_bytes_sent ' '"$http_referer" "$http_user_agent" ' '$request_time $upstream_response_time'; # Detailed log format log_format detailed '$remote_addr - $remote_user [$time_local] ' '"$request" $status $body_bytes_sent ' '"$http_referer" "$http_user_agent" ' '$request_time $upstream_response_time ' '$upstream_addr $upstream_status ' '$http_x_forwarded_for $request_id'; # JSON format log log_format json_combined escape=json '{' '"time_local":"$time_local",' '"remote_addr":"$remote_addr",' '"remote_user":"$remote_user",' '"request":"$request",' '"status":"$status",' '"body_bytes_sent":"$body_bytes_sent",' '"request_time":"$request_time",' '"http_referrer":"$http_referer",' '"http_user_agent":"$http_user_agent"' '}'; # Apply log format access_log /var/log/nginx/access.log main; server { listen 80; server_name example.com; # Use different log format access_log /var/log/nginx/example.com.access.log detailed; location / { proxy_pass http://backend; } } }
Error Log Configuration:
nginx# Error log levels: debug, info, notice, warn, error, crit, alert, emerg error_log /var/log/nginx/error.log warn; # Different level error logs error_log /var/log/nginx/error.log info; error_log /var/log/nginx/crit.log crit;
Log Optimization:
nginxhttp { # Disable logging for specific paths location ~* \.(css|js|jpg|jpeg|png|gif|ico|svg|woff|woff2)$ { access_log off; } # Disable health check logging location /health { access_log off; return 200 "OK"; } # Buffer log writes access_log /var/log/nginx/access.log main buffer=32k flush=5s; # Compress logs access_log /var/log/nginx/access.log main gzip=9; }
Conditional Logging:
nginxhttp { # Log based on status code map $status $loggable { ~^[23] 0; default 1; } # Log based on request method map $request_method $loggable_method { GET 1; POST 1; default 0; } server { listen 80; server_name example.com; # Only log requests with specific status codes access_log /var/log/nginx/access.log main if=$loggable; # Only log requests with specific methods access_log /var/log/nginx/method.log main if=$loggable_method; location / { proxy_pass http://backend; } } }
Log Separation:
nginxhttp { # API log format log_format api '$remote_addr - $remote_user [$time_local] ' '"$request" $status $body_bytes_sent ' 'rt=$request_time uct="$upstream_connect_time" ' 'uht="$upstream_header_time" urt="$upstream_response_time"'; server { listen 80; server_name example.com; # Main site log access_log /var/log/nginx/main.log main; # API log location /api/ { access_log /var/log/nginx/api.log api; proxy_pass http://api_backend; } # Don't log static resources location ~* \.(css|js|jpg|jpeg|png|gif|ico|svg|woff|woff2)$ { access_log off; root /var/www/static; } } }
Log Rotation:
bash# /etc/logrotate.d/nginx /var/log/nginx/*.log { daily missingok rotate 14 compress delaycompress notifempty create 0640 nginx adm sharedscripts postrotate [ -f /var/run/nginx.pid ] && kill -USR1 `cat /var/run/nginx.pid` endscript }
Log Analysis Variables:
nginxlog_format analysis '$remote_addr - $remote_user [$time_local] ' '"$request" $status $body_bytes_sent ' '"$http_referer" "$http_user_agent" ' '$request_time $upstream_response_time ' '$upstream_addr $upstream_status ' '$scheme $server_name $request_uri ' '$http_host $http_x_forwarded_for ' '$request_id $connection $connections ' '$time_iso8601 $msec';
Common Log Variables:
| Variable | Description |
|---|---|
| $remote_addr | Client IP address |
| $remote_user | Authenticated username |
| $time_local | Local time |
| $request | Full request line |
| $status | Response status code |
| $body_bytes_sent | Bytes sent |
| $http_referer | Referrer page |
| $http_user_agent | User agent |
| $request_time | Request processing time |
| $upstream_response_time | Upstream response time |
| $upstream_addr | Upstream server address |
| $upstream_status | Upstream status code |
| $request_id | Request ID |
| $http_x_forwarded_for | Real client IP |
Log Monitoring and Alerting:
nginx# Custom error log format log_format error_log_format '$time_local [$level] $message'; # Log slow requests log_format slow_request '$remote_addr - $remote_user [$time_local] ' '"$request" $status $request_time ' 'upstream_response_time=$upstream_response_time'; http { # Slow request threshold map $request_time $slow_request { default 0; ~^([1-9]\d*\.?\d*|0\.\d*[1-9]\d*) 1; } server { listen 80; server_name example.com; # Log slow requests access_log /var/log/nginx/slow.log slow_request if=$slow_request; location / { proxy_pass http://backend; } } }
Log Security:
nginxhttp { # Don't log sensitive information log_format secure '$remote_addr - $remote_user [$time_local] ' '"$request" $status $body_bytes_sent ' '"$http_referer" "$http_user_agent" ' '$request_time'; server { listen 80; server_name example.com; # Don't log passwords and other sensitive info location /login { access_log /var/log/nginx/login.log secure; proxy_pass http://auth_backend; } # Don't log sensitive paths location ~* ^/(admin|api/v1/users) { access_log /var/log/nginx/sensitive.log secure; proxy_pass http://backend; } } }
Complete Log Configuration Example:
nginxuser nginx; worker_processes auto; http { # Log formats log_format main '$remote_addr - $remote_user [$time_local] ' '"$request" $status $body_bytes_sent ' '"$http_referer" "$http_user_agent" ' '$request_time $upstream_response_time'; log_format api '$remote_addr - $remote_user [$time_local] ' '"$request" $status $body_bytes_sent ' 'rt=$request_time uct="$upstream_connect_time" ' 'uht="$upstream_header_time" urt="$upstream_response_time" ' 'upstream_addr=$upstream_addr upstream_status=$upstream_status'; log_format json_combined escape=json '{' '"time_local":"$time_local",' '"remote_addr":"$remote_addr",' '"remote_user":"$remote_user",' '"request":"$request",' '"status":"$status",' '"body_bytes_sent":"$body_bytes_sent",' '"request_time":"$request_time",' '"http_referrer":"$http_referer",' '"http_user_agent":"$http_user_agent",' '"upstream_response_time":"$upstream_response_time"' '}'; # Global logs access_log /var/log/nginx/access.log main buffer=32k flush=5s; error_log /var/log/nginx/error.log warn; # Conditional logging map $status $loggable { ~^[23] 0; default 1; } # Slow requests map $request_time $slow_request { default 0; ~^([1-9]\d*\.?\d*|0\.\d*[1-9]\d*) 1; } server { listen 80; server_name example.com; # Main log access_log /var/log/nginx/example.com.access.log main if=$loggable; # Slow request log access_log /var/log/nginx/slow.log main if=$slow_request; # API log location /api/ { access_log /var/log/nginx/api.log api; proxy_pass http://api_backend; } # Don't log static resources location ~* \.(css|js|jpg|jpeg|png|gif|ico|svg|woff|woff2)$ { access_log off; root /var/www/static; } # Don't log health checks location /health { access_log off; return 200 "OK"; } location / { proxy_pass http://backend; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; } } }
Log Analysis Tools:
- GoAccess: Real-time log analysis
- AWStats: Web log analysis
- ELK Stack: Elasticsearch + Logstash + Kibana
- Grafana + Loki: Log monitoring and visualization
- Splunk: Enterprise-level log analysis
Log Optimization Recommendations:
- Set appropriate log levels: Use warn or error in production
- Use buffering: Reduce disk I/O
- Regular rotation: Prevent log files from becoming too large
- Compress old logs: Save disk space
- Separate logs: Separate by business type
- Conditional logging: Only log necessary information
- Use JSON format: Easier for machine parsing
- Monitor log size: Prevent disk from filling up