Log Management¶
Reference: systemd journald Docs · Debian Wiki — syslog · journalctl(1)
Log Locations¶
On Debian 12 and 13 the systemd journal is the system log. rsyslog is no longer installed by default, so the
classic text files /var/log/syslog, /var/log/auth.log and /var/log/kern.log simply don't exist on a fresh
server. The journal is persistent (/var/log/journal/), so logs survive reboots.
| What you want | Debian 13 (journal) | Old text file (only with rsyslog) |
|---|---|---|
| Everything | journalctl |
/var/log/syslog |
| SSH logins / failures | journalctl -u ssh |
/var/log/auth.log |
| sudo usage | journalctl _COMM=sudo |
/var/log/auth.log |
| Kernel messages | journalctl -k / dmesg |
/var/log/kern.log |
| Package installs | /var/log/dpkg.log, /var/log/apt/history.log |
(same, these are still files) |
| unattended-upgrades runs | /var/log/unattended-upgrades/ |
(same) |
| Container logs | docker logs <container> |
/var/lib/docker/containers/<id>/*-json.log |
Want the text files back?
sudo apt install rsyslog recreates /var/log/syslog and friends (it reads from the journal). Ubuntu still
installs rsyslog by default, which is why most guides grep /var/log/auth.log. On Debian, translate those to the
journalctl filters above. Last-login tools changed too: last/lastb/lastlog are gone in trixie; use
wtmpdb last or lslogins --failed.
Reading Logs¶
# Follow everything live (like tail -f /var/log/syslog)
journalctl -f
# Follow SSH logins live (like tail -f /var/log/auth.log)
journalctl -u ssh -f
# Last 50 lines
journalctl -n 50
# Search within the log
journalctl -g "error" # --grep, regex
journalctl -u ssh -g "Failed|Invalid" # case-insensitive when the pattern is all lowercase
# Plain text files still work the usual way
less /var/log/apt/history.log
tail -f /var/log/dpkg.log
# View kernel ring buffer (hardware/boot messages)
sudo dmesg
sudo dmesg | tail -20
sudo dmesg -T # with human-readable timestamps
journalctl -k -b -1 # kernel messages from the PREVIOUS boot (after a crash)
journalctl — systemd Journal¶
The journal is the primary log store on Debian. See also the Systemd page for more detail.
# All logs
journalctl
# Follow live
journalctl -f
# Last 100 lines
journalctl -n 100
# Logs for a specific service
journalctl -u nginx
journalctl -u docker -f
# Logs since last boot
journalctl -b
# Logs from a specific time window
journalctl --since "2024-01-15 09:00:00" --until "2024-01-15 10:00:00"
journalctl --since "1 hour ago"
journalctl --since today
# Filter by priority
journalctl -p err # errors and above
journalctl -p warning # warnings and above
journalctl -p debug # everything
# Priority levels: emerg, alert, crit, err, warning, notice, info, debug
# Kernel messages only
journalctl -k
# Show full output (no truncation)
journalctl --no-pager
# Output as JSON (useful for log forwarding)
journalctl -u myservice -o json-pretty
Log Rotation — logrotate¶
logrotate automatically rotates, compresses, and removes old log files.
# Config files
/etc/logrotate.conf # global defaults
/etc/logrotate.d/ # per-application configs
# Test a config (dry run)
sudo logrotate --debug /etc/logrotate.d/nginx
# Force run logrotate now
sudo logrotate -f /etc/logrotate.conf
Example Config¶
# /etc/logrotate.d/myapp
# (logrotate only allows comments on their own line, not after a directive)
/var/log/myapp/*.log {
# rotate daily
daily
# don't error if log file missing
missingok
# keep 14 rotated logs
rotate 14
# gzip old logs
compress
# compress on second rotation (app may still write)
delaycompress
# don't rotate empty files
notifempty
# create new log with these perms/owner
create 0640 myapp myapp
postrotate
systemctl reload myapp > /dev/null 2>&1 || true
endscript
}
journald Configuration¶
# Config file
sudo nano /etc/systemd/journald.conf
# Key settings:
[Journal]
# Limit journal disk usage
SystemMaxUse=500M
# Keep logs for max 30 days
MaxRetentionSec=30day
# Max size per log file
SystemMaxFileSize=50M
# Persist journal across reboots (default is sometimes volatile)
Storage=persistent
# Apply changes
sudo systemctl restart systemd-journald
# Check current disk usage
journalctl --disk-usage
# Manual cleanup
sudo journalctl --vacuum-size=200M # trim to under 200MB
sudo journalctl --vacuum-time=14d # remove logs older than 14 days
Searching & Filtering Logs¶
# Context lines around a match: pipe to grep
journalctl -b | grep -A 3 -B 3 "Out of memory"
# -A 3 = 3 lines after match, -B 3 = 3 before, -C 3 = either side
# Time window + priority
journalctl --since "2026-01-15" --until "2026-01-16" -p err
# Count failed SSH logins
journalctl -u ssh --since today | grep -c "Failed password"
# Failed SSH attempts by source IP
journalctl -u ssh -g "Failed password" -o cat | awk '{print $(NF-3)}' | sort | uniq -c | sort -rn
# sudo usage
journalctl _COMM=sudo
# OOM kills
journalctl -k -g "Out of memory|oom-kill"
# Search text logs that still exist as files
grep -r "connection refused" /var/log/
Forwarding Logs (Loki / Remote Syslog)¶
Docker Logging Driver → Loki¶
My servers keep Docker's default json-file driver with rotation (see
Docker post-installation) and read logs with
docker logs/Dozzle. If you do centralise logs, a Loki driver looks like this. Add to /etc/docker/daemon.json to send all container logs to Loki without changing compose files:
{
"log-driver": "loki",
"log-opts": {
"loki-url": "http://localhost:3100/loki/api/v1/push",
"loki-batch-size": "400",
"loki-retries": "3",
"loki-max-backoff": "800ms",
"loki-timeout": "2s"
}
}
# Install the Loki Docker driver plugin first
# (pin a version tag in production instead of :latest)
docker plugin install grafana/loki-docker-driver:latest \
--alias loki \
--grant-all-permissions
# Restart Docker to apply
sudo systemctl restart docker
Remote Syslog Forwarding (rsyslog)¶
Not installed by default on Debian: sudo apt install rsyslog first. It reads the journal and forwards it.
# Forward to remote syslog server
sudo nano /etc/rsyslog.d/90-forward.conf
# Add (one of):
*.* @@192.168.1.50:514 # TCP (@@)
*.* @192.168.1.50:514 # UDP (@)
Audit Log (auditd)¶
For tracking file access, user commands, or privilege escalation:
sudo apt install auditd
# Watch a file for reads/writes
sudo auditctl -w /etc/passwd -p rwa -k passwd-watch
# View audit log
sudo ausearch -k passwd-watch
sudo aureport --summary