Nginx Cheatsheet

Logging

Use this Nginx reference while you build software engineering projects, review code for technical interview prep, or polish examples for a software engineer resume.

Default Log Locations

FileContents
/var/log/nginx/access.logEvery HTTP request
/var/log/nginx/error.logErrors, warnings, notices
# Watch logs live
tail -f /var/log/nginx/access.log
tail -f /var/log/nginx/error.log

# Filter by status code
tail -f /var/log/nginx/access.log | grep '" 5'

# Count requests by IP
awk '{print $1}' /var/log/nginx/access.log | sort | uniq -c | sort -rn | head -20

Access Log Directive

access_log path [format [buffer=size [flush=time]] [if=condition]];

# Examples
access_log /var/log/nginx/example.access.log combined;
access_log /var/log/nginx/example.access.log main buffer=32k flush=5s;
access_log off;   # Disable entirely for this block

Error Log Directive

error_log path [level];

# Level (lowest to most verbose): emerg alert crit error warn notice info debug
error_log /var/log/nginx/error.log warn;      # Production default
error_log /var/log/nginx/error.log debug;     # Full debug (very verbose)
error_log /dev/null;                          # Suppress all errors (not recommended)

Built-in Log Formats

# "combined" (default) — already defined in nginx.conf
log_format combined '$remote_addr - $remote_user [$time_local] '
                    '"$request" $status $body_bytes_sent '
                    '"$http_referer" "$http_user_agent"';

# "main" (defined in the stock nginx.conf, not built in) is combined
# plus "$http_x_forwarded_for" — see Custom Log Format below

Custom Log Format

http {
    log_format main '$remote_addr - $remote_user [$time_local] "$request" '
                    '$status $body_bytes_sent "$http_referer" '
                    '"$http_user_agent" "$http_x_forwarded_for"';

    log_format json_combined escape=json
        '{'
            '"time":"$time_iso8601",'
            '"remote_addr":"$remote_addr",'
            '"method":"$request_method",'
            '"uri":"$request_uri",'
            '"status":$status,'
            '"bytes_sent":$body_bytes_sent,'
            '"request_time":$request_time,'
            '"upstream_time":"$upstream_response_time",'
            '"upstream_addr":"$upstream_addr",'
            '"http_referrer":"$http_referer",'
            '"http_user_agent":"$http_user_agent"'
        '}';

    access_log /var/log/nginx/access.json json_combined;
}

Useful Log Variables

VariableExample valueDescription
$remote_addr203.0.113.5Client IP
$http_x_forwarded_for203.0.113.5Original IP behind proxy
$time_local13/Jun/2024:12:00:00 +0000Local time
$time_iso86012024-06-13T12:00:00+00:00ISO 8601 time
$requestGET /api/v1/users HTTP/1.1Full request line
$request_methodGETHTTP method
$request_uri/api/v1/users?page=2URI + query string
$status200Response status code
$body_bytes_sent1234Bytes sent (excludes headers)
$bytes_sent1398Total bytes sent (includes headers)
$request_time0.045Request processing time (seconds)
$upstream_response_time0.042Time upstream took to respond
$upstream_addr127.0.0.1:3000Backend server address
$upstream_cache_statusHITCache result
$http_refererhttps://google.comReferer header
$http_user_agentMozilla/5.0 ...User-Agent header
$ssl_protocolTLSv1.3TLS version (HTTPS only)
$ssl_cipherTLS_AES_256_GCM_SHA384Cipher used

Per-location Log Control

# Silence noisy health checks
location = /health {
    access_log off;
    return 200;
}

# Log static assets to a separate file
location ~* \.(js|css|png|jpg)$ {
    access_log /var/log/nginx/static.log;
    root /var/www/app;
}

# Conditional logging — skip 2xx responses from monitoring IPs
map $status $log_this {
    ~^2  0;
    default 1;
}
access_log /var/log/nginx/errors.log combined if=$log_this;

Conditional Access Log (if=)

# Only log errors
map $status $is_error {
    ~^[45] 1;
    default 0;
}

access_log /var/log/nginx/errors.log combined if=$is_error;

Log Rotation

# /etc/logrotate.d/nginx  (installed by package, shown for reference)
/var/log/nginx/*.log {
    daily
    missingok
    rotate 14
    compress
    delaycompress
    notifempty
    create 640 nginx adm
    sharedscripts
    postrotate
        # Send USR1 to reopen log files without restarting
        nginx -s reopen
    endscript
}
# Force immediate rotation
sudo logrotate -f /etc/logrotate.d/nginx

# Manually reopen logs (zero-downtime)
sudo nginx -s reopen
# or
sudo kill -USR1 $(cat /var/run/nginx.pid)

Buffered Logging (High Traffic)

# Buffer writes — flush every 5 s or when buffer is full
access_log /var/log/nginx/access.log combined buffer=64k flush=5s;

Reduces disk I/O on high-request-rate servers.