Busy Nginx servers can spend measurable CPU time and disk I/O budget on access logging, especially when every image, stylesheet, health check, and cache hit generates a separate line. Reducing low-value access log writes lowers per-request work while preserving the entries operators still need for application, audit, and latency review.
The ngx_http_log_module formats requests with log_format and writes them through access_log in the http, server, or location context where processing ends. Performance gains usually come from logging fewer static or health-check requests, shortening each line, and buffering writes so workers do fewer disk operations.
Buffered logging changes how quickly entries appear on disk, and a crash can lose the newest buffered lines before they flush. When a log path contains variables such as $host, buffered writes do not apply and open_log_file_cache only reduces repeated open and close work for frequently used log files, so keep the filter focused on traffic that has no troubleshooting or security value.
Related: How to improve Nginx performance
Related: How to configure log rotation for Nginx
$ sudo nginx -T
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
##### snipped #####
http {
access_log /var/log/nginx/access.log;
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;
}
##### snipped #####
Multiple access_log directives on the same configuration level write multiple log entries for each request. Replace the active directive instead of adding a second log at the same level.
$ sudoedit /etc/nginx/nginx.conf
On packaged layouts that include /etc/nginx/conf.d/ from the http block, a dedicated snippet such as /etc/nginx/conf.d/logging-performance.conf keeps the tuning separate from virtual host files.
map $uri $log_request {
default 1;
=/favicon.ico 0;
=/robots.txt 0;
~*\.(css|js|map|jpg|jpeg|png|gif|ico|svg|webp|woff|woff2)$ 0;
}
Using map keeps the logging condition centralized and cheap to evaluate for every request.
log_format main_perf '$remote_addr - [$time_local] "$request" '
'$status $body_bytes_sent $request_time';
Add fields such as "$http_user_agent" or "$http_referer" only when they are operationally necessary.
access_log /var/log/nginx/access.log main_perf buffer=64k flush=1s if=$log_request;
Buffered logging delays writes and can lose the newest lines during a crash or hard reboot.
Use access_log off; only on exact location blocks whose requests have no audit or troubleshooting value.
open_log_file_cache max=1000 inactive=20s valid=1m min_uses=2;
Static paths such as /var/log/nginx/access.log already stay open, so this directive is for variable-based log filenames.
$ sudo nginx -t nginx: the configuration file /etc/nginx/nginx.conf syntax is ok nginx: configuration file /etc/nginx/nginx.conf test is successful
Related: How to test Nginx configuration
$ sudo systemctl reload nginx
Related: How to manage the Nginx service
$ curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1/sg-log-test-request
404
The HTTP status does not matter for this check. The path has no suppressed asset extension, so it should be logged.
$ curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1/sg-log-test.png
404
$ sleep 2
Buffered log data is written when the buffer fills, when the flush timer expires, or when workers reopen or shut down the log file.
$ sudo grep -F '"GET /sg-log-test-request' /var/log/nginx/access.log 127.0.0.1 - [06/Jun/2026:11:34:50 +0000] "GET /sg-log-test-request HTTP/1.1" 404 162 0.000
$ sudo grep -F '"GET /sg-log-test.png' /var/log/nginx/access.log
No output means the request matched $log_request = 0 and was filtered out before Nginx wrote the access log entry.