Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

iTechGuides is reader-supported. When you buy through links on our site, we may earn an affiliate commission. As an Amazon Associate I earn from qualifying purchases. Learn more

The reliable way to find Nginx logs is to inspect the configuration that is actually running. The active access_log and error_log directives choose the destination, format, and severity; package defaults are only conventions. Start with nginx -T, identify the directives for the affected server or location, then correlate one access-log line with error-log entries from the same request and time window.

What Nginx access and error logs tell you

Nginx produces two different kinds of records:

  • Access logs record completed requests. They normally contain the client address, request line, response status, response size, referrer, user agent, and any additional variables selected by the configured log_format.
  • Error logs record processing problems and diagnostic messages. They can identify permission failures, missing files, refused connections, upstream timeouts, TLS problems, and configuration-load errors that an HTTP status alone cannot explain.

An access entry answers “what response did Nginx return, and how long did processing take?” An error entry helps answer “why did it return that response?” A reverse-proxy investigation usually needs both.

What’s actually slowing this PC down?

Pick the symptom - the matching free tool is one click away.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Find the active log destinations first

Inspect the complete running configuration

Use the configuration Nginx can load, rather than guessing a distribution-specific path:

sudo nginx -T | less

Search the output for every access_log and error_log. Pay particular attention to the server block serving the hostname and to any more-specific location block. A virtual host can write to a different file from the global HTTP setting, and a location-level directive can replace an inherited setting.

If the command reports a permissions or syntax problem, resolve that first. You need to inspect the configuration that the installed binary can parse; an old sample file or an unused include does not describe the active service.

Check compiled-in path conventions

When a path is not obvious, inspect the build options:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
sudo nginx -V 2>&1

Look for --error-log-path= and --http-log-path=. These options show the build-time defaults, but an explicit directive in the configuration takes precedence. The generic Nginx module defaults are logs/error.log and logs/access.log combined; relative paths are resolved under the build prefix.

Know the common package locations

Environment Common convention Qualification
RHEL-based, Debian, and Ubuntu packages /var/log/nginx/error.log
/var/log/nginx/access.log
These are common package paths, not guarantees. Confirm with nginx -T.
FreeBSD packages /usr/local/var/log/nginx/error.log A common FreeBSD convention; an explicit directive may point elsewhere.
Container images Often standard files or a link to /dev/stderr Inspect the image configuration and the container runtime’s logs. A host-side file may not exist.

Watch the files while reproducing a request

Once the configuration gives you exact paths, follow them in separate terminals:

sudo tail -f /var/log/nginx/access.log
sudo tail -f /var/log/nginx/error.log

Replace the examples with the paths shown by your configuration. In a container, use the runtime’s log command when Nginx writes to standard error instead of a file.

Understand where each logging directive applies

access_log: destination and format

The access_log directive selects a file, standard error, or (where supported by the configuration) another destination and associates the entries with a named format. The format is defined separately by log_format. If no custom format is selected, the documented combined example includes:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
  • client address;
  • authenticated user, when present;
  • local time;
  • request line;
  • final HTTP status;
  • response bytes;
  • referrer; and
  • user agent.

Do not parse a line using assumptions from another server. Two Nginx installations can use different fields, quoting, delimiters, or formats. Read the log_format definition in the active configuration before writing a parser or deciding that a field is missing.

error_log: destination and severity threshold

error_log accepts a file, stderr, or a syslog destination and can specify a severity threshold. The directive is valid in the main, http, stream, server, and location contexts.

Thresholds are inclusive toward more serious messages. With a warn threshold, Nginx records warn, error, crit, alert, and emerg messages, but not lower-severity informational or debug output. A lower-level directive overrides an inherited setting. If multiple error_log directives are configured at the same level, a message can be written to each configured destination; otherwise it is written once to the closest applicable log.

Why a file you expect may stay empty

  • The request is handled by another server block selected by its host name or listen address.
  • A specific location has its own logging directive.
  • The destination is stderr or syslog rather than a file.
  • The configured severity threshold excludes the message you expect.
  • The process cannot write the file, or log rotation changed the path and the worker has not been reopened.
  • The request has not completed yet, so its access entry has not been emitted.

Read an access-log line field by field

Find the outcome

$status is the final HTTP status Nginx sent for the request. A 404 means the resulting response was “not found”; it does not by itself prove that a file was absent. The response might have been generated by Nginx, an upstream application, an internal redirect, or a custom error handler.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

$body_bytes_sent and $bytes_sent report response volume according to their respective variable definitions. Use the variable present in your configured format and remember that headers and body are accounted for differently.

Measure total Nginx request time

$request_time measures total request processing time in seconds, from the first bytes received until the final response processing completes. It is the quickest way to find slow requests, but it does not identify which phase consumed the time.

Separate upstream delays

For proxied or FastCGI traffic, add these variables to a custom format or inspect them if they are already logged:

Variable What it isolates How to interpret it
$upstream_connect_time Time to establish a connection to the upstream A high value points toward network reachability, connection limits, or an overloaded upstream accepting connections slowly.
$upstream_header_time Time until the upstream response headers arrive A high value after a normal connect time usually indicates application or upstream processing delay.
$upstream_response_time Time to receive the complete upstream response The difference from header time can indicate a slow response body or slow upstream transfer.

Also log the upstream address and upstream status when diagnosing proxy failures. Multiple upstream attempts can produce comma-separated values, so compare positions across related upstream variables rather than treating a list as one measurement.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Account for buffering and compression

Access logging can be buffered and flushed according to the configured buffer and flush settings. A line may therefore appear later than the request completion. Rotated logs may be compressed; the Nginx module documentation notes that compressed blocks can be read with zcat, for example:

zcat /var/log/nginx/access.log.2.gz | less

Use the rotation naming and compression policy configured on your host; do not assume that the newest numerical suffix contains the newest request.

Read an error-log entry in context

Start with timestamp and process details

An error entry normally gives a timestamp, severity, process identifier, and descriptive text. It may also include the client address, server name, request line, upstream address, and the operating-system error text. Record the exact time, host, method, and URI before searching; broad searches often mix unrelated virtual hosts.

Recognize common diagnostic patterns

  • Connection refused: Nginx reached the upstream address but no service accepted the connection, or a local firewall/socket policy rejected it. Check that the upstream process is listening on the configured address and port.
  • Permission denied: The worker could not read a static file, traverse a directory, access a certificate, or connect to a protected socket. Check ownership, mode bits, parent-directory traversal, and mandatory access controls.
  • No such file or directory: The resolved root, alias, script path, socket, or certificate path does not exist. Confirm the path after variable expansion and check deployment symlinks.
  • Upstream timed out: The upstream did not complete the expected operation within the configured timeout. Use upstream timing fields and inspect the application or database rather than increasing the timeout blindly.
  • TLS or configuration-load failure: The error text identifies the certificate, protocol, syntax, or included file that failed. A reload that does not pass configuration validation will leave the previous configuration running.

The precise message and its context matter more than the status code. A 502 can result from a refused connection, an invalid upstream response, or a timeout; each requires a different fix.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

A repeatable workflow for 404, 502, and slow requests

  1. Confirm the active configuration. Run sudo nginx -T and identify the exact access_log and error_log directives for the affected host and URI.
  2. Reproduce one request. Note the UTC or local timestamp used by the log, host name, method, URI, and expected status. Use a single request first so correlation is unambiguous.
  3. Locate its access entry. Read the fields defined by the selected log_format, including $status, $request_time, and any upstream variables.
  4. Search the same time window in the error log. Match the request, client, process, upstream, and operating-system text rather than searching only for “502” or “404.”
  5. Check for a more specific block. Re-read the matching server and location sections for overridden roots, proxies, logging destinations, or thresholds.
  6. Validate the proposed correction. After editing, run the configuration test appropriate to your installation, reload only after it passes, and reproduce the same request. Verify that the new access and error entries show the intended result.

Investigating a 404

Compare the request URI with the selected root or alias, the location match, and any internal redirect. If the error log says a file is missing, verify the resolved filesystem path and permissions. If no file error appears, the 404 may have been generated by an upstream application or custom error handler; the access status alone cannot distinguish those cases.

Investigating a 502

Use the error entry to distinguish refusal, timeout, or malformed upstream response. Then compare the upstream address and status in the access record with $upstream_connect_time, $upstream_header_time, and $upstream_response_time. A fast refusal is different from a long header wait, and neither is fixed by changing the same setting.

Investigating latency

Sort or filter access records by $request_time. For each slow request, compare connect, header, and response timings. A high total time with low upstream timings can indicate client transmission, response buffering, or Nginx-side processing; a high header time points more directly at upstream work.

Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

When ordinary logging is not enough

Verify debug support before enabling it

Debug logging is disabled by default and requires a debug-capable Nginx build. Check the build information first:

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
sudo nginx -V 2>&1

Only when the binary supports debug logging should you use an error_log directive with the debug threshold in the narrowest practical context. Generate one controlled reproduction, collect the relevant entries, then restore the normal threshold. Debug output is substantially more verbose and can expose request details, consume storage, and make other events harder to find.

Prefer a temporary, narrow scope

Place diagnostic logging at the affected server or location when possible instead of enabling it globally. Confirm the destination has sufficient space and that rotation can handle the temporary increase. Remove or reduce the setting after the problem is understood.

Compare logging setups before changing one

For a migration, incident review, or server comparison, document these properties for each setup:

Axis Questions to answer
Destination File, standard error, or syslog? Is the destination visible from the host, container, or service manager?
Scope Is the directive in main, http, server, or location? Which lower-level block overrides it?
Severity What threshold is active, and will it include the event you need?
Format and fields Which log_format is selected? Are status, request time, upstream address, and upstream timings present?
Buffering and compression When are lines flushed, and how are rotated files compressed or named?
Retention and rotation Which component rotates logs, how long are they retained, and how are open files reopened?
Upstream visibility Can you distinguish connection, first-byte, and full-response delays?

Quick command checklist

  • sudo nginx -T | less — print the complete effective configuration and find active logging directives.
  • sudo nginx -V 2>&1 — inspect build options, including compiled-in log paths and debug capability.
  • sudo tail -f /path/from/nginx-T/access.log — watch completed requests.
  • sudo tail -f /path/from/nginx-T/error.log — watch warnings and errors.
  • zcat /path/to/rotated.log.gz | less — inspect a compressed rotated log.

Replace every illustrative path with the destination shown by the active configuration. If Nginx logs to stderr, read the container or service-manager log stream instead of creating an assumed file.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Practical interpretation rules

  • Trust the active directive over a distribution convention or a tutorial’s sample path.
  • Interpret a line according to its configured format, not the documented combined example unless that format is actually selected.
  • Use the final status as an outcome, then use error text and upstream fields to find the cause.
  • Keep timestamps, host names, URIs, process identifiers, and upstream addresses together when correlating records.
  • Remember that access logging occurs after request processing and may be delayed by buffering.
  • Treat debug logging as a short, targeted escalation that needs a debug-capable build.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.