Nginx tutorial: configure request logging

Configure Nginx access logs to capture POST data, GET parameters, and custom log formats using the log_format and access_log directives in nginx.conf.

This tutorial walks through configuring Nginx access logs to capture POST data, GET request parameters, and custom log formats. By the end, you will understand how the log_format and access_log directives work and have working log configurations for debugging HTTP traffic.

What You Will Need

  • Root or sudo access to a Linux server running Nginx.
  • SSH access to edit the nginx.conf configuration file at /etc/nginx/nginx.conf.
  • The ngx_http_echo_module installed (required for POST body logging). This module is not included in the default Nginx package on most distributions.

Step 1: Understand Nginx Log Directives

Nginx provides two directives that control access logging: log_format and access_log. The log_format directive defines a named template that specifies which request variables Nginx writes to the log file. The access_log directive assigns a log file path and a format name.

Both directives must appear inside the http { } context in nginx.conf. Nginx does not allow log_format inside server or location blocks. The access_log directive can appear in http, server, or location contexts.

Nginx writes one line to the access log for every HTTP request it processes. The default combined log format records the client IP, timestamp, request method, URI, status code, response size, referrer, and user agent.

Step 2: Configure Nginx to Log POST Request Bodies

Nginx does not log POST request bodies in the default log format. The $request_body variable captures the POST data, but Nginx only populates this variable when the request body has been read by a handler.

Add a custom log_format in the http { } block and reference it in an access_log directive. The echo_read_request_body directive from the ngx_http_echo_module forces Nginx to read the request body so the $request_body variable contains data.

http {
    log_format post_log '$remote_addr - $remote_user [$time_local] '
        '"$request" $status '
        '"$http_referer" "$http_user_agent" '
        'body: $request_body';
    access_log /var/log/nginx/post_access.log post_log;

    server {
        location / {
            echo_read_request_body;
            default_type text/html;
        }
    }
}

Nginx writes POST data to /var/log/nginx/post_access.log in this configuration. Without echo_read_request_body, the $request_body variable remains empty because Nginx does not buffer the request body by default.

Step 3: Configure Nginx to Log GET Request Parameters

Nginx includes GET request parameters in the $request variable by default. The default combined log format already captures the full request line, which includes the query string. A custom log format provides finer control over the output.

Define a custom log_format that includes the variables relevant to GET request analysis:

http {
    log_format get_log '$remote_addr - $remote_user [$time_local] '
        '"$request" $status '
        '"$http_host" '
        '"$http_referer" "$http_user_agent"';
    access_log /var/log/nginx/access.log get_log;
}

Nginx writes every GET request to /var/log/nginx/access.log using this custom format. The $http_host variable captures the domain name from the Host header, which is useful when Nginx serves multiple domains.

Step 4: Customize the Nginx Log Format

Nginx exposes many variables that can appear in a log_format template. Choose the variables that match the debugging or analytics needs.

VariableDescription
$remote_addrClient IP address
$remote_userAuthenticated username (if using HTTP basic auth)
$time_localLocal time in common log format
$requestFull request line (method, URI, protocol)
$statusHTTP response status code
$body_bytes_sentNumber of bytes sent to the client (excluding headers)
$http_refererReferrer URL from the request header
$http_user_agentUser-Agent string from the request header
$request_timeTotal request processing time in seconds
$upstream_response_timeTime spent waiting for the upstream server response
$upstream_connect_timeTime to establish a connection to the upstream server
$ssl_protocolSSL/TLS protocol version used for the connection
$ssl_cipherSSL/TLS cipher suite used for the connection
$gzip_ratioCompression ratio achieved by gzip

Combine these variables into a format string that suits the use case. Enclose variable references in single quotes within the log_format directive.

Step 5: Test and Reload the Nginx Configuration

Nginx validates the configuration when the -t flag runs. Test after every change to catch syntax errors before they affect the running server.

sudo nginx -t

Reload Nginx to apply the new logging configuration. A reload applies changes without dropping active connections.

sudo systemctl reload nginx

Send a test request and verify that the log file captures the expected data:

curl -X POST -d "username=testuser&action=login" http://example.com/
tail -5 /var/log/nginx/post_access.log

What You Learned

Nginx uses the log_format directive to define custom log templates and the access_log directive to assign a log file and format. The $request_body variable captures POST data only when a handler reads the request body. GET parameters appear in the $request variable by default. Nginx log variables such as $upstream_response_time and $ssl_protocol provide performance and security insights.

What to Do Next

For a quick-reference version of logging configuration, see the nginx.conf snippetspage. To secure the Nginx web server and protect log files from unauthorized access, see Nginx tutorial: secure a web server.