Tutorials

NGINX Logs Explained: Access and Error Log Guide

Logs are very useful to monitor activities of any application apart from providing you with valuable information while you troubleshoot it. Like any other application, NGINX also records events like visitors to your site, issues it encountered and more to log files. This information enables you to take preemptive measures in case you notice some serious discrepancies in the log events. This article will guide you in details about how to configure NGINX logging so that you have a better insight into its activities.

By default, NGINX writes its events in two types of logs – the error log and the access log. In most of the popular Linux distro like Ubuntu, CentOS or Debian, both the access and error log can be found in /var/log/nginx, assuming you have already enabled the access and error logs in the core NGINX configuration file. Let us find out more about NGINX access log, error log and how to enable them if you have not done it earlier.

The NGINX logs the activities of all the visitors to your site in the access logs. Here you can find which files are accessed, how NGINX responded to a request, what browser a client is using, IP address of clients and more. It is possible to use the information from the access log to analyze the traffic to find sites usages over time. Further, by monitoring the access logs properly, one can find out if a user is sending some unusual request for finding flaws in the deployed web application.

On the other hand, if NGINX encounters any issues or glitches, it records these events in the error log. This can happen, for example, if there is a mistake in your configuration file. If NGINX is unable to start or suddenly stops running, checking the error logs will help you find more details about the problem. You may also notice warnings in the error log—while these do not always indicate an immediate problem, they can signal issues that might become serious later. For a step-by-step approach to diagnosing and resolving common NGINX errors using the error log, see our guide about How To Troubleshoot Common NGINX Errors.

In general, the access log can be enabled with access_log directive either in http or in server section. The first argument log_file is mandatory whereas the second argument log_format is optional. If you don’t specify any format then logs will be written in default combined format.

access_log log_file log_format;

The access log is enabled by default in the http context of core NGINX configuration file. That means access log of all the virtual host will be recorded in the same file.

http { … … access_log /var/log/nginx/access.log; … … }

It is always better to segregate the access logs of all the virtual hosts by recording them in a separate file. To do that, you need to override the access_log directive that is defined in the http section with another access_log directive in the server context.

http { … … access_log /var/log/nginx/access.log; server { listen 80; server_name domain1.com access_log /var/log/nginx/domain1.access.log; … … } }

Reload NGINX to apply the new settings. To view the access logs for the domain domain1.com in the file /var/log/nginx/domain1.access.log, use the following tail command in the terminal.

The default log format used to record an event in the access log is combined log format. You can override the default behavior by creating your own custom log format and then specify the name of the custom format in the access_log directive. The following example defines a custom log format by extending the predefined combined format with the value of gzip compression ratio of the response. The format is then applied by indicating the log format with the access_log directive.

http { log_format custom ‘$remote_addr – $remote_user [$time_local] ‘ ‘”$request” $status $body_bytes_sent ‘ ‘”$http_referer” “$http_user_agent” “$gzip_ratio”‘; server { gzip on; … access_log /var/log/nginx/domain1.access.log custom; … } }

Once you have applied above log format in your environment, reload NGINX. Now tail the access log to find the gzip ratio at the end of the log event.

47.29.201.179 – – [28/Feb/2019:13:17:10 +0000] “GET /?p=1 HTTP/2.0” 200 5316 “https://domain1.com/?p=1” “Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.119 Safari/537.36” “2.75”

The error_log directive sets up error logging to file or stderr, or syslog by specifying minimal severity level of error messages to be logged. The syntax of error_log directive is:

error_log log_file log_level;

The first argument log_file defines the path of the log file and the second argument log_level defines the severity level of the log event to be recorded. If you don’t specify the log_level then by default, only log events with a severity level of error are recorded. For example, the following example sets the severity level of error messages to be logged to crit. Further, the error_log directive in the http context implies that the error log for all the virtual host will be available in a single file.

http { … error_log /var/log/nginx/error_log crit; … }

It is also possible to record error logs for all the virtual host separately by overriding the error_log directive in the server context. The following example exactly does that by overriding error_log directive in the server context.

http { … … error_log /var/log/nginx/error_log; server { listen 80; server_name domain1.com; error_log /var/log/nginx/domain1.error_log warn; … } server { listen 80; server_name domain2.com; error_log /var/log/nginx/domain2.error_log debug; … } }

All the examples described above records the log events to a file. You can also configure the error_log directive for sending the log events to a syslog server. The following error_log directive sends the error logs to syslog server with an IP address of 192.168.10.11 in debug format.

error_log syslog:server=192.168.10.11 debug;

In some situation, you might want to disable the error log. To do that, set the log file name to /dev/null.

error_log /dev/null;

There are many types of log levels that are associated with a log event and with a different priority. All the log levels are listed below. In the following log levels, debug has top priority and includes the rest of the levels too. For example, if you specify error as a log level, then it will also capture log events those are labeled as crit, alert and emergency.

  1. emerg: Emergency messages when your system may be unstable.
  2. alert: Alert messages of serious issues.
  3. crit: Critical issues that need to be taken care of immediately.
  4. error: An error has occured. Something went wrong while processing a page.
  5. warn: A warning messages that you should look into it.
  6. notice: A simple log notice that you can ignore.
  7. info: Just an information messages that you might want to know.
  8. debug: Debugging information used to pinpoint the location of error.

NGINX allows you to control the verbosity of error logging through severity levels. You can change the error_log directive to include different levels based on your debugging needs. For instance, during development or while troubleshooting issues, setting the log level to debug provides extensive output that includes request handling, configuration parsing, and module interactions.

To increase the verbosity, adjust your configuration as shown:

error_log /var/log/nginx/error.log debug;

After making this change, reload NGINX:

sudo systemctl reload nginx

In production systems, it’s common to set the log level to warn or error to reduce verbosity and limit disk usage. These levels capture only actionable errors and avoid flooding logs with benign details. However, during critical incidents or for tracing subtle bugs, switching temporarily to info or debug can provide granular visibility.

Advanced configurations may also involve using conditional logging based on variables, or configuring different log levels per virtual host. For example, you can log general traffic at the warn level and log suspicious or sensitive routes at info or debug levels selectively using multiple error_log directives in separate contexts.

For even finer control, enable debug logging for specific connections using the debug_connection directive in the events block:

events { debug_connection 192.168.1.100; }

This limits debug output to trusted clients only and is especially useful when troubleshooting behind a NAT or reverse proxy.

NGINX logs are instrumental in identifying potential bottlenecks and suspicious behavior on your server. For example, you can detect high-latency endpoints by filtering access logs for long response times using custom log formats. You might also discover IPs attempting brute-force attacks or scanning for vulnerabilities by analyzing request patterns and status codes like 403, 404, or 500.

A basic approach includes:

  • Analyze status codes to find unusual spikes in errors.
  • Track IP addresses that generate large amounts of traffic or repeated failed requests.
  • Check user-agents to identify bots.
  • Review referer headers to detect traffic redirection from suspicious domains.
  • Compare $request_time and $upstream_response_time to isolate slow backends or database latency.

Example of a custom log format for performance tuning:

log_format perf_monitor ‘$remote_addr [$time_local] “$request” $status ‘ ‘$request_time $upstream_response_time’;

Use command-line tools like awk, cut, or grep to sort and analyze slow requests:

awk ‘{print $NF}’ /var/log/nginx/access.log | sort -nr | head -n 20

Security auditing can be further enhanced by scripting log parsers to:

  • Count failed login attempts to /admin, /login, /wp-login.php
  • Detect repetitive hits to non-existent URLs (probing)
  • Flag unusual user-agent strings (e.g., “curl”, “sqlmap”)
  • Visualize access trends using tools like GoAccess or Grafana

To gain deeper insights and automate log management, you can integrate NGINX logs with industry-standard monitoring tools:

Logrotate (for rotation and cleanup)

Use logrotate to manage file sizes and prevent disk bloat. Proper rotation prevents uncontrolled disk consumption, ensures long-term availability of logs, and complies with audit policies. A solid logrotate config for NGINX might look like this:

/var/log/nginx/*.log { daily missingok rotate 14 compress delaycompress notifempty create 0640 www-data adm sharedscripts postrotate systemctl reload nginx > /dev/null 2>/dev/null || true endscript }

Enable email alerts on failure by appending a mail directive, or logrotate status for audits in /var/lib/logrotate/status.

ELK Stack (for centralized log analysis)

The ELK Stack (Elasticsearch, Logstash, Kibana) is widely used for ingesting, storing, and visualizing logs.

  • Filebeat: Lightweight agent to collect NGINX logs and forward them.
  • Logstash: Use grok patterns to parse logs and extract fields.
  • Elasticsearch: Stores logs in an indexed format, enabling real-time queries.
  • Kibana: Dashboard for trend analysis, anomaly detection, and drill-downs.

A typical pipeline:

Filebeat (NGINX host) → Logstash → Elasticsearch → Kibana

This setup can identify 5xx spikes, map geo-IP traffic, correlate latency with specific routes, and visualize traffic by country or browser.

Better Stack, Datadog, and Loki

These tools offer fast deployment and managed dashboards:

  • Better Stack: Visual alerting, Slack integration, retention policies, uptime monitoring
  • Datadog Logs: Full-text search, monitors, role-based access, APM correlation
  • Grafana Loki: Scalable, Prometheus-aligned log aggregation—ideal for cloud-native environments

Enable remote syslog logging to ship logs from NGINX directly:

access_log syslog:server=192.168.0.10:514,tag=nginx_access; error_log syslog:server=192.168.0.10:514,tag=nginx_error;

For secure cloud log shipping, prefer TLS-secured outputs or HTTP API ingestion (e.g., via Fluentd or Vector).

Understanding the meaning of each variable in a log entry helps with debugging and analysis. A sample access log entry looks like this:

192.168.0.1 – – [10/May/2025:13:00:00 +0000] “GET /index.html HTTP/1.1” 200 1024 “-” “Mozilla/5.0”

Here’s a breakdown:

  • $remote_addr: IP address of the client.
  • $remote_user: Authenticated user (if any).
  • $time_local: Timestamp of the request.
  • $request: Full HTTP request line.
  • $status: HTTP response status code.
  • $body_bytes_sent: Size of the response body.
  • $http_referer: The page that linked to the requested resource.
  • $http_user_agent: Browser or bot used.
  • $request_time: Time taken to process the request on the NGINX side.
  • $upstream_response_time: Time taken for the upstream server (backend/API) to respond.
  • $host: Host header sent by the client.
  • $http_x_forwarded_for: IP forwarded by proxy servers (useful behind load balancers).
  • $scheme: Protocol used (http or https).
  • $request_length: Size of the incoming request from the client.
  • $connection_requests: Number of requests made over a keepalive connection.

These variables can be combined into complex formats, used in custom log parsers, or ingested into centralized SIEM platforms for security correlation and behavioral analytics.

1. Where are NGINX access and error logs stored?

By default, NGINX stores its logs in the /var/log/nginx/ directory on Linux-based systems. The two primary log files are access.log and error.log, which record incoming traffic and server-side errors, respectively. You can verify the exact log file paths by checking the access_log and error_log directives in your NGINX configuration (usually found at /etc/nginx/nginx.conf or inside /etc/nginx/sites-enabled/). On macOS with Homebrew, logs may be located at /usr/local/var/log/nginx/. These default paths can be customized in your server or HTTP blocks.

2. How can I change the NGINX log format?

To change the log format in NGINX, use the log_format directive inside the http block of your config file. You can define a custom format by specifying variables like $remote_addr, $status, $request_time, and others. Once defined, assign the format to an access log like so: access_log /var/log/nginx/custom_access.log custom_format;. Custom formats help you capture additional context such as compression ratio, upstream time, or cookies for deeper analysis. Don’t forget to reload NGINX (sudo systemctl reload nginx) after making changes.

3. What are the error log levels in NGINX?

NGINX error logs support several severity levels that control the verbosity of logging:

  • debug: Maximum detail, useful for troubleshooting

  • info and notice: Informational messages

  • warn: Warnings that don’t halt execution

  • error: Common errors preventing processing

  • crit, alert, emerg: Critical system-level issues

Each level includes messages of higher severity. For example, error will log crit, alert, and emerg too. You can set the desired level in your config using error_log /path/to/error.log warn;.

4. Can I monitor NGINX logs in real-time?

Yes, NGINX logs can be monitored in real-time using the tail command. For example, tail -f /var/log/nginx/access.log will continuously stream access log entries as they’re written. Tools like multitail or less +F provide enhanced viewing capabilities. For more advanced setups, you can integrate real-time log monitoring with centralized logging platforms such as ELK Stack, Graylog, or BetterStack, enabling alerts, dashboards, and search across multiple servers.

5. How do I disable NGINX logging for specific files or routes?

You can disable logging in NGINX by using access_log off; and error_log /dev/null; within a specific location block. This is useful for static assets (like CSS, JS, images) that don’t require logging. Example:

location /static/ { access_log off; error_log /dev/null crit; }

This reduces disk usage and makes logs cleaner by removing repetitive, low-value entries.

6. What is the combined log format in NGINX?

The combined log format is the default format used in NGINX access logs. It includes information like client IP, timestamp, HTTP method, URI, response status, and user agent. Here’s a typical example:

192.168.1.1 – – [22/May/2025:10:55:22 +0000] “GET /index.html HTTP/1.1” 200 2326 “http://referrer.com” “Mozilla/5.0”

This format is helpful for basic analysis and compatibility with most log parsers. You can extend it using the log_format directive.

7. How do I enable debugging logs in NGINX?

To enable debugging logs, set the error_log directive to a log file and assign it the debug level. Example:

error_log /var/log/nginx/error.log debug;

You must also compile NGINX with the –with-debug flag or enable debugging in specific modules using debug_connection. Be cautious, as debug logging can be very verbose and consume significant disk space. It’s best used temporarily during troubleshooting.

8. Can I send NGINX logs to a remote server?

Yes, NGINX can send error logs to a remote syslog server using the syslog: protocol. Example:

error_log syslog:server=192.168.1.100:514,facility=local7,tag=nginx warn;

However, access logs do not natively support syslog. For access logs, use log shipping agents like Filebeat, Fluentd, or Vector to forward entries to centralized systems like ELK, Graylog, or BetterStack. This enables scalable log aggregation across multiple nodes.

9. How do I rotate NGINX logs?

NGINX logs are not rotated automatically. Use a tool like logrotate on Linux to manage them. Add a config file under /etc/logrotate.d/nginx with directives like:

/var/log/nginx/*.log { daily missingok rotate 14 compress delaycompress notifempty create 0640 www-data adm sharedscripts postrotate [ -f /var/run/nginx.pid ] && kill -USR1`cat /var/run/nginx.pid endscript }

This setup rotates logs daily, compresses them, and gracefully signals NGINX to start writing to a new file.

10. How can I identify security issues using NGINX logs?

NGINX logs can reveal signs of brute-force attacks, path traversal, and probing attempts. For example:

  • Multiple failed login attempts from the same IP

  • Unusual HTTP methods like PUT or DELETE

  • Requests to /wp-admin or /phpmyadmin on non-CMS sites

  • High volume of 404s or 5xx errors

By leveraging log analysis tools such as GoAccess or AWStats, or by integrating your NGINX logs with security platforms, you can automatically detect suspicious patterns and respond to potential threats. Regularly reviewing your logs is essential for maintaining server security. Additionally, securing your NGINX instance with SSL/TLS is a key step in protecting against common attacks. For a step-by-step guide on setting up SSL with Let’s Encrypt, see our tutorial on How to Secure NGINX with Let’s Encrypt on Ubuntu 20.04.

NGINX access and error logs are essential for monitoring user activity and streamlining the debugging process. You can also customize the access log format to capture additional details as needed. Enabling both access and error logs is highly recommended, as they provide valuable insights for maintaining and troubleshooting your NGINX server. If you’re planning to scale your infrastructure, check out our guide on how to set up NGINX load balancing.

Leave a Reply

Your email address will not be published. Required fields are marked *

Back to top button