Nginx Log Analyzer & Pattern Reference
Annotated nginx access and error log format reference, error log severity levels, default file locations, ~15 curated regex patterns for common access/error log events, and a private in-browser paste-and-test matcher. Every pattern ships with a ready-to-paste Alert24 server-agent log-search config.
Private by design: the pattern matcher runs entirely in your browser. Log lines you paste are never uploaded, logged, or stored anywhere.
Nginx log format reference
Access log — default combined format
The default access log uses the predefined combined format. Its log_format definition is:
log_format combined '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent"';Example line:
192.0.2.10 - alice [10/Oct/2024:13:55:36 +0000] "GET /api/orders?id=42 HTTP/1.1" 200 2326 "https://example.com/cart" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36"
| Field | Variable | Meaning |
|---|---|---|
| 192.0.2.10 | $remote_addr | Client IP address. Behind a proxy/load balancer this is the proxy IP unless you log $http_x_forwarded_for or use the real_ip module. |
| - | (identd) | RFC 1413 identity of the client. Almost always "-" — nginx does not perform ident lookups; the field exists only for historical Common Log Format compatibility. |
| alice | $remote_user | Username supplied via HTTP Basic authentication. "-" when the request is not authenticated. |
| [10/Oct/2024:13:55:36 +0000] | $time_local | Local time the request finished, in Common Log Format (day/month/year:hour:minute:second zone). |
| "GET /api/orders?id=42 HTTP/1.1" | $request | The full request line: HTTP method, request URI (path + query string), and protocol version, exactly as sent by the client. |
| 200 | $status | HTTP response status code nginx sent back to the client (e.g. 200, 301, 404, 502). |
| 2326 | $body_bytes_sent | Number of bytes sent to the client in the response body, not counting the response headers. |
| "https://example.com/cart" | $http_referer | Value of the Referer request header — the page the client came from. "-" when absent. |
| "Mozilla/5.0 (X11; Linux x86_64) ..." | $http_user_agent | Value of the User-Agent request header — identifies the browser, bot, or client library. |
Error log format
The error log is not configurable like the access log; nginx writes a fixed structure:date time [level] pid#tid: *conn message.
Example line:
2024/10/10 13:55:36 [error] 1234#1234: *567 connect() failed (111: Connection refused) while connecting to upstream, client: 192.0.2.10, server: example.com, request: "GET /api HTTP/1.1", upstream: "http://127.0.0.1:9000/api", host: "example.com"
| Field | Part | Meaning |
|---|---|---|
| 2024/10/10 13:55:36 | date time | Timestamp of the event (server local time), in YYYY/MM/DD HH:MM:SS format. |
| [error] | severity level | Severity of the message. The threshold is controlled by the second argument to the error_log directive. |
| 1234#1234 | pid#tid | The worker process ID and thread ID that emitted the message. |
| *567 | connection | Connection serial number — lets you correlate every log line for a single connection. |
| connect() failed (111: Connection refused) ... | message | Free-form message plus context key/value pairs nginx attaches (client, server, request, upstream, host). |
Error log severity levels
The second argument to error_log sets the minimum level (e.g. error_log /var/log/nginx/error.log warn;). Levels run from least to most severe; selecting one logs that level and all more severe ones.
| Level | Meaning |
|---|---|
| debug | Extremely verbose debugging detail (requires nginx built with --with-debug). |
| info | Informational messages about normal operation. |
| notice | Normal but notable events. |
| warn | Warnings — something unexpected, but the request was still served. |
| error | A request failed: an error occurred while processing it (the default error_log level). |
| crit | Critical conditions, such as failing to bind a socket. |
| alert | Action must be taken immediately; the server is in a bad state. |
| emerg | Emergency — nginx is unusable (e.g. configuration prevents startup). |
Highlighted rows (error and above) are what most production alerting should watch.
Default log file locations
| /var/log/nginx/access.log | Default access log (Debian/Ubuntu and RHEL/CentOS packages). |
| /var/log/nginx/error.log | Default error log. |
| /usr/local/nginx/logs/access.log | Default when nginx is compiled from source with default --prefix. |
| /usr/local/nginx/logs/error.log | Source-build error log. |
| /etc/nginx/nginx.conf | Main config — look here for log_format and access_log / error_log directives. |
Defining a custom log_format
Define a named format with the log_format directive in the http {} block, then reference it on anaccess_log directive. Adding upstream timing variables is what lets the “slow upstream” pattern below work:
# Define a custom format (e.g. add upstream timing) in the http {} block:
log_format timed_combined
'$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent" '
'rt=$request_time uct="$upstream_connect_time" '
'uht="$upstream_header_time" urt="$upstream_response_time"';
# Then reference it on an access_log directive (http, server, or location):
access_log /var/log/nginx/access.log timed_combined;Pattern library
15 curated regex patterns for nginx access and error logs. Each card includes the regex, what it catches, a matching example line, a severity, and a ready-to-paste Alert24 server-agent log-search config. Click Test this pattern to load it into the matcher below.
5xx server errors
access logcriticalAny 5xx response in the combined access log (500, 502, 503, 504…). Matches the status field that follows the quoted request line.
" 5\d\d 192.0.2.10 - - [10/Oct/2024:13:55:36 +0000] "GET /api HTTP/1.1" 500 120 "-" "curl/8.0"log_searches entry){ "name": "nginx_5xx", "source": "file", "path": "/var/log/nginx/access.log", "pattern": "\" 5\\d\\d ", "pattern_type": "regex" }alert_rules entry){ "metric": "log_error_rate", "log_search": "nginx_5xx", "operator": "gt", "threshold": 5, "duration_seconds": 120, "severity": "high" }4xx client errors
access logmediumAny 4xx client error (400, 401, 403, 404, 429…). Useful as a volume metric — a sudden 4xx spike often signals scanning or a broken deploy.
" 4\d\d 198.51.100.7 - - [10/Oct/2024:13:55:37 +0000] "GET /wp-admin HTTP/1.1" 404 153 "-" "Mozilla/5.0"log_searches entry){ "name": "nginx_4xx", "source": "file", "path": "/var/log/nginx/access.log", "pattern": "\" 4\\d\\d ", "pattern_type": "regex" }alert_rules entry){ "metric": "log_match_rate", "log_search": "nginx_4xx", "operator": "gt", "threshold": 100, "duration_seconds": 300, "severity": "medium" }Specific status codes (502 / 504)
access logcriticalBad-gateway (502) and gateway-timeout (504) responses specifically — the two codes that almost always mean the upstream/app server is down or too slow.
" 50[24] 192.0.2.10 - - [10/Oct/2024:13:55:38 +0000] "POST /checkout HTTP/1.1" 504 0 "-" "Mozilla/5.0"log_searches entry){ "name": "nginx_502_504", "source": "file", "path": "/var/log/nginx/access.log", "pattern": "\" 50[24] ", "pattern_type": "regex" }alert_rules entry){ "metric": "log_match_count", "log_search": "nginx_502_504", "operator": "gt", "threshold": 0, "duration_seconds": 0, "severity": "critical" }Slow upstream responses
access loghighRequests where $upstream_response_time (logged as urt="…") is roughly 0.5s or longer. Requires a custom log_format that includes urt="$upstream_response_time".
urt="(?:[1-9]\d*\.\d+|\d+\.[5-9]\d*)"192.0.2.10 - - [10/Oct/2024:13:55:39 +0000] "GET /report HTTP/1.1" 200 8123 "-" "Mozilla/5.0" rt=2.512 uct="0.001" uht="2.500" urt="2.500"log_searches entry){ "name": "nginx_slow_upstream", "source": "file", "path": "/var/log/nginx/access.log", "pattern": "urt=\"(?:[1-9]\\d*\\.\\d+|\\d+\\.[5-9]\\d*)\"", "pattern_type": "regex" }alert_rules entry){ "metric": "log_match_rate", "log_search": "nginx_slow_upstream", "operator": "gt", "threshold": 10, "duration_seconds": 120, "severity": "high" }Requests to a specific path (/login)
access logmediumHits on a sensitive path such as /login. Swap the path to monitor /admin, /api/keys, etc. Pair with a status filter to count failed logins.
"(?:GET|POST) /login(?:[ ?])203.0.113.5 - - [10/Oct/2024:13:55:40 +0000] "POST /login HTTP/1.1" 401 12 "-" "python-requests/2.31"log_searches entry){ "name": "nginx_path_login", "source": "file", "path": "/var/log/nginx/access.log", "pattern": "\"(?:GET|POST) /login(?:[ ?])", "pattern_type": "regex" }alert_rules entry){ "metric": "log_match_count", "log_search": "nginx_path_login", "operator": "gt", "threshold": 50, "duration_seconds": 60, "severity": "medium" }Large response bodies (>1 MB)
access loglowResponses whose $body_bytes_sent is 7+ digits (≥1,000,000 bytes ≈ 1 MB). Helps spot accidental full-table exports or unthrottled downloads.
" [1-5]\d\d \d{7,} 192.0.2.10 - - [10/Oct/2024:13:55:41 +0000] "GET /export.csv HTTP/1.1" 200 5242880 "-" "Mozilla/5.0"log_searches entry){ "name": "nginx_large_body", "source": "file", "path": "/var/log/nginx/access.log", "pattern": "\" [1-5]\\d\\d \\d{7,} ", "pattern_type": "regex" }alert_rules entry){ "metric": "log_match_rate", "log_search": "nginx_large_body", "operator": "gt", "threshold": 20, "duration_seconds": 300, "severity": "low" }Bot / scanner user-agents
access loghighCommon scanner and automated-client user-agent strings. Tune the list to your environment — legitimate tooling (curl) may appear too.
(?:sqlmap|nikto|nmap|masscan|nuclei|acunetix|wpscan|dirbuster|gobuster|zgrab|censys|curl|python-requests|Go-http-client)198.51.100.7 - - [10/Oct/2024:13:55:42 +0000] "GET /?id=1%27 HTTP/1.1" 403 0 "-" "sqlmap/1.8#stable (https://sqlmap.org)"log_searches entry){ "name": "nginx_bots_scanners", "source": "file", "path": "/var/log/nginx/access.log", "pattern": "(?:sqlmap|nikto|nmap|masscan|nuclei|acunetix|wpscan|dirbuster|gobuster|zgrab|censys|python-requests|Go-http-client)", "pattern_type": "regex" }alert_rules entry){ "metric": "log_match_count", "log_search": "nginx_bots_scanners", "operator": "gt", "threshold": 5, "duration_seconds": 60, "severity": "high" }Upstream timed out
error loghighThe classic "upstream timed out" error — nginx gave up waiting for the backend (proxy_read_timeout / proxy_connect_timeout exceeded). Frequently precedes 504s.
upstream timed out \(110: (?:Connection timed out|Unknown error)\)2024/10/10 13:55:43 [error] 1234#1234: *890 upstream timed out (110: Connection timed out) while reading response header from upstream, client: 192.0.2.10, server: example.com, request: "GET /slow HTTP/1.1", upstream: "http://127.0.0.1:9000/slow"log_searches entry){ "name": "nginx_upstream_timeout", "source": "file", "path": "/var/log/nginx/error.log", "pattern": "upstream timed out \\(110: ", "pattern_type": "regex" }alert_rules entry){ "metric": "log_match_count", "log_search": "nginx_upstream_timeout", "operator": "gt", "threshold": 0, "duration_seconds": 60, "severity": "high" }Connection refused (upstream down)
error logcriticalnginx could not open a connection to the upstream — the backend process is not listening on the configured address/port. Usually means the app crashed or was never started.
connect\(\) failed \(111: Connection refused\)2024/10/10 13:55:44 [error] 1234#1234: *891 connect() failed (111: Connection refused) while connecting to upstream, client: 192.0.2.10, server: example.com, request: "GET /api HTTP/1.1", upstream: "http://127.0.0.1:9000/api"log_searches entry){ "name": "nginx_conn_refused", "source": "file", "path": "/var/log/nginx/error.log", "pattern": "connect\\(\\) failed \\(111: Connection refused\\)", "pattern_type": "regex" }alert_rules entry){ "metric": "log_match_count", "log_search": "nginx_conn_refused", "operator": "gt", "threshold": 0, "duration_seconds": 0, "severity": "critical" }worker_connections are not enough
error logcriticalnginx ran out of worker connections — raise the worker_connections directive (and the OS file-descriptor limit). New clients are being dropped while this fires.
worker_connections are not enough2024/10/10 13:55:45 [alert] 1234#1234: *892 worker_connections are not enough while connecting to upstream, client: 192.0.2.10, server: example.com, request: "GET / HTTP/1.1"log_searches entry){ "name": "nginx_worker_connections", "source": "file", "path": "/var/log/nginx/error.log", "pattern": "worker_connections are not enough", "pattern_type": "contains" }alert_rules entry){ "metric": "log_match_count", "log_search": "nginx_worker_connections", "operator": "gt", "threshold": 0, "duration_seconds": 0, "severity": "critical" }SSL handshake errors
error logmediumA TLS handshake failed (bad cipher, unsupported protocol version, client abort, or a non-HTTPS request hitting an HTTPS port). A trickle is normal; a spike signals a scanner or misconfigured client.
SSL_do_handshake\(\) failed2024/10/10 13:55:46 [info] 1234#1234: *893 SSL_do_handshake() failed (SSL: error:0A00006C:SSL routines::bad key share) while SSL handshaking, client: 198.51.100.7, server: 0.0.0.0:443log_searches entry){ "name": "nginx_ssl_handshake", "source": "file", "path": "/var/log/nginx/error.log", "pattern": "SSL_do_handshake\\(\\) failed", "pattern_type": "regex" }alert_rules entry){ "metric": "log_match_rate", "log_search": "nginx_ssl_handshake", "operator": "gt", "threshold": 30, "duration_seconds": 120, "severity": "medium" }Rate limiting (limiting requests)
error logmediumThe limit_req module is throttling clients. Each line names the zone and the excess rate. A high volume means your rate limit is biting (DoS, scraping, or a too-tight limit).
limiting requests, excess: [\d.]+ by zone2024/10/10 13:55:47 [error] 1234#1234: *894 limiting requests, excess: 5.300 by zone "one", client: 203.0.113.5, server: example.com, request: "GET /api HTTP/1.1", host: "example.com"log_searches entry){ "name": "nginx_rate_limit", "source": "file", "path": "/var/log/nginx/error.log", "pattern": "limiting requests, excess:", "pattern_type": "contains" }alert_rules entry){ "metric": "log_match_rate", "log_search": "nginx_rate_limit", "operator": "gt", "threshold": 50, "duration_seconds": 120, "severity": "medium" }All error-level and worse
error loghighEvery error log line at severity error or higher. A broad catch-all for an "is anything broken?" volume metric across the whole error log.
\[(?:error|crit|alert|emerg)\]2024/10/10 13:55:48 [crit] 1234#1234: *895 SSL_write() failed while sending response to client, client: 192.0.2.10, server: example.comlog_searches entry){ "name": "nginx_all_errors", "source": "file", "path": "/var/log/nginx/error.log", "pattern": "\\[(?:error|crit|alert|emerg)\\]", "pattern_type": "regex" }alert_rules entry){ "metric": "log_match_rate", "log_search": "nginx_all_errors", "operator": "gt", "threshold": 20, "duration_seconds": 120, "severity": "high" }No live upstreams
error logcriticalEvery server in an upstream {} pool is marked down — nginx has no healthy backend to forward to. Almost always a full backend outage; emits 502s to clients.
no live upstreams while connecting to upstream2024/10/10 13:55:49 [error] 1234#1234: *896 no live upstreams while connecting to upstream, client: 192.0.2.10, server: example.com, request: "GET /api HTTP/1.1", upstream: "http://backend/api", host: "example.com"log_searches entry){ "name": "nginx_no_live_upstreams", "source": "file", "path": "/var/log/nginx/error.log", "pattern": "no live upstreams", "pattern_type": "contains" }alert_rules entry){ "metric": "log_match_count", "log_search": "nginx_no_live_upstreams", "operator": "gt", "threshold": 0, "duration_seconds": 0, "severity": "critical" }Too many open files
error logcriticalThe worker hit its file-descriptor limit (errno 24). Raise worker_rlimit_nofile and the systemd/ulimit LimitNOFILE. Connections and upstreams fail while this fires.
\(24: Too many open files\)2024/10/10 13:55:50 [crit] 1234#1234: *897 accept4() failed (24: Too many open files)log_searches entry){ "name": "nginx_too_many_files", "source": "file", "path": "/var/log/nginx/error.log", "pattern": "\\(24: Too many open files\\)", "pattern_type": "regex" }alert_rules entry){ "metric": "log_match_count", "log_search": "nginx_too_many_files", "operator": "gt", "threshold": 0, "duration_seconds": 0, "severity": "critical" }Paste & test
Paste sample log lines below and pick a pattern; matches are highlighted live in your browser.
/" 5\d\d /gNo log lines yet — paste some above or click “Load example log lines.”
Turning a pattern into a monitor
The Alert24 server agent can tail these log files and report match counts on every heartbeat, so the alert-rule engine can threshold on them (e.g. “page me if the 5xx error rate exceeds 5% for 2 minutes”). Each pattern card above includes a log_searches entry; drop it into your agent config alongside metrics, services, and alert_rules.
Add the alert_rules entry to the existing "alert_rules" array in the same agent config. log_match_count = matches in the interval; log_match_rate = matches/min; log_error_rate = % of lines matching (great for the 5xx pattern). Rate metrics need a non-zero interval_seconds on the heartbeat.
log_searches are simply ignored.Get alerted when your logs go wrong
Alert24’s lightweight agent watches your log files where they live and alerts on error spikes, pattern matches, log floods, and sudden silence — no log shipping, no SIEM bill, no per-GB ingest pricing.
Try Alert24 log monitoringReady to take this to the next level?
Our team can help implement enterprise-grade solutions. Get personalized recommendations in a free 30-minute consultation.
Reading Nginx Logs
Nginx writes two logs. The access log records one line per HTTP request using a configurable log_format (the default is the predefined combined format). The error log records diagnostics — failed upstream connections, timeouts, TLS handshake failures, and resource limits — in a fixed structure whose verbosity is controlled by the level argument to error_log. Most incident triage starts by correlating a status-code spike in the access log with the matching cause in the error log.
Access Log vs. Error Log
| Aspect | Access log | Error log |
|---|---|---|
| Written by | ngx_http_log_module | core (ngx_core_module) |
| Format | Configurable (log_format) | Fixed: date time [level] pid#tid: *conn message |
| One line per | Completed request | Diagnostic event |
| Best for | Status codes, traffic, timing, bots | Root cause: timeouts, refused connections, TLS, limits |
From grep to Continuous Alerting
Grepping a regex over a log file answers “what happened?” once. To answer “is it happening right now?” you need the same pattern evaluated continuously and thresholded over time. That is what the Alert24 server-agent log_searches config blocks in each pattern card do: the agent tails the file, counts new matches each interval, and the alert-rule engine fires when log_match_count, log_match_rate, or log_error_rate crosses your threshold.
Frequently Asked Questions
Common questions about the Nginx Log Analyzer & Pattern Reference
By default nginx writes the access log using the predefined "combined" format: $remote_addr - $remote_user [$time_local] "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent". That is client IP, identd (almost always "-"), Basic-auth user, local timestamp, the full request line, the HTTP status code, response body size in bytes, the Referer header, and the User-Agent header.
On Debian/Ubuntu and RHEL/CentOS packages the defaults are /var/log/nginx/access.log and /var/log/nginx/error.log. When nginx is compiled from source with the default prefix they live under /usr/local/nginx/logs/. The exact paths are set by the access_log and error_log directives in /etc/nginx/nginx.conf (or files it includes).
From least to most severe: debug, info, notice, warn, error, crit, alert, emerg. The second argument to the error_log directive sets the minimum level, and selecting a level logs that level plus all more severe ones. "error" is the default. Production alerting usually watches error and above (error, crit, alert, emerg).
In the access log, the status code is the field right after the quoted request line, so a regex like " 50[24] " matches 502 (Bad Gateway) and 504 (Gateway Timeout) responses. The error log usually explains the cause: "connect() failed (111: Connection refused)" or "no live upstreams" tends to produce 502s, while "upstream timed out (110: ...)" produces 504s.
It means nginx waited longer than the configured timeout (proxy_connect_timeout, proxy_read_timeout, or proxy_send_timeout) for the backend and gave up, returning 504 to the client. It signals a slow or overloaded upstream. The fix is either to speed up the backend or, if the slowness is legitimate, raise the relevant timeout.
Add upstream timing variables to a custom log_format, e.g. urt="$upstream_response_time" (and optionally uct="$upstream_connect_time" and uht="$upstream_header_time"). Then a regex can flag lines where that value crosses a threshold. This tool includes a slow-upstream pattern that matches urt values of roughly 0.5 seconds or more.
Declare a named format with the log_format directive inside the http {} block, then reference that name on an access_log directive at the http, server, or location level — for example: access_log /var/log/nginx/access.log timed_combined;. Custom formats are how you add request timing, upstream timing, or request IDs to your logs.
Yes. The matcher compiles the selected regex and highlights matches entirely in your browser using the JavaScript regex engine. Nothing you paste is uploaded, transmitted, or stored — there is no server-side processing and no analytics on the log content itself.
Each pattern card includes a ready-to-paste Alert24 server-agent log_searches entry that tails the relevant log file and reports match counts on every heartbeat, plus a matching alert_rules example (log_match_count, log_match_rate, or log_error_rate). Log-search monitoring is a paid Alert24 feature; every plan includes 3 server agents free, and paid plans add 5 agents per subscription unit.
Explore More Tools
Continue with these related tools
Related External Resources
Additional tools from our partner sites
ℹ️ Disclaimer
This tool is provided for informational and educational purposes only. All processing happens entirely in your browser - no data is sent to or stored on our servers. While we strive for accuracy, we make no warranties about the completeness or reliability of results. Use at your own discretion.