Configuring logging in Nginx on Ubuntu is essential for monitoring server performance, troubleshooting errors, and ensuring security. Whether you’re dealing with high-traffic websites or simple applications, knowing how to configure Nginx logging Ubuntu setups allows you to capture critical data without overwhelming your system. This comprehensive tutorial walks you through setting up access and error logs, implementing log rotation to manage disk space, and applying advanced configurations for optimal observability.

In today’s digital landscape, where websites handle millions of requests daily, improper logging can lead to undetected issues or disk exhaustion. According to Nginx’s official documentation, effective logging helps identify traffic patterns, security threats, and performance bottlenecks. 

This guide, validated on Ubuntu 22.04 LTS with the stable Nginx release, provides step-by-step instructions to configure Nginx logging Ubuntu environments securely and efficiently. By the end, you’ll have a production-ready setup that balances detail with performance.

Introduction

Nginx logs provide the data you need to troubleshoot failures, analyse traffic, and verify application behaviour. Without a proper logging setup, diagnosing production issues becomes guesswork. This tutorial shows you how to configure Nginx logging Ubuntu, set up log rotation to prevent disk exhaustion, and verify your configuration with real commands.

By default, Nginx stores logs in /var/log/nginx/ and uses the logrotate utility to manage log files automatically. You’ll use an Ubuntu virtual private server as an example, but the configuration applies to any modern Linux distribution running Nginx. This tutorial was last validated on Ubuntu 22.04 LTS with the Ubuntu-packaged Nginx stable release.

To configure Nginx logging Ubuntu effectively, start with understanding the basics: access logs track every request, while error logs capture diagnostics. We’ll cover custom formats, buffering for high traffic, and conditional logging to reduce noise. Whether you’re a beginner or experienced sysadmin, these steps ensure your logs are actionable and manageable.

Key Takeaways

  • Nginx uses two primary log types: access logs for request visibility and error logs for operational diagnostics.
  • Choose error log levels deliberately: warn is a practical default for production observability, while error minimizes noise; reserve debug only for short-term troubleshooting.
  • Log rotation is mandatory on production servers: Ubuntu’s logrotate prevents uncontrolled disk growth and enables long-term retention.
  • Custom log formats improve observability: JSON logs simplify ingestion into centralised logging platforms such as Elasticsearch and Datadog.
  • Buffered logging reduces I/O overhead: enabling buffer=32k is recommended for high-traffic environments.
  • Always validate before reloads: use nginx -t to prevent configuration errors from causing downtime.
  • Conditional logging reduces noise: exclude health checks and static assets to keep logs focused on actionable traffic.
  • Separate logs per site for clarity: per-domain log files simplify debugging and incident response.
  • Monitor disk usage proactively: alert on log partitions before they exceed safe capacity thresholds.
  • Centralised logging is essential at scale: multi-server deployments should aggregate logs using syslog or log shipping agents.

These takeaways highlight why learning to configure Nginx logging Ubuntu is crucial for maintaining reliable servers.

Quick Reference

Use this cheat sheet to validate changes quickly when you configure Nginx logging Ubuntu:

  • Logs directory: /var/log/nginx/
  • Access log: /var/log/nginx/access.log
  • Error log: /var/log/nginx/error.log
  • PID file: /run/nginx.pid
  • Test config: sudo nginx -t
  • Reload Nginx: sudo systemctl reload nginx
  • Dry-run logrotate: sudo logrotate -d /etc/logrotate.d/nginx
  • Force logrotate once: sudo logrotate -f /etc/logrotate.d/nginx

This reference saves time during troubleshooting and configuration adjustments.

Prerequisites

To follow this tutorial on how to configure Nginx logging Ubuntu, you will need:

  • One Ubuntu server running Ubuntu 22.04 LTS or later with a non-root sudo-enabled user and a firewall configured. Follow the Initial Server Setup with Ubuntu 22.04 guide from Progressive Robot to get started.
  • Nginx installed on the server. Follow the How to Install Nginx on Ubuntu 22.04 tutorial from Progressive Robot to install it.

With Nginx running on your Ubuntu server, you’re ready to begin.

Quick Baseline: Production-Friendly Logging

If you want a safe default you can deploy immediately when you configure Nginx logging Ubuntu, start here and refine later:

				
					# /etc/nginx/nginx.conf
# Place these inside the http { } block
error_log /var/log/nginx/error.log warn;
access_log /var/log/nginx/access.log combined buffer=32k;

map $request_uri $log_healthcheck {
    default 1;
    ~^/healthz$ 0;
}
				
			

Then apply per-site logging in your server {} block (commonly in /etc/nginx/sites-available/your_site):

				
					# /etc/nginx/sites-available/your_site
server {
    access_log /var/log/nginx/access.log combined if=$log_healthcheck;

    location = /healthz {
        access_log off;
        return 200;
    }
}
				
			

This configuration balances signal quality, disk I/O, and operational safety for most production Ubuntu deployments. It ensures health checks don’t clutter logs, while buffering minimizes performance hits.

Understanding Nginx Log Types

Nginx uses two main logs: access (for every request) and error (for diagnostics). Each serves a distinct purpose in monitoring and troubleshooting when you configure Nginx logging Ubuntu.

Where Logging Directives Belong

Use these placement rules to avoid unexpected overrides:

  • Use the http {} block for global defaults (log formats, default paths).
  • Use server {} blocks to separate logs per site or domain.
  • Use location {} blocks only for targeted overrides such as disabling logs for health checks or static assets.

Proper placement prevents conflicts and ensures consistent logging across your setup.

Nginx vs Apache: Logging at a Glance

If you’re used to Apache: Nginx error_log is analogous to Apache’s ErrorLog; Nginx access_log plus log_format is analogous to CustomLog and LogFormat. Both support conditional logging and rotation via external tools (e.g., logrotate). A practical difference is that Nginx does not rotate logs itself—you must use logrotate or a script and then signal Nginx (e.g., kill -USR1) to reopen files. Apache’s rotatelogs pipes logs to a rotating process; on Nginx you rely on the OS or logrotate to move/compress files and then signal the process.

This comparison helps Apache users transition to configure Nginx logging Ubuntu smoothly.

Access Logs

Access logs record every request processed by Nginx, including the client IP, request method, URI, response status code, bytes sent, user agent, and referrer. These logs are invaluable for:

  • Traffic trends: Identifying top endpoints, referrers, and status-code patterns.
  • Performance debugging: Spotting slow requests and bandwidth-heavy responses.
  • Security visibility: Detecting suspicious request patterns and abuse.

By default, Nginx writes access logs to /var/log/nginx/access.log using the combined log format, which captures comprehensive request data in a standardised format compatible with most log analysis tools. When you configure Nginx logging Ubuntu, starting with access logs provides immediate visibility into server activity.

To enable or customise access logging, edit /etc/nginx/nginx.conf or site-specific files. For example, to log in a custom path:

				
					access_log /var/log/nginx/my_site_access.log combined;
				
			

Test with sudo nginx -t and reload with sudo systemctl reload nginx. Access logs grow quickly on busy sites, so pair them with rotation (covered later).

Error Logs

Error logs capture diagnostic information when something goes wrong, from minor warnings to critical system failures. They include:

  • Server errors: Configuration problems, upstream failures, or resource exhaustion.
  • Client errors: Invalid requests, missing files (404s), or permission issues (403s).
  • System warnings: Non-critical issues that might indicate future problems.
  • Debug information: Detailed traces when troubleshooting specific issues.

Error logs are written to /var/log/nginx/error.log by default and use severity levels (debug, info, notice, warn, error, crit, alert, emerg) to categorise messages. To configure Nginx logging Ubuntu for errors, set the level appropriately to avoid overwhelming your logs.

For instance, use warn for production to catch issues early without excessive noise.

Log Location and Permissions

On Ubuntu, Nginx logs are stored in /var/log/nginx/ by default and owned by the www-data user. The log directory requires proper permissions:

				
					ls -la /var/log/nginx/
				
			

Expected output:

				
					total 12
drwxr-x--- 2 www-data adm  4096 Feb  2 10:00 .
drwxrwxr-x 8 root     syslog 4096 Feb  2 09:45 ..
-rw-r----- 1 www-data adm     0 Feb  2 10:00 access.log
-rw-r----- 1 www-data adm     0 Feb  2 10:00 error.log
				
			

The adm group allows system administrators to read logs without root privileges. If you need to access logs as a regular user, add yourself to the adm group:

				
					sudo usermod -aG adm your_username
				
			

Note: You’ll need to log out and back in for group changes to take effect. Correct permissions are vital when you configure Nginx logging Ubuntu to ensure logs are writable by Nginx but secure.

Disk Space Considerations

Nginx logs can grow rapidly on busy servers. A single day of traffic on a moderately busy site might generate:

  • Access logs: 100-500 MB per day (varies with traffic).
  • Error logs: 10-50 MB per day (depends on error rate).

Without rotation, logs can consume gigabytes of disk space within weeks. The logrotate utility, covered later in this tutorial, automatically archives and compresses old logs to prevent disk space issues. When planning to configure Nginx logging Ubuntu, factor in storage: use df -h /var/log to monitor and set alerts for 80% usage.

Understanding the error_log Directive

The error_log directive controls where and at what level Nginx writes error and diagnostic messages. Set the path and level (for example, warn) in your config; if you’re familiar with Apache, it behaves like Apache’s ErrorLog.

error_log Syntax

The error_log directive applies the following syntax:

				
					# /etc/nginx/nginx.conf
error_log log_file log_level;
				
			

The log_file specifies the file where the logs will be written. The log_level specifies the lowest level of logging that you would like to record. This is a core step when you configure Nginx logging Ubuntu.

Logging Levels

The error_log directive can be configured to log more or less information as required. The level of logging can be any one of the following:

  • emerg: Emergency situations where the system is in an unusable state.
  • alert: Severe situations where action is needed promptly.
  • crit: Important problems that need to be addressed.
  • error: An error has occurred and something was unsuccessful.
  • warn: Something out of the ordinary happened, but is not a cause for concern.
  • notice: Something normal, but worth noting what has happened.
  • info: An informational message that might be nice to know.
  • debug: Debugging information that can be useful to pinpoint where a problem is occurring.

The levels higher on the list are considered a higher priority. If you specify a level, the log captures that level and any level higher than the specified level. For example, if you specify error, the log will capture messages labelled error, crit, alert, and emerg.

Performance Impact of Logging Levels

Different log levels have different performance implications:

  • warn (recommended for production): Minimal performance impact while preserving early warning signals such as upstream failures and configuration issues.
  • info and notice: Moderate performance impact, generates more I/O operations. Use when you need detailed operational visibility.
  • debug: Significant performance impact, generates extensive output. Only use for active troubleshooting, never leave enabled in production as it can slow your server and fill disk space rapidly.

To change the log level, edit your Nginx configuration. An example of this directive in use is inside the main configuration file. Use your preferred text editor to access the following configuration file. This example uses nano:

				
					sudo nano /etc/nginx/nginx.conf
				
			

Find the # Logging Settings section (usually in the lower part of the main block) and note the following directives:

				
					# /etc/nginx/nginx.conf
##
# Logging Settings
##
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
				
			

If you do not want the error_log to log anything, you must send the output into /dev/null:

				
					# /etc/nginx/nginx.conf
error_log /dev/null crit;
				
			

The other logging directive, access_log, will be discussed in the following section. Adjusting levels is key to optimising when you configure Nginx logging Ubuntu.

Understanding HttpLogModule Logging Directives

While the error_log directive is part of the core module, the access_log directive is part of the HttpLogModule. This provides the ability to customise the logs. There are a few other directives included with this module that assist in configuring custom logs.

log_format Directive

The log_format directive is used to describe the format of a log entry using plain text and variables. There is one format that comes predefined with Nginx called combined. This is a common format used by many servers.

The following is an example of the combined format if it was not defined internally and needed to be specified with the log_format directive:

				
					# /etc/nginx/nginx.conf
log_format combined '$remote_addr - $remote_user [$time_local]  '
      '"$request" $status $body_bytes_sent '
      '"$http_referer" "$http_user_agent"';
				
			

This definition spans multiple lines until it finds the semicolon (;). The lines beginning with a dollar sign ($) indicate variables, while the characters like -, [, and ] are interpreted literally.

The general syntax of the directive is:

				
					# /etc/nginx/nginx.conf
log_format format_name 'string_describing_formatting';
				
			

You can use variables supported by the core module to formulate your logging strings. Custom formats enhance analysis when you configure Nginx logging Ubuntu.

JSON Log Format for Modern Monitoring

For integration with modern log aggregation tools like Elasticsearch, Logstash, Grafana, or Datadog, you can configure Nginx to output logs in JSON format. This makes parsing and querying logs much easier.

Add this custom log format to the http block in /etc/nginx/nginx.conf:

				
					# /etc/nginx/nginx.conf
log_format json_combined escape=json
  '{'
    '"time_local":"$time_local",'
    '"remote_addr":"$remote_addr",'
    '"remote_user":"$remote_user",'
    '"request":"$request",'
    '"status": "$status",'
    '"body_bytes_sent":"$body_bytes_sent",'
    '"request_time":"$request_time",'
    '"http_referrer":"$http_referer",'
    '"http_user_agent":"$http_user_agent"'
  '}';
				
			

Then apply it to a specific server or location block:

				
					# /etc/nginx/sites-available/your_site
server {
    listen 80;
    server_name example.com;

    access_log /var/log/nginx/example.com_access.log json_combined;

    # rest of your configuration
}
				
			

The escape=json parameter ensures that special characters are properly escaped, preventing JSON parsing errors. JSON formats are ideal for scaled setups when you configure Nginx logging Ubuntu.

Sending JSON Logs to a Monitoring Pipeline

Once Nginx writes JSON to a file, you can ship it with a log agent without parsing. Examples: Filebeat or Fluentd to Elasticsearch; Promtail to Grafana Loki. Point the agent at /var/log/nginx/*.log (or per-site paths), set the input format to JSON, and configure retention and indexing in the destination. This keeps Nginx config simple and moves parsing and retention to the pipeline.

Custom Log Formats for Specific Needs

You can create multiple custom formats for different purposes. Here’s an example that tracks response times and upstream performance:

				
					# /etc/nginx/nginx.conf
log_format performance '$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"';
				
			

This format adds:

  • $request_time: Total time to process the request.
  • $upstream_connect_time: Time spent establishing connection to upstream server.
  • $upstream_header_time: Time to receive headers from upstream.
  • $upstream_response_time: Time to receive full response from upstream.

These metrics are invaluable when troubleshooting slow application response times or identifying bottlenecks between Nginx and backend services. Custom formats add depth to how you configure Nginx logging Ubuntu.

Understanding the access_log Directive

The access_log directive uses similar syntax to the error_log directive, but is more flexible. It is used to configure custom logging.

The access_log directive uses the following syntax:

				
					# /etc/nginx/nginx.conf
access_log /path/to/log/location [ format_name [ buffer=size ] ];
				
			

The default value for access_log is the combined format mentioned in the log_format section. You can use any format defined by a log_format definition.

The buffer size is the maximum size of data that Nginx will hold before writing it all to the log. You can also specify compression of the log file by adding gzip into the definition:

				
					# /etc/nginx/nginx.conf
access_log /var/log/nginx/access.log combined gzip=1;
				
			

Unlike the error_log directive, if you do not want logging, you can turn it off by updating it in the configuration file:

				
					# /etc/nginx/nginx.conf
##
# Logging Settings
##
access_log off;
error_log /var/log/nginx/error.log;
				
			

It is not necessary to write to /dev/null in this case. This directive is central to configure Nginx logging Ubuntu for access data.

Conditional Logging

You can use the if parameter with access_log to log only specific requests. This is useful for excluding health checks, static assets, or known bot traffic to reduce log volume:

				
					# /etc/nginx/nginx.conf
# Map to determine if request should be logged
map $request_uri $loggable {
    ~^/health-check 0;
    ~^/ping 0;
    default 1;
}

server {
    listen 80;
    server_name example.com;

    # Only log if $loggable is 1
    access_log /var/log/nginx/access.log combined if=$loggable;
}
				
			

This configuration excludes /health-check and /ping endpoints from logs, which is particularly useful when using load balancers or monitoring systems that poll these endpoints frequently. Conditional logging optimizes storage when you configure Nginx logging Ubuntu.

Separate Logs for Different Sites

When hosting multiple websites or applications, separate log files for each site makes troubleshooting and analysis much easier:

				
					# /etc/nginx/sites-available/site1.conf
server {
    listen 80;
    server_name site1.example.com;

    access_log /var/log/nginx/site1_access.log combined;
    error_log /var/log/nginx/site1_error.log warn;

    # rest of configuration
}
				
			
				
					# /etc/nginx/sites-available/site2.conf
server {
    listen 80;
    server_name site2.example.com;

    access_log /var/log/nginx/site2_access.log combined;
    error_log /var/log/nginx/site2_error.log warn;

    # rest of configuration
}
				
			

This approach isolates logs per site, making it easier to:

  • Track traffic patterns for individual applications.
  • Identify which site is experiencing errors.
  • Set different retention policies per site.
  • Simplify log analysis with tools like goaccess or awstats.

Separate logs are a best practice for multi-site setups when you configure Nginx logging Ubuntu.

Managing Log Rotation

Rotate logs so they don’t fill the disk. Use Ubuntu’s built-in logrotate (configured in /etc/logrotate.d/nginx) or manually move logs and send kill -USR1 to the Nginx master process to reopen log files. Nginx does not rotate files itself but cooperates with rotation by reopening log file handles when it receives the USR1 signal.

Manual Log Rotation

To manually rotate your logs, you can create a script to rotate them. For example, move the current log to a new file for archiving. A common scheme is to name the most recent log file with a suffix of .0, and then name older files with .1, and so on:

				
					mv /var/log/nginx/access.log /var/log/nginx/access.log.0
				
			

The command that actually reopens Nginx’s log files after you move them is kill -USR1 $(cat /run/nginx.pid). This does not kill the Nginx process; it sends a signal so Nginx reopens its log file handles. New requests are then logged to the new log file:

				
					kill -USR1 $(cat /run/nginx.pid)
				
			

The /run/nginx.pid file is where Nginx stores the master process’s PID. It is specified at the top of the /etc/nginx/nginx.conf configuration file with the line that begins with pid:

				
					sudo nano /etc/nginx/nginx.conf
				
			
				
					# /etc/nginx/nginx.conf
user www-data;
worker_processes auto;
pid /run/nginx.pid;
include /etc/nginx/modules-enabled/*.conf;
...
				
			

After the rotation, execute sleep 1 to allow the process to complete the transfer. You can then zip the old files or do whatever post-rotation processes you like:

				
					sleep 1
gzip /var/log/nginx/access.log.0
				
			

Manual rotation is useful for testing when you configure Nginx logging Ubuntu.

Log Rotation with logrotate

The logrotate application is a program used to rotate logs. It is installed on Ubuntu by default, and Nginx on Ubuntu comes with a custom logrotate script.

Use your preferred text editor to access the rotation script. This example uses nano:

				
					sudo nano /etc/logrotate.d/nginx
				
			

The first line of the file specifies the location that the subsequent lines will apply to. Keep this in mind if you switch the location of logging in the Nginx configuration files.

The rest of the file specifies that the logs will be rotated daily and that 14 older copies will be preserved. Choose a retention policy that matches your environment:

  • Most production servers: daily with rotate 14 or rotate 30.
  • Compliance / forensics: daily with rotate 90 (or more).
  • Very high traffic: rotate by size (for example, size 100M) or use hourly with a small rotate value.

Notice that the postrotate section contains a command similar to the manual rotation mechanisms previously employed:

				
					# /etc/logrotate.d/nginx
/var/log/nginx/*.log {
    daily
    missingok
    rotate 14
    compress
    delaycompress
    notifempty
    create 0640 www-data adm
    sharedscripts
    postrotate
        [ ! -f /run/nginx.pid ] || kill -USR1 $(cat /run/nginx.pid)
    endscript
}
				
			

This section tells Nginx to reload the log files once the rotation is complete. Logrotate is essential for long-term management when you configure Nginx logging Ubuntu.

Best Practices for Nginx Logging

Most production logging problems come down to three things: too much noise, too much disk usage, or logs that are hard to query. The practices below focus on reducing I/O, keeping retention predictable, and improving troubleshooting speed when you configure Nginx logging Ubuntu.

  1. Use Appropriate Log Levels for Each Environment

    Different environments require different logging strategies: Production:

				
					# /etc/nginx/nginx.conf
error_log /var/log/nginx/error.log warn;
				
			

Use warn as a balanced production default. It captures early warning signals such as upstream failures and configuration issues without the noise and overhead of verbose debug logging.

Staging/QA:

				
					# /etc/nginx/nginx.conf
error_log /var/log/nginx/error.log warn;
				
			

Include warnings to catch potential issues before they reach production. Using the same warn level as production helps validate real-world behaviour before deployment.

Development:

				
					# /etc/nginx/nginx.conf
error_log /var/log/nginx/error.log debug;
				
			
  • Use debug level for detailed troubleshooting, but never in production.

  • Implement Log Buffering for High-Traffic Sites

    On busy servers, writing to disk on every request can become a performance bottleneck. Enable buffering:

				
					# /etc/nginx/nginx.conf
access_log /var/log/nginx/access.log combined buffer=32k flush=5s;
				
			
  • This buffers up to 32KB of log data before writing to disk, or flushes every 5 seconds, whichever comes first. Benefits include reduced disk I/O operations, lower system call overhead, and improved request processing speed. Tradeoff: In the event of a crash, you might lose up to 5 seconds of log data.

  • Set Retention Policies Based on Compliance and Storage

    Configure logrotate using the canonical /etc/logrotate.d/nginx stanza shown earlier, and adjust only rotate, size, and frequency (daily/hourly) based on your retention needs.

    Key parameters explained:

    • rotate 14: Keep 14 days of logs (adjust based on your needs).
    • compress: Gzip old logs to save ~90% disk space.
    • delaycompress: Don’t compress the most recent rotated log (useful for active analysis).
    • notifempty: Don’t rotate empty log files.
    • create 0640 www-data adm: Set proper permissions on new log files.

    Storage planning: A site serving 1 million requests per day might generate raw access logs of ~400MB/day, compressed to ~40MB/day, with 30-day retention using ~1.2GB total.

  • Use Separate Logs for Security Analysis

    Create a dedicated log for security-relevant events:

				
					# /etc/nginx/nginx.conf
# Log format that includes more security-relevant fields
log_format security '$remote_addr - $remote_user [$time_local] '
                    '"$request" $status $body_bytes_sent '
                    '"$http_referer" "$http_user_agent" '
                    '$request_time $ssl_protocol $ssl_cipher';

server {
    listen 443 ssl;
    server_name example.com;

    # Regular access log
    access_log /var/log/nginx/access.log combined;

    # Security-focused log with additional fields
    access_log /var/log/nginx/security.log security;
}
				
			
  • This allows security tools to analyse a specialised log without processing all access logs, and includes SSL/TLS information useful for security audits.

  • Disable Logging for Static Assets (Optional)

    To reduce log volume on sites serving many static files:

				
					# /etc/nginx/nginx.conf
location ~* \.(jpg|jpeg|png|gif|ico|css|js|woff|woff2)$ {
    access_log off;
    expires 30d;
}
				
			
  • Consideration: You’ll lose visibility into static asset requests. Only do this if static assets are served from a CDN that provides separate analytics, you’ve confirmed these logs aren’t needed for business intelligence, or disk space/performance is a genuine concern.

  • Centralise Logs for Multi-Server Deployments

    For applications running across multiple Nginx instances, centralise logs using syslog:

				
					# /etc/nginx/nginx.conf
access_log syslog:server=logserver.example.com:514,tag=nginx_access combined;
error_log syslog:server=logserver.example.com:514,tag=nginx_error warn;
				
			
  • Or ship logs to a dedicated logging service: Elasticsearch + Filebeat for parsing JSON logs and visualizing with Kibana; Logstash for transforming and routing logs; cloud services like AWS CloudWatch, Google Cloud Logging, or Datadog.

  • Monitor Log Disk Usage with Alerts

    Set up monitoring to alert before logs fill your disk:

				
					df -h /var/log/nginx/
				
			

Create a simple monitoring script:

				
					# /usr/local/bin/check_log_disk.sh
#!/bin/bash
THRESHOLD=80
USAGE=$(df /var/log | awk 'NR==2 {print $5}' | sed 's/%//')

if [ "$USAGE" -gt "$THRESHOLD" ]; then
    echo "WARNING: /var/log disk usage is at ${USAGE}%" | mail -s "Log Disk Alert" admin@example.com
fi
				
			

Run this via cron every hour:

				
					0 * * * * /usr/local/bin/check_log_disk.sh
				
			

These best practices ensure your setup is robust when you configure Nginx logging Ubuntu.

Troubleshooting Common Logging Issues

Most Nginx logging issues fall into three buckets: logs not being written, log rotation not running, or disk usage growing unexpectedly. Use the checks below to confirm the root cause before changing configuration when you configure Nginx logging Ubuntu.

Issue 1: Logs Not Being Written

Symptoms: Log files exist but aren’t being updated, or don’t exist at all.

Diagnosis: Check if Nginx is running:

				
					sudo systemctl status nginx
				
			

Verify log file permissions:

				
					ls -la /var/log/nginx/
				
			

Check Nginx error log for permission issues:

				
					sudo tail -n 20 /var/log/nginx/error.log
				
			

Solutions: If the directory doesn’t exist, create it:

				
					sudo mkdir -p /var/log/nginx/
sudo chown www-data:adm /var/log/nginx/
sudo chmod 750 /var/log/nginx/
				
			

If the log file has wrong permissions:

				
					sudo chown www-data:adm /var/log/nginx/*.log
sudo chmod 640 /var/log/nginx/*.log
				
			

If SELinux is enabled (though rare on Ubuntu), set the correct context. Reload Nginx after fixing permissions:

				
					sudo systemctl reload nginx
				
			

Issue 2: Log Rotation Not Working

Symptoms: Log files grow indefinitely; old logs aren’t compressed or removed.

Diagnosis: Check if logrotate is installed:

				
					which logrotate
				
			

View the Nginx logrotate configuration:

				
					cat /etc/logrotate.d/nginx
				
			

Test logrotate manually in debug mode:

				
					sudo logrotate -d /etc/logrotate.d/nginx
				
			

Check logrotate status:

				
					sudo cat /var/lib/logrotate/status | grep nginx
				
			

Solutions: If logrotate isn’t installed:

				
					sudo apt update
sudo apt install logrotate
				
			

If the configuration has syntax errors, verify with debug mode output and fix any issues shown. If rotation timing is wrong, check the main logrotate configuration:

				
					cat /etc/cron.daily/logrotate
				
			

Force a rotation to verify it works:

				
					sudo logrotate -f /etc/logrotate.d/nginx
				
			

If the postrotate script fails (Nginx not reloading logs), verify the PID file location:

				
					cat /run/nginx.pid
				
			

Issue 3: Disk Space Filling Up Rapidly

Symptoms: Root partition fills up; logs consuming excessive disk space.

Diagnosis: Check disk usage:

				
					df -h /var/log
				
			

Find largest log files:

				
					sudo du -sh /var/log/nginx/* | sort -h
				
			

Check log growth rate:

				
					sudo watch -n 1 'ls -lh /var/log/nginx/access.log'
				
			

Solutions: Implement more aggressive rotation:

				
					# /etc/logrotate.d/nginx
/var/log/nginx/*.log {
    daily
    rotate 7
    size 100M
    compress
    delaycompress
    notifempty
    create 0640 www-data adm
    sharedscripts
    postrotate
        [ ! -f /run/nginx.pid ] || kill -USR1 $(cat /run/nginx.pid)
    endscript
}
				
			

Normalize logging verbosity in /etc/nginx/nginx.conf to avoid excessive disk usage:

				
					# /etc/nginx/nginx.conf
error_log /var/log/nginx/error.log warn;
				
			

Disable access logging for static files (see Best Practices section above). Enable conditional logging to exclude health checks and bots. If logs are already too large, manually compress old logs:

				
					sudo gzip /var/log/nginx/access.log.1
sudo gzip /var/log/nginx/error.log.1
				
			

Disable access logging for static files (see Best Practices section above). Enable conditional logging to exclude health checks and bots. If logs are already too large, manually compress old logs:

				
					sudo gzip /var/log/nginx/access.log.1
sudo gzip /var/log/nginx/error.log.1
				
			

Issue 4: Cannot Read Logs (Permission Denied)

Symptoms: tail or cat commands return “Permission denied” errors.

Solution: Add your user to the adm group:

				
					sudo usermod -aG adm $USER
				
			

Log out and back in, then verify:

				
					groups
				
			

You should see adm in your group list. Now you can read logs without sudo:

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

Issue 5: Log Format Causing Parsing Errors

Symptoms: Log analysis tools fail to parse logs; JSON format errors.

Diagnosis: View recent log entries:

				
					sudo tail -n 5 /var/log/nginx/access.log
				
			

If using JSON format, test with jq:

				
					sudo tail -n 1 /var/log/nginx/access.log | jq .
				
			

Solutions: Ensure escape=json is set in your log_format directive:

				
					# /etc/nginx/nginx.conf
log_format json_combined escape=json
  '{'
    '"time":"$time_local",'
    # rest of format
  '}';
				
			

Test your log format by generating a request and immediately checking the output format. For combined format issues, verify you haven’t modified the default format unexpectedly.

Issue 6: Nginx Restart/Reload Fails After Log Configuration Changes

Symptoms: Nginx fails to start after modifying logging directives.

Diagnosis: Always test configuration before applying:

				
					sudo nginx -t
				
			

Check systemd logs for specific errors:

				
					sudo journalctl -xeu nginx
				
			

Common causes:

  • Invalid log format syntax: Missing quotes, unclosed braces, or invalid variables.
  • Invalid file paths: Directory doesn’t exist or incorrect permissions.
  • Conflicting directives: Multiple error_log or access_log directives at the same context level without understanding inheritance.

Solution: Review the error message from nginx -t, which typically points to the exact line and issue. Fix the syntax, verify permissions, then test again before reloading.

These troubleshooting steps resolve most issues when you configure Nginx logging Ubuntu.

FAQ

Where are Nginx logs stored on Ubuntu?

By default, Nginx stores logs in /var/log/nginx/:

  • Access logs: /var/log/nginx/access.log
  • Error logs: /var/log/nginx/error.log

You can customise these locations in /etc/nginx/nginx.conf or in individual site configurations under /etc/nginx/sites-available/. Each server block can specify its own log files for easier management and analysis.

How often should Nginx logs be rotated?

The optimal rotation frequency depends on traffic volume and retention requirements:

  • Most production servers: Daily rotation with rotate 14 or rotate 30.
  • High-traffic workloads: Rotate by size (for example, size 100M) or use hourly rotation with a small retention window.
  • Compliance and audit requirements: Retain logs for 90 days or longer.

Adjust the rotate, size, and frequency values in /etc/logrotate.d/nginx to match your operational and regulatory needs.

How do I create custom Nginx log formats?

Create custom formats using the log_format directive in the http block of /etc/nginx/nginx.conf:

				
					log_format custom_format '$remote_addr - $remote_user [$time_local] '
                         '"$request" $status $body_bytes_sent '
                         'rt=$request_time';
				
			

Then apply it using access_log:

				
					access_log /var/log/nginx/custom_access.log custom_format;
				
			

You can use any Nginx variables in your format. Common additions include $request_time, $upstream_response_time, $ssl_protocol, and $ssl_cipher for performance and security monitoring.

Why are my Nginx logs not rotating?

Common causes and solutions:

  1. Logrotate not installed: Install with sudo apt install logrotate.
  2. Logrotate cron job disabled: Check /etc/cron.daily/logrotate exists and is executable.
  3. Configuration errors: Test with sudo logrotate -d /etc/logrotate.d/nginx.
  4. Nginx not releasing file handles: The postrotate script should send USR1 signal to reload logs.
  5. Wrong file paths: Ensure paths in /etc/logrotate.d/nginx match actual log locations.

Debug by running: sudo logrotate -dv /etc/logrotate.d/nginx to see detailed output of what logrotate would do.

Can Nginx log in JSON format?

Yes, Nginx can output logs in JSON format, which is ideal for modern log aggregation and analysis tools. Define a JSON format in /etc/nginx/nginx.conf:

				
					log_format json_combined escape=json
  '{'
    '"timestamp":"$time_local",'
    '"client":"$remote_addr",'
    '"method":"$request_method",'
    '"uri":"$request_uri",'
    '"status":"$status",'
    '"bytes_sent":"$body_bytes_sent",'
    '"response_time":"$request_time",'
    '"user_agent":"$http_user_agent"'
  '}';
				
			

Apply it to your access log:

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

The escape=json parameter ensures proper escaping of special characters. JSON logs work seamlessly with Elasticsearch, Splunk, Datadog, and other log analysis platforms.

How do I disable access logging for specific requests?

Use conditional logging with a map:

				
					map $request_uri $loggable {
    ~^/health        0;
    ~^/status        0;
    ~*\.(gif|jpg|png)$ 0;
    default          1;
}

server {
    access_log /var/log/nginx/access.log combined if=$loggable;
}
				
			

This excludes health check endpoints and image requests from logs. Alternatively, disable logging completely for a location:

				
					location /health-check {
    access_log off;
    return 200 "OK";
}
				
			

What’s the performance impact of verbose logging?

Logging performance impact varies by level and traffic:

  • warn level: Recommended default for production. Low overhead while preserving early warning signals.
  • info and notice levels: Moderate overhead due to higher disk I/O. Use temporarily for investigation.
  • debug level: High overhead and heavy disk writes. Use only during active troubleshooting and disable immediately after.

The actual impact depends on your disk I/O speed, traffic volume, and whether you use buffering. On high-traffic sites, enable buffering (buffer=32k flush=5s) to reduce disk writes and minimise performance overhead.

How long should I retain Nginx logs?

Log retention should balance compliance requirements, storage costs, and usefulness. Minimum recommendations:

  • Production sites: 30 days for troubleshooting and trend analysis.
  • Compliance requirements (PCI DSS, HIPAA, GDPR): 90 days to 1 year.
  • Forensic/security needs: 90+ days for incident investigation.

Storage efficiency:

  • Use compress in logrotate to reduce storage by ~90%.
  • Archive older logs to cheaper storage (S3 Glacier, etc.).
  • Use tiered retention: 30 days local, 90 days archived, 1 year cold storage.

Example retention policy:

				
					/var/log/nginx/*.log {
    daily
    rotate 30           # 30 days local
    compress
    dateext
    # Archive anything older to S3 via a script
    lastaction
        /usr/local/bin/archive_old_logs.sh
    endscript
}
				
			

These FAQs address common queries when users search to configure Nginx logging Ubuntu.

Conclusion

Conclusion

Proper log configuration and management directly affect your ability to troubleshoot outages, detect abnormal traffic, and prevent disk-related failures. By implementing the logging strategies covered in this tutorial, you gain practical visibility into real server behaviour.

You’ve learned how to configure Nginx logging Ubuntu with error_log and access_log directives, create custom log formats for specific monitoring needs, implement log rotation to prevent disk space issues, and troubleshoot common logging problems. These capabilities will help you diagnose issues quickly, understand traffic patterns, and maintain server security.

For next steps, consider:

  • Setting up the LEMP stack (Linux, Nginx, MySQL, PHP) for dynamic web applications.
  • Learning more about managing log files with logrotate across your entire system.
  • Configuring Nginx as a reverse proxy with proper upstream logging.
  • Troubleshooting other common issues with Nginx error handling.

Remember that effective logging is about finding the right balance: comprehensive enough to catch problems, but not so verbose that it impacts performance or overwhelms your storage. Start with the defaults, monitor your actual usage, and adjust based on your specific needs.