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.

Steps to optimize Nginx access log performance:

  1. Print the active Nginx configuration and note the existing access_log, log_format, and open_log_file_cache directives before editing.
    $ 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.

  2. 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.

  3. Insert a map block inside the http context to suppress known low-value 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.

  4. Define a shorter log_format inside the http context so each retained 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.

  5. 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.

  6. 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.

  7. 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
  8. Reload Nginx so workers start using the new logging rules.
    $ sudo systemctl reload nginx
  9. Send a unique request that should still be written to the access log.
    $ 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.

  10. Send a unique asset-style 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/sg-log-test.png
    404
  11. 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.

  12. Search /var/log/nginx/access.log for the retained test request and confirm the shortened format includes $request_time.
    $ 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
  13. Search /var/log/nginx/access.log for the suppressed asset-style request.
    $ 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.