By Meghna Gangwar and Vinayak Baranwal
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.
# tail -f /var/log/nginx/domain1.access.log
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.
# tail -f /var/log/nginx/domain1.access.log
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.
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:
$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:
/admin
, /login
, /wp-login.php
GoAccess
or Grafana
To gain deeper insights and automate log management, you can integrate NGINX logs with industry-standard monitoring tools:
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
.
The ELK Stack (Elasticsearch, Logstash, Kibana) is widely used for ingesting, storing, and visualizing logs.
grok
patterns to parse logs and extract fields.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.
These tools offer fast deployment and managed dashboards:
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.
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.
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.
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;
.
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.
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.
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.
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.
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.
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.
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.
Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.
Building future-ready infrastructure with Linux, Cloud, and DevOps. Full Stack Developer & System Administrator @ DigitalOcean | GitHub Contributor | Passionate about Docker, PostgreSQL, and Open Source | Exploring NLP & AI-TensorFlow | Nailed over 50+ deployments across production environments.
Get paid to write technical tutorials and select a tech-focused charity to receive a matching donation.
Full documentation for every DigitalOcean product.
The Wave has everything you need to know about building a business, from raising funding to marketing your product.
Stay up to date by signing up for DigitalOcean’s Infrastructure as a Newsletter.
New accounts only. By submitting your email you agree to our Privacy Policy
Scale up as you grow — whether you're running one virtual machine or ten thousand.
Sign up and get $200 in credit for your first 60 days with DigitalOcean.*
*This promotional offer applies to new accounts only.