Linux Log Files Explained

    Find, read, and manage log files on Debian/Ubuntu and AlmaLinux/RHEL

    Every service on your Linux server writes logs — from the kernel and SSH daemon to web servers and databases. Knowing where to find these logs and how to read them is essential for diagnosing problems, monitoring security, and understanding what's happening on your VPS.

    What You'll Learn

    The difference between syslog and journald
    Where every important log file lives
    Read, search, and follow logs in real time
    Configure logrotate to prevent disk full
    Filter and query logs with journalctl
    Troubleshoot common issues using logs

    Prerequisites

    1. syslog vs journald

    Modern Linux distributions have two logging systems that work alongside each other:

    Featuresyslog (rsyslog)journald (systemd)
    FormatPlain text filesBinary, structured
    Location/var/log//var/log/journal/ (or memory)
    Readingcat, less, grepjournalctl
    RotationlogrotateBuilt-in size/time limits
    SearchgrepNative filtering by unit, priority, time
    Default onDebian/Ubuntu (rsyslog)All systemd distros

    💡 Key point: On Debian/Ubuntu, both rsyslog and journald run by default — rsyslog writes text files to /var/log/, and journald keeps its own binary journal. On AlmaLinux/RHEL 9+, rsyslog is still available but journald is the primary logging system. Both distro families let you use journalctl.

    2. Where Logs Live

    All traditional log files are stored under /var/log/. Here's a quick tour of the most important ones:

    System Logs

    Log FileDebian/UbuntuAlmaLinux/RHELContents
    /var/log/syslogGeneral system messages (kernel, services, etc.)
    /var/log/messagesEquivalent of syslog on RHEL-family
    /var/log/auth.logAuthentication events (SSH logins, sudo, etc.)
    /var/log/secureEquivalent of auth.log on RHEL-family
    /var/log/kern.logKernel messages only
    /var/log/dmesgBoot-time kernel ring buffer messages
    /var/log/boot.logService startup messages during boot
    /var/log/cronCron job execution logs

    Package Manager Logs

    Log FileDistroContents
    /var/log/apt/history.logDebian/UbuntuPackage install/upgrade/remove history
    /var/log/apt/term.logDebian/UbuntuTerminal output from apt operations
    /var/log/dpkg.logDebian/UbuntuLow-level dpkg package operations
    /var/log/dnf.logAlmaLinux/RHELDNF package manager activity
    See everything in /var/log/
    # List all log files, sorted by modification time
    ls -lht /var/log/
    
    # Check total log disk usage
    sudo du -sh /var/log/

    3. Reading Text Logs

    Traditional log files in /var/log/ are plain text. Here are the essential tools for reading them:

    Viewing log files
    # View the entire file (careful with large files!)
    cat /var/log/syslog          # Debian/Ubuntu
    cat /var/log/messages        # AlmaLinux/RHEL
    
    # Page through a large log file
    less /var/log/syslog
    
    # View the last 50 lines
    tail -n 50 /var/log/syslog
    
    # Follow a log in real time (like a live stream)
    tail -f /var/log/syslog
    
    # Follow multiple files at once
    tail -f /var/log/syslog /var/log/auth.log

    Searching with grep

    Searching logs with grep
    # Find all SSH login attempts
    grep "sshd" /var/log/auth.log         # Debian/Ubuntu
    grep "sshd" /var/log/secure           # AlmaLinux/RHEL
    
    # Find failed login attempts
    grep "Failed password" /var/log/auth.log
    
    # Case-insensitive search
    grep -i "error" /var/log/syslog
    
    # Show 3 lines before and after each match (context)
    grep -B3 -A3 "error" /var/log/syslog
    
    # Count occurrences
    grep -c "Failed password" /var/log/auth.log
    
    # Search across all log files
    grep -r "Out of memory" /var/log/
    
    # Search compressed/rotated logs
    zgrep "error" /var/log/syslog.2.gz

    Filtering by Time

    Time-based filtering
    # Find all entries from today (Feb 25)
    grep "Feb 25" /var/log/syslog
    
    # Find entries in a time range using awk
    awk '/Feb 25 10:00/,/Feb 25 11:00/' /var/log/syslog
    
    # Count errors per hour
    grep "error" /var/log/syslog | awk '{print $1, $2, $3}' | cut -d: -f1 | sort | uniq -c

    💡 Tip: For more details on commands like grep, awk, and piping, see our Linux Command Line Basics guide.

    4. journalctl Deep Dive

    journalctl reads from the systemd journal — a structured, indexed binary log. It works on both Debian/Ubuntu and AlmaLinux/RHEL.

    Basic journalctl usage
    # Show all logs (newest at the bottom)
    sudo journalctl
    
    # Show logs in reverse order (newest first)
    sudo journalctl -r
    
    # Follow logs in real time
    sudo journalctl -f
    
    # Show only the last 100 entries
    sudo journalctl -n 100

    Filter by Service

    Service-specific logs
    # Logs for a specific service
    sudo journalctl -u nginx
    sudo journalctl -u sshd
    sudo journalctl -u mariadb
    
    # Follow a specific service's logs in real time
    sudo journalctl -u nginx -f
    
    # Multiple services at once
    sudo journalctl -u nginx -u php-fpm

    Filter by Time

    Time-based filtering
    # Logs since a specific date/time
    sudo journalctl --since "2026-02-24 10:00"
    
    # Logs from the last hour
    sudo journalctl --since "1 hour ago"
    
    # Logs between two times
    sudo journalctl --since "2026-02-24" --until "2026-02-25"
    
    # Logs from the current boot only
    sudo journalctl -b
    
    # Logs from the previous boot
    sudo journalctl -b -1
    
    # List all available boots
    sudo journalctl --list-boots

    Filter by Priority

    Priority levels
    # Show only errors and more severe
    sudo journalctl -p err
    
    # Show warnings and above
    sudo journalctl -p warning
    
    # Priority levels (0=most severe):
    #   0 emerg   — System is unusable
    #   1 alert   — Immediate action needed
    #   2 crit    — Critical conditions
    #   3 err     — Error conditions
    #   4 warning — Warning conditions
    #   5 notice  — Normal but significant
    #   6 info    — Informational
    #   7 debug   — Debug-level messages
    
    # Combine priority with service and time
    sudo journalctl -u nginx -p err --since "1 hour ago"

    Output Formats

    Changing output format
    # Short (default) — one line per entry
    sudo journalctl -u nginx -o short
    
    # Verbose — all metadata fields
    sudo journalctl -u nginx -o verbose
    
    # JSON — machine-readable
    sudo journalctl -u nginx -o json-pretty
    
    # cat — message text only, no metadata
    sudo journalctl -u nginx -o cat

    Kernel Messages

    Kernel logs
    # Kernel messages (equivalent to dmesg)
    sudo journalctl -k
    
    # Kernel messages from current boot
    sudo journalctl -k -b
    
    # Kernel errors only
    sudo journalctl -k -p err

    📖 Related: For a deeper look at managing systemd services and their logs, see Managing systemd Services.

    5. Application Logs

    Web servers, databases, and other applications typically write their own log files:

    Web Servers

    ApplicationAccess LogError Log
    Nginx/var/log/nginx/access.log/var/log/nginx/error.log
    Apache/var/log/apache2/access.log/var/log/apache2/error.log
    Apache (RHEL)/var/log/httpd/access_log/var/log/httpd/error_log

    Databases

    DatabaseLog Location
    MariaDB/MySQL/var/log/mysql/error.log or /var/log/mariadb/mariadb.log
    PostgreSQL/var/log/postgresql/postgresql-*-main.log
    MongoDB/var/log/mongodb/mongod.log

    Other Services

    ServiceLog Location
    Fail2Ban/var/log/fail2ban.log
    UFW/var/log/ufw.log
    Mail (Postfix)/var/log/mail.log (Debian) or /var/log/maillog (RHEL)
    Docker/var/lib/docker/containers/*/
    Reading application logs
    # Follow Nginx errors in real time
    sudo tail -f /var/log/nginx/error.log
    
    # Find 500 errors in access logs
    grep '" 500 ' /var/log/nginx/access.log
    
    # Top 10 IPs hitting your server
    awk '{print $1}' /var/log/nginx/access.log | sort | uniq -c | sort -rn | head -10
    
    # Find slow MySQL queries (if slow query log is enabled)
    sudo tail -100 /var/log/mysql/slow-query.log

    💡 Tip: Many modern services also write to the systemd journal. You can check both: sudo journalctl -u nginx shows the same information as the log file in many cases.

    6. logrotate Configuration

    Without rotation, log files grow indefinitely until they fill your disk. logrotate compresses, rotates, and removes old log files automatically. It's installed by default on both Debian/Ubuntu and AlmaLinux/RHEL.

    How logrotate Works

    logrotate runs daily via a cron job (or systemd timer). It reads its configuration from:

    PathPurpose
    /etc/logrotate.confGlobal defaults
    /etc/logrotate.d/Per-application configs (nginx, apt, mysql, etc.)

    Global Configuration

    /etc/logrotate.conf
    # Rotate logs weekly
    weekly
    
    # Keep 4 weeks of old logs
    rotate 4
    
    # Create new empty log files after rotation
    create
    
    # Compress old log files with gzip
    compress
    
    # Don't compress the most recently rotated file (for services that
    # haven't yet reopened their log file handle)
    delaycompress
    
    # Include per-application configs
    include /etc/logrotate.d

    Per-Application Config Examples

    /etc/logrotate.d/nginx
    /var/log/nginx/*.log {
        daily
        missingok
        rotate 14
        compress
        delaycompress
        notifempty
        create 0640 www-data adm
        sharedscripts
        postrotate
            if [ -d /etc/nginx ]; then
                /usr/sbin/nginx -s reopen > /dev/null 2>&1 || true
            fi
        endscript
    }

    Key Directives Explained

    DirectiveDescription
    daily / weekly / monthlyHow often to rotate
    rotate NKeep N rotated files before deleting
    compressGzip old log files
    delaycompressDon't compress the most recent rotated file
    missingokDon't error if the log file doesn't exist
    notifemptyDon't rotate if the log file is empty
    create MODE OWNER GROUPCreate a new empty log file with the given permissions
    copytruncateCopy the file then truncate it (for apps that can't reopen logs)
    sharedscriptsRun postrotate once even if multiple files match
    maxsize SIZERotate when file exceeds this size, regardless of schedule
    postrotate / endscriptCommands to run after rotation (e.g., signal the service)

    Creating a Custom logrotate Config

    If you have a custom application that writes to /var/log/myapp/:

    /etc/logrotate.d/myapp
    /var/log/myapp/*.log {
        daily
        rotate 7
        compress
        delaycompress
        missingok
        notifempty
        copytruncate
        maxsize 100M
    }

    Testing & Debugging logrotate

    logrotate commands
    # Dry run — show what would happen without doing it
    sudo logrotate -d /etc/logrotate.conf
    
    # Force rotation now (useful for testing)
    sudo logrotate -f /etc/logrotate.d/myapp
    
    # Run logrotate verbosely
    sudo logrotate -v /etc/logrotate.conf
    
    # Check logrotate status (last rotation times)
    cat /var/lib/logrotate/status

    ⚠️ Common mistake: Using create with apps that keep the file handle open (like some Node.js apps). Those apps will keep writing to the old, now-renamed file. Use copytruncate instead, or signal the app to reopen its log file via postrotate.

    7. Managing Journal Size

    The systemd journal can also grow large. Unlike text logs managed by logrotate, the journal has its own size management.

    Check and clean journal
    # Check current journal disk usage
    sudo journalctl --disk-usage
    
    # Remove journal entries older than 7 days
    sudo journalctl --vacuum-time=7d
    
    # Limit journal to 500MB
    sudo journalctl --vacuum-size=500M
    
    # Keep only the 5 most recent journal files
    sudo journalctl --vacuum-files=5

    Set Permanent Limits

    /etc/systemd/journald.conf
    [Journal]
    # Maximum disk space the journal can use
    SystemMaxUse=500M
    
    # Always keep at least this much free
    SystemKeepFree=1G
    
    # Maximum time to keep entries
    MaxRetentionSec=30day
    
    # Maximum size of individual journal files
    SystemMaxFileSize=50M
    Apply changes
    sudo systemctl restart systemd-journald

    Persistent vs Volatile Journal

    By default, some distributions store the journal only in memory (volatile), meaning logs are lost on reboot. To make the journal persistent:

    Enable persistent journal storage
    # Create the journal directory (enables persistence)
    sudo mkdir -p /var/log/journal
    sudo systemd-tmpfiles --create --prefix /var/log/journal
    sudo systemctl restart systemd-journald
    
    # Verify — you should now see logs from previous boots
    sudo journalctl --list-boots

    8. Centralized Logging

    If you manage multiple servers, consider aggregating logs in one place. Here are some options:

    ELK Stack

    Elasticsearch + Logstash + Kibana — the full-featured open-source logging stack.

    → ELK Stack Deployment Guide

    Dozzle (Docker)

    Lightweight, real-time log viewer for Docker containers.

    → Dozzle Deployment Guide

    💡 Tip: rsyslog can also forward logs to a remote server over TCP/UDP. This is built into both Debian/Ubuntu and AlmaLinux and doesn't require installing additional software.

    9. Troubleshooting with Logs

    Here are common scenarios and which logs to check first:

    ProblemWhere to LookCommand
    SSH login failuresauth.log / securesudo journalctl -u sshd -p err
    Website returning 500nginx/apache error logsudo tail -50 /var/log/nginx/error.log
    Service won't startjournaldsudo journalctl -u myservice -n 50
    Server crashed/rebootedPrevious boot logssudo journalctl -b -1 -p err
    Out of memory (OOM)Kernel logsudo journalctl -k | grep -i "oom\|killed"
    Disk fullsyslog / messagessudo journalctl -p warning | grep -i "space\|full\|disk"
    Brute force attacksauth.log + fail2bangrep "Failed password" /var/log/auth.log | tail -20
    Quick diagnostic workflow
    # 1. Check for recent errors across all services
    sudo journalctl -p err --since "1 hour ago"
    
    # 2. Check if any services have failed
    systemctl list-units --state=failed
    
    # 3. Check disk usage (logs filling disk?)
    df -h /var/log
    sudo du -sh /var/log/*
    
    # 4. Check for OOM kills
    sudo dmesg | grep -i "oom|killed process"
    
    # 5. Check auth failures (brute force?)
    sudo journalctl -u sshd -p warning --since today | tail -20

    Related Security Documentation

    Next Steps

    You now know where Linux logs live, how to read them, and how to keep them under control. Here are some related topics: