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. Tightening access logging reduces per-request overhead and leaves more headroom for application responses during sustained traffic.
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 low-value 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 change focused on genuinely noisy traffic instead of weakening application or security visibility everywhere.
Related: How to improve Nginx performance
Related: How to configure log rotation for Nginx
Steps to optimize Nginx access log performance:
- Locate the active access_log, log_format, and open_log_file_cache directives before editing so the final configuration does not write duplicate access logs.
$ sudo nginx -T 2>/dev/null | grep -nE '^\s*(access_log|log_format|open_log_file_cache)\b' 42: access_log /var/log/nginx/access.log; 119: log_format combined '$remote_addr - $remote_user [$time_local] '
Multiple access_log directives on the same configuration level write multiple log entries for each request.
- Open the Nginx configuration file that controls access logging at the http 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.
- Insert a map block inside the http context to suppress known noise paths before Nginx reaches the log write.
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.
- Define a shorter log_format inside the http context so each request writes fewer bytes.
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.
- Replace the primary access_log directive with a buffered conditional write that uses main_perf and $log_request.
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.
- Enable open_log_file_cache only when the log path itself contains variables such as $host or $server_name.
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.
- Test the updated Nginx configuration before reloading the service.
$ 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
- Reload Nginx so workers start using the new logging rules.
$ sudo systemctl reload nginx
Related: How to manage the Nginx service
- Send a request that should still be written to the access log.
$ curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1/ 200 - Send a request that the $log_request map should suppress from access logging.
$ curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1/favicon.ico 404 - Wait longer than the configured flush interval before reading the log on a quiet server.
$ 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.
- Inspect the newest line in /var/log/nginx/access.log for the expected logged request.
$ sudo tail -n 1 /var/log/nginx/access.log 127.0.0.1 - [09/Apr/2026:13:10:01 +0000] "GET / HTTP/1.1" 200 896 0.000
- Search /var/log/nginx/access.log for the suppressed /favicon.ico request.
$ sudo grep -F '"GET /favicon.ico' /var/log/nginx/access.log
No output means the request was filtered out before Nginx wrote the access log entry.
Mohd Shakir Zakaria is a cloud architect with deep roots in software development and open-source advocacy. Certified in AWS, Red Hat, VMware, ITIL, and Linux, he specializes in designing and managing robust cloud and on-premises infrastructures.
