Console9

How to manage web server logs with Logrotate and Nginx

Configure Nginx access and error logging, set up Logrotate for automatic log rotation, and monitor log files for troubleshooting.

This guide walks through configuring web server logging and automated log rotation on a Linux server. By the end, you will have Nginx writing structured access and error logs, Logrotate compressing and rotating those logs on a schedule, and a monitoring workflow for identifying issues from log data.

What You Need Before Starting

  • An Ubuntu 22.04 or 24.04 server with root or sudo access
  • Nginx installed and running (see the Web Server Setup Guide)
  • Basic familiarity with the Linux command line

Estimated time: 20–30 minutes.

Architecture Overview

Log management on a Linux web server involves two components working together.

Nginxwrites two types of log files. The access log records every HTTP request the server receives — including the client IP, request path, status code, and response size. The error log records server errors, configuration problems, and upstream failures. Both log files grow continuously and consume disk space unless managed.

Logrotateis a Linux utility that compresses, rotates, and deletes old log files on a schedule. Logrotate runs as a cron job (typically daily) and processes log files according to rules defined in configuration files under /etc/logrotate.d/. Without Logrotate, log files grow until they fill the disk, which causes the server to stop writing logs or — in the worst case — crash.

Step 1: Configure Nginx Access and Error Logs

Nginx writes log files to /var/log/nginx/ by default. The main Nginx configuration file ( /etc/nginx/nginx.conf) defines the global log format and file paths.

Set the Log Format in Nginx

Open the Nginx configuration file:

sudo nano /etc/nginx/nginx.conf

The log_format directive inside the http block defines what Nginx records for each request. The default combined format includes the most useful fields:

http {
    log_format combined '$remote_addr - $remote_user [$time_local] '
                        '"$request" $status $body_bytes_sent '
                        '"$http_referer" "$http_user_agent"';

    access_log /var/log/nginx/access.log combined;
    error_log /var/log/nginx/error.log warn;
}

The access_log directive sets the file path and format. The error_log directive sets the file path and minimum severity level — warn records warnings and errors while filtering out debug and info messages.

Configure Per-Site Logging in Nginx

Nginx supports separate log files for each server block. Add access_log and error_log directives inside the server block:

server {
    server_name example.com;
    access_log /var/log/nginx/example.com.access.log combined;
    error_log /var/log/nginx/example.com.error.log warn;
}

Per-site log files make it easier to isolate issues to a specific domain when the server hosts multiple sites.

Reload Nginx to apply the logging configuration:

sudo nginx -t
sudo systemctl reload nginx

For a full logging tutorial, see Nginx tutorial: How to configure and analyze Nginx log data.

Step 2: Install and Configure Logrotate for Nginx Logs

Logrotate is pre-installed on most Linux distributions. Verify that Logrotate is available:

logrotate --version

If Logrotate is not installed, install it with:

sudo apt install logrotate

Create a Logrotate Configuration for Nginx

Nginx typically installs a default Logrotate configuration at /etc/logrotate.d/nginx. Open or create this file:

sudo nano /etc/logrotate.d/nginx

Add the following Logrotate configuration:

/var/log/nginx/*.log {
    daily
    missingok
    rotate 14
    compress
    delaycompress
    notifempty
    create 0640 www-data adm
    sharedscripts
    postrotate
        if [ -f /var/run/nginx.pid ]; then
            kill -USR1 $(cat /var/run/nginx.pid)
        fi
    endscript
}

This Logrotate configuration applies these rules to all Nginx log files:

  • daily: Logrotate rotates the log files once per day.
  • rotate 14: Logrotate keeps 14 rotated files before deleting the oldest.
  • compress: Logrotate compresses rotated files with gzip to save disk space.
  • delaycompress: Logrotate skips compression on the most recently rotated file — this prevents issues with programs that still write to the old file.
  • notifempty: Logrotate skips rotation if the log file is empty.
  • create 0640 www-data adm: Logrotate creates a new log file with the specified permissions and ownership after rotation.
  • postrotate: Logrotate sends the USR1 signal to Nginx after rotation. Nginx reopens its log files when it receives this signal, which ensures it writes to the new file instead of the rotated one.

Test the Logrotate Configuration

Run Logrotate in debug mode to verify the configuration without actually rotating files:

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

The debug output shows what Logrotate would do for each log file. Verify that it detects the correct files and applies the expected rules.

Force a manual rotation to test the full process:

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

Check that rotated files appear in /var/log/nginx/:

ls -la /var/log/nginx/

Rotated files follow the naming pattern access.log.1, access.log.2.gz, access.log.3.gz, and so on.

For more Logrotate configuration options, see the Logrotate tutorial: How to configure log rotation.

Step 3: Monitor Log Files for Troubleshooting

Log files are the primary source for diagnosing web server issues. Nginx error logs reveal upstream failures, permission errors, and configuration problems.

Watch Nginx Error Logs in Real Time

Use tail -f to follow the Nginx error log as new entries appear:

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

Common Nginx error patterns and their meanings:

Error patternMeaningRelated article
connect() to unix:/run/php/php-fpm.sock failedPHP-FPM is not running or the socket path is wrongNginx: connect to php-fpm.sock failed
upstream sent too big headerPHP response headers exceed Nginx buffer sizeNginx: upstream sent too big header
502 Bad GatewayThe upstream server (PHP-FPM, Node.js) is down or unresponsiveNginx: 502 Bad Gateway

Search Access Logs for Specific Patterns

Use grep to filter access logs for specific HTTP status codes, IP addresses, or request paths:

# Find all 404 errors in the access log
grep '" 404 ' /var/log/nginx/access.log

# Find all requests from a specific IP address
grep '203.0.113.42' /var/log/nginx/access.log

# Count requests per status code
awk '{print $9}' /var/log/nginx/access.log | sort | uniq -c | sort -rn

Check Logrotate Status

Logrotate records the last rotation time for each log file in its state file. Check when Logrotate last processed your Nginx logs:

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

If Logrotate has not rotated files as expected, see Logrotate: logs are not rotating.

How to Verify the Complete Setup

Test each component of the log management setup:

  1. Nginx logging: Send a request to your server and verify a new entry appears in the access log:
curl -s http://localhost > /dev/null
sudo tail -1 /var/log/nginx/access.log
  1. Error logging: Request a non-existent page and verify a 404 appears in the access log:
curl -s http://localhost/nonexistent > /dev/null
sudo tail -1 /var/log/nginx/access.log
  1. Logrotate: Force a rotation and verify compressed files appear:
sudo logrotate -f /etc/logrotate.d/nginx
ls -la /var/log/nginx/
  1. Nginx log reopening: After rotation, verify Nginx writes to the new log file (not the rotated one):
curl -s http://localhost > /dev/null
sudo tail -1 /var/log/nginx/access.log

What to Do Next