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
Prerequisites
- • A RamNode Cloud VPS running any Linux distribution
- • Root or sudo access (see Linux Command Line Basics)
1. syslog vs journald
Modern Linux distributions have two logging systems that work alongside each other:
| Feature | syslog (rsyslog) | journald (systemd) |
|---|---|---|
| Format | Plain text files | Binary, structured |
| Location | /var/log/ | /var/log/journal/ (or memory) |
| Reading | cat, less, grep | journalctl |
| Rotation | logrotate | Built-in size/time limits |
| Search | grep | Native filtering by unit, priority, time |
| Default on | Debian/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 File | Debian/Ubuntu | AlmaLinux/RHEL | Contents |
|---|---|---|---|
| /var/log/syslog | ✅ | ❌ | General system messages (kernel, services, etc.) |
| /var/log/messages | ❌ | ✅ | Equivalent of syslog on RHEL-family |
| /var/log/auth.log | ✅ | ❌ | Authentication events (SSH logins, sudo, etc.) |
| /var/log/secure | ❌ | ✅ | Equivalent of auth.log on RHEL-family |
| /var/log/kern.log | ✅ | ❌ | Kernel messages only |
| /var/log/dmesg | ✅ | ✅ | Boot-time kernel ring buffer messages |
| /var/log/boot.log | ❌ | ✅ | Service startup messages during boot |
| /var/log/cron | ❌ | ✅ | Cron job execution logs |
Package Manager Logs
| Log File | Distro | Contents |
|---|---|---|
| /var/log/apt/history.log | Debian/Ubuntu | Package install/upgrade/remove history |
| /var/log/apt/term.log | Debian/Ubuntu | Terminal output from apt operations |
| /var/log/dpkg.log | Debian/Ubuntu | Low-level dpkg package operations |
| /var/log/dnf.log | AlmaLinux/RHEL | DNF package manager activity |
# 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:
# 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.logSearching 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.gzFiltering by Time
# 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.
# 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 100Filter by Service
# 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-fpmFilter by Time
# 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-bootsFilter by Priority
# 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
# 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 catKernel Messages
# 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
| Application | Access Log | Error 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
| Database | Log 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
| Service | Log 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/*/ |
# 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:
| Path | Purpose |
|---|---|
| /etc/logrotate.conf | Global defaults |
| /etc/logrotate.d/ | Per-application configs (nginx, apt, mysql, etc.) |
Global Configuration
# 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.dPer-Application Config Examples
/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
| Directive | Description |
|---|---|
| daily / weekly / monthly | How often to rotate |
| rotate N | Keep N rotated files before deleting |
| compress | Gzip old log files |
| delaycompress | Don't compress the most recent rotated file |
| missingok | Don't error if the log file doesn't exist |
| notifempty | Don't rotate if the log file is empty |
| create MODE OWNER GROUP | Create a new empty log file with the given permissions |
| copytruncate | Copy the file then truncate it (for apps that can't reopen logs) |
| sharedscripts | Run postrotate once even if multiple files match |
| maxsize SIZE | Rotate when file exceeds this size, regardless of schedule |
| postrotate / endscript | Commands 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/:
/var/log/myapp/*.log {
daily
rotate 7
compress
delaycompress
missingok
notifempty
copytruncate
maxsize 100M
}Testing & Debugging logrotate
# 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 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=5Set Permanent Limits
[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=50Msudo systemctl restart systemd-journaldPersistent 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:
# 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-boots8. 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 GuideDozzle (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:
| Problem | Where to Look | Command |
|---|---|---|
| SSH login failures | auth.log / secure | sudo journalctl -u sshd -p err |
| Website returning 500 | nginx/apache error log | sudo tail -50 /var/log/nginx/error.log |
| Service won't start | journald | sudo journalctl -u myservice -n 50 |
| Server crashed/rebooted | Previous boot logs | sudo journalctl -b -1 -p err |
| Out of memory (OOM) | Kernel log | sudo journalctl -k | grep -i "oom\|killed" |
| Disk full | syslog / messages | sudo journalctl -p warning | grep -i "space\|full\|disk" |
| Brute force attacks | auth.log + fail2ban | grep "Failed password" /var/log/auth.log | tail -20 |
# 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 -20Related Security Documentation
- Fail2Ban Guide — Automatically ban IPs with too many failed login attempts
- CrowdSec Guide — Modern collaborative intrusion prevention
- Basic Resource Monitoring — Monitor CPU, RAM, and disk alongside logs
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:
