Set up comprehensive Linux logging infrastructure using rsyslog for traditional syslog handling and journald for systemd service logs. Configure remote logging, log rotation, filtering rules, and troubleshoot common logging performance issues.
Prerequisites
- Root or sudo access
- Basic understanding of Linux system administration
- Network connectivity for remote logging setup
What this solves
Modern Linux systems use both rsyslog and journald for logging, which can create confusion and fragmented log management. This tutorial shows you how to configure both systems to work together effectively, set up centralized logging for multiple servers, implement proper log retention policies, and optimize logging performance for production environments.
Understanding Linux logging architecture
Linux logging involves two primary systems that serve different purposes. The journald service, part of systemd, captures all system and service logs in binary format with structured metadata. The rsyslog daemon handles traditional syslog messages in text format and provides powerful filtering, formatting, and forwarding capabilities.
By default, journald forwards messages to rsyslog, which then writes them to files in /var/log. This dual approach gives you the benefits of structured logging from journald and the flexibility of traditional syslog processing from rsyslog. Understanding this relationship is crucial for effective log management.
Step-by-step configuration
Update system packages
Start by updating your package manager and installing the required logging components.
sudo apt update && sudo apt upgrade -y
sudo apt install -y rsyslog rsyslog-relp logrotate
Configure journald persistent storage
By default, journald stores logs in memory only. Configure persistent storage to retain logs across reboots.
[Journal]
Storage=persistent
Compress=yes
Seal=yes
SplitMode=uid
SyncIntervalSec=5m
RateLimitInterval=30s
RateLimitBurst=10000
SystemMaxUse=4G
SystemKeepFree=1G
SystemMaxFileSize=128M
SystemMaxFiles=100
MaxRetentionSec=2month
MaxFileSec=1month
ForwardToSyslog=yes
ForwardToKMsg=no
ForwardToConsole=no
ForwardToWall=yes
Create journald storage directory
Create the persistent storage directory with correct permissions for journald.
sudo mkdir -p /var/log/journal
sudo chown root:systemd-journal /var/log/journal
sudo chmod 2755 /var/log/journal
Configure rsyslog main configuration
Set up the main rsyslog configuration with modern features and security settings.
# Global configuration
$ModLoad imuxsock # provides support for local system logging
$ModLoad imklog # provides kernel logging support
$ModLoad imjournal # provides access to the systemd journal
$ModLoad immark # provides --MARK-- message capability
High precision timestamps
$ActionFileDefaultTemplate RSYSLOG_TraditionalFileFormat
$template HighPrecision,"%timegenerated:::date-rfc3339% %HOSTNAME% %syslogtag%%msg%\n"
$ActionFileDefaultTemplate HighPrecision
Work directory
$WorkDirectory /var/spool/rsyslog
Include all config files in /etc/rsyslog.d/
$IncludeConfig /etc/rsyslog.d/*.conf
Turn off message reception via local log socket
$OmitLocalLogging on
File syncing capability is disabled by default
$ActionFileEnableSync on
Set the default permissions for all log files
$FileOwner syslog
$FileGroup adm
$FileCreateMode 0640
$DirCreateMode 0755
$Umask 0022
$PrivDropToUser syslog
$PrivDropToGroup syslog
Standard log files
.;auth,authpriv.none -/var/log/syslog
auth,authpriv.* /var/log/auth.log
.;auth,authpriv.none -/var/log/syslog
cron.* /var/log/cron.log
daemon.* -/var/log/daemon.log
kern.* -/var/log/kern.log
lpr.* -/var/log/lpr.log
mail.* -/var/log/mail.log
user.* -/var/log/user.log
Configure remote logging client
Set up rsyslog to send logs to a central log server using reliable RELP protocol.
# Load RELP output module
$ModLoad omrelp
Configure remote logging with RELP
Replace log-server.example.com with your log server
$template RemoteHost,"/var/log/remote/%HOSTNAME%/%PROGRAMNAME%.log"
Send all logs to remote server
. :omrelp:log-server.example.com:2514
Also log locally (comment out if you only want remote logging)
& ~
Configure remote logging server
Set up a server to receive logs from multiple clients using RELP for reliability.
# Load RELP input module
$ModLoad imrelp
RELP listener
$InputRELPServerRun 2514
$InputRELPServerBindRuleset remote
Template for remote log files
$template RemoteLogs,"/var/log/remote/%HOSTNAME%/%PROGRAMNAME%.log"
Ruleset for remote logs
$RuleSet remote
$template RemoteFormat,"%timegenerated:::date-rfc3339% %HOSTNAME% %syslogtag%%msg%\n"
. ?RemoteLogs;RemoteFormat
& stop
Use default ruleset for local logs
$RuleSet RSYSLOG_DefaultRuleset
Create log filtering rules
Configure advanced filtering to separate logs by priority, facility, and custom criteria.
# High priority alerts to separate file
.err;.crit;.alert;.emerg /var/log/error.log
Application-specific filtering
:programname, isequal, "nginx" /var/log/nginx/access.log
& stop
:programname, isequal, "postfix" /var/log/mail.log
& stop
Filter by message content
:msg, contains, "Failed password" /var/log/failed-logins.log
:msg, contains, "authentication failure" /var/log/failed-logins.log
Rate limiting for noisy applications
:programname, isequal, "kernel" and $msg contains "audit"
{
action(type="omfile" file="/var/log/audit.log"
action.execonlyonceeveryinterval="60")
stop
}
Discard debug messages from specific applications
:programname, isequal, "systemd" and :syslogseverity, isequal, "7" stop
Configure log rotation policies
Set up logrotate with custom policies for different log types and retention requirements.
/var/log/syslog
/var/log/mail.log
/var/log/kern.log
/var/log/auth.log
/var/log/user.log
/var/log/daemon.log
/var/log/cron.log
/var/log/lpr.log
{
daily
rotate 30
missingok
notifempty
compress
delaycompress
sharedscripts
postrotate
/usr/lib/rsyslog/rsyslog-rotate
endscript
}
/var/log/error.log
{
daily
rotate 90
missingok
notifempty
compress
delaycompress
create 0640 syslog adm
postrotate
/usr/lib/rsyslog/rsyslog-rotate
endscript
}
/var/log/remote//.log
{
daily
rotate 7
missingok
notifempty
compress
delaycompress
create 0640 syslog adm
sharedscripts
postrotate
/usr/lib/rsyslog/rsyslog-rotate
endscript
}
Create custom journald retention policy
Configure journald cleanup service for automated log maintenance.
[Unit]
Description=Clean up old journal files
[Service]
Type=oneshot
ExecStart=/usr/bin/journalctl --vacuum-time=30d
ExecStart=/usr/bin/journalctl --vacuum-size=2G
Create journald cleanup timer
Set up automated cleanup to run weekly and keep journals within size limits.
[Unit]
Description=Weekly journal cleanup
Requires=journald-cleanup.service
[Timer]
OnCalendar=weekly
Persistent=true
[Install]
WantedBy=timers.target
Configure firewall for remote logging
Open the required port for RELP remote logging server.
sudo ufw allow 2514/tcp comment "RELP logging"
sudo ufw reload
Enable and restart services
Apply all configurations by restarting the logging services and enabling the cleanup timer.
sudo systemctl restart systemd-journald
sudo systemctl restart rsyslog
sudo systemctl enable --now journald-cleanup.timer
sudo systemctl status rsyslog
sudo systemctl status systemd-journald
Verify your setup
Test the logging configuration to ensure both journald and rsyslog are working correctly.
# Check journald status and recent logs
sudo journalctl --verify
journalctl -n 20 --no-pager
Test rsyslog configuration
sudo rsyslogd -N1
Check log file permissions
ls -la /var/log/syslog /var/log/auth.log
Test log generation
logger -p user.notice "Test message from logger command"
tail -f /var/log/syslog
Check remote logging (if configured)
sudo ss -tlnp | grep :2514
Verify log rotation configuration
sudo logrotate -d /etc/logrotate.d/rsyslog-custom
Performance optimization
For high-volume logging environments, optimize both journald and rsyslog performance. Configure journald to use appropriate rate limiting and rsyslog to handle high throughput efficiently.
Monitor disk I/O and memory usage during peak logging periods. Consider using asynchronous file writes in rsyslog and adjusting journal file sizes based on your log volume. System performance tuning can help optimize overall logging performance.
Integration with monitoring systems
Connect your centralized logging to monitoring and alerting systems for comprehensive observability. Export logs to time-series databases or integrate with log analysis platforms for advanced searching and alerting capabilities.
Consider implementing structured logging formats like JSON for better parsing and analysis. This integration works well with Prometheus and Grafana monitoring or Loki log aggregation systems.
Common issues
| Symptom | Cause | Fix |
|---|---|---|
| Logs not appearing in files | rsyslog configuration error | Run sudo rsyslogd -N1 to check config syntax |
| Journal files growing too large | Incorrect SystemMaxUse setting | Adjust SystemMaxUse and run sudo journalctl --vacuum-size=2G |
| Remote logging not working | Firewall blocking RELP port | Check firewall rules and network connectivity on port 2514 |
| Permission denied errors | Incorrect log directory permissions | Run sudo chown syslog:adm /var/log/filename and chmod 640 |
| High disk I/O from logging | Excessive log volume or sync issues | Enable async writes with $ActionFileEnableSync off and implement filtering |
| Journal corruption after crash | Unclean shutdown | Run sudo journalctl --verify and --rotate to fix corruption |
| Logrotate not working | Missing postrotate script | Ensure /usr/lib/rsyslog/rsyslog-rotate exists and is executable |
| Missing logs from containers | Docker logging driver misconfiguration | Configure Docker to use journald driver or forward to rsyslog |
Next steps
Automated install script
Run this to automate the entire setup
#!/usr/bin/env bash
set -euo pipefail
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'
# Configuration variables
LOG_SERVER=""
REMOTE_LOGGING=false
# Cleanup function
cleanup() {
echo -e "${RED}[ERROR] Installation failed. Restoring original configurations...${NC}"
if [ -f /etc/systemd/journald.conf.backup ]; then
mv /etc/systemd/journald.conf.backup /etc/systemd/journald.conf
fi
if [ -f /etc/rsyslog.conf.backup ]; then
mv /etc/rsyslog.conf.backup /etc/rsyslog.conf
fi
rm -f /etc/rsyslog.d/99-remote.conf
echo -e "${YELLOW}[WARNING] Cleanup completed. Original configurations restored.${NC}"
}
trap cleanup ERR
# Usage message
show_usage() {
echo "Usage: $0 [OPTIONS]"
echo "Options:"
echo " -s SERVER Configure remote log server (optional)"
echo " -h Show this help message"
echo ""
echo "Examples:"
echo " $0 # Local logging only"
echo " $0 -s log.example.com # With remote logging"
}
# Parse arguments
while getopts "s:h" opt; do
case $opt in
s)
LOG_SERVER="$OPTARG"
REMOTE_LOGGING=true
;;
h)
show_usage
exit 0
;;
\?)
echo -e "${RED}Invalid option: -$OPTARG${NC}" >&2
show_usage
exit 1
;;
esac
done
# Check prerequisites
echo -e "${BLUE}[0/8] Checking prerequisites...${NC}"
if [ "$EUID" -ne 0 ]; then
echo -e "${RED}[ERROR] This script must be run as root${NC}"
exit 1
fi
# Auto-detect distribution
if [ -f /etc/os-release ]; then
. /etc/os-release
case "$ID" in
ubuntu|debian)
PKG_MGR="apt"
PKG_UPDATE="apt update && apt upgrade -y"
PKG_INSTALL="apt install -y"
SYSLOG_USER="syslog"
SYSLOG_GROUP="adm"
;;
almalinux|rocky|centos|rhel|ol|fedora)
PKG_MGR="dnf"
PKG_UPDATE="dnf update -y"
PKG_INSTALL="dnf install -y"
SYSLOG_USER="root"
SYSLOG_GROUP="root"
;;
amzn)
PKG_MGR="yum"
PKG_UPDATE="yum update -y"
PKG_INSTALL="yum install -y"
SYSLOG_USER="root"
SYSLOG_GROUP="root"
;;
*)
echo -e "${RED}[ERROR] Unsupported distribution: $ID${NC}"
exit 1
;;
esac
else
echo -e "${RED}[ERROR] Cannot detect distribution${NC}"
exit 1
fi
echo -e "${GREEN}[SUCCESS] Detected distribution: $PRETTY_NAME${NC}"
# Update system packages
echo -e "${BLUE}[1/8] Updating system packages...${NC}"
$PKG_UPDATE
# Install required packages
echo -e "${BLUE}[2/8] Installing logging components...${NC}"
$PKG_INSTALL rsyslog logrotate
# Try to install rsyslog-relp if available
if $REMOTE_LOGGING; then
if $PKG_INSTALL rsyslog-relp 2>/dev/null; then
echo -e "${GREEN}[SUCCESS] rsyslog-relp installed${NC}"
else
echo -e "${YELLOW}[WARNING] rsyslog-relp not available, using UDP transport${NC}"
fi
fi
# Create backup of journald configuration
echo -e "${BLUE}[3/8] Configuring journald...${NC}"
cp /etc/systemd/journald.conf /etc/systemd/journald.conf.backup
# Configure journald
cat > /etc/systemd/journald.conf << 'EOF'
[Journal]
Storage=persistent
Compress=yes
Seal=yes
SplitMode=uid
SyncIntervalSec=5m
RateLimitInterval=30s
RateLimitBurst=10000
SystemMaxUse=4G
SystemKeepFree=1G
SystemMaxFileSize=128M
SystemMaxFiles=100
MaxRetentionSec=2month
MaxFileSec=1month
ForwardToSyslog=yes
ForwardToKMsg=no
ForwardToConsole=no
ForwardToWall=yes
EOF
# Create journald storage directory
echo -e "${BLUE}[4/8] Setting up journald storage...${NC}"
mkdir -p /var/log/journal
chown root:systemd-journal /var/log/journal
chmod 2755 /var/log/journal
# Create backup of rsyslog configuration
echo -e "${BLUE}[5/8] Configuring rsyslog...${NC}"
cp /etc/rsyslog.conf /etc/rsyslog.conf.backup
# Configure main rsyslog
cat > /etc/rsyslog.conf << EOF
# Global configuration modules
\$ModLoad imuxsock
\$ModLoad imklog
\$ModLoad imjournal
\$ModLoad immark
# High precision timestamps
\$template HighPrecision,"%timegenerated:::date-rfc3339% %HOSTNAME% %syslogtag%%msg%\\n"
\$ActionFileDefaultTemplate HighPrecision
# Work directory
\$WorkDirectory /var/spool/rsyslog
# Include all config files in /etc/rsyslog.d/
\$IncludeConfig /etc/rsyslog.d/*.conf
# Configuration settings
\$OmitLocalLogging on
\$ActionFileEnableSync on
# Set permissions and security
\$FileOwner $SYSLOG_USER
\$FileGroup $SYSLOG_GROUP
\$FileCreateMode 0640
\$DirCreateMode 0755
\$Umask 0022
# Drop privileges (Debian/Ubuntu only)
EOF
if [ "$PKG_MGR" = "apt" ]; then
cat >> /etc/rsyslog.conf << EOF
\$PrivDropToUser syslog
\$PrivDropToGroup syslog
EOF
fi
cat >> /etc/rsyslog.conf << 'EOF'
# Standard log files
*.*;auth,authpriv.none -/var/log/syslog
auth,authpriv.* /var/log/auth.log
*.*;auth,authpriv.none -/var/log/syslog
cron.* /var/log/cron.log
daemon.* -/var/log/daemon.log
kern.* -/var/log/kern.log
lpr.* -/var/log/lpr.log
mail.* -/var/log/mail.log
user.* -/var/log/user.log
# Emergency messages
*.emerg :omusrmsg:*
# News and mail logging
mail.info -/var/log/mail.info
mail.warn -/var/log/mail.warn
mail.err /var/log/mail.err
EOF
# Configure remote logging if requested
echo -e "${BLUE}[6/8] Setting up logging destinations...${NC}"
if $REMOTE_LOGGING && [ -n "$LOG_SERVER" ]; then
cat > /etc/rsyslog.d/99-remote.conf << EOF
# Load RELP output module (if available)
\$ModLoad omrelp
# Remote logging configuration
\$template RemoteHost,"/var/log/remote/%HOSTNAME%/%PROGRAMNAME%.log"
# Forward all logs to remote server
*.* @@$LOG_SERVER:514
# Also try RELP if module is loaded
*.* :omrelp:$LOG_SERVER:2514
EOF
echo -e "${GREEN}[SUCCESS] Remote logging configured to $LOG_SERVER${NC}"
else
echo -e "${YELLOW}[INFO] Local logging only${NC}"
fi
# Create necessary directories
mkdir -p /var/spool/rsyslog /var/log/remote
chown $SYSLOG_USER:$SYSLOG_GROUP /var/spool/rsyslog
chmod 755 /var/spool/rsyslog
# Restart and enable services
echo -e "${BLUE}[7/8] Restarting logging services...${NC}"
systemctl restart systemd-journald
systemctl restart rsyslog
systemctl enable systemd-journald
systemctl enable rsyslog
# Verify configuration
echo -e "${BLUE}[8/8] Verifying installation...${NC}"
# Check service status
if systemctl is-active --quiet systemd-journald; then
echo -e "${GREEN}[SUCCESS] systemd-journald is running${NC}"
else
echo -e "${RED}[ERROR] systemd-journald is not running${NC}"
exit 1
fi
if systemctl is-active --quiet rsyslog; then
echo -e "${GREEN}[SUCCESS] rsyslog is running${NC}"
else
echo -e "${RED}[ERROR] rsyslog is not running${NC}"
exit 1
fi
# Check log directories
if [ -d /var/log/journal ]; then
echo -e "${GREEN}[SUCCESS] Journal persistent storage configured${NC}"
else
echo -e "${RED}[ERROR] Journal directory not found${NC}"
exit 1
fi
# Test logging
logger "Test message from rsyslog configuration script"
sleep 2
if grep -q "Test message from rsyslog configuration script" /var/log/syslog 2>/dev/null; then
echo -e "${GREEN}[SUCCESS] Log message routing verified${NC}"
else
echo -e "${YELLOW}[WARNING] Could not verify log routing${NC}"
fi
# Clean up trap
trap - ERR
echo -e "${GREEN}[COMPLETE] Linux logging configuration completed successfully!${NC}"
echo ""
echo -e "${BLUE}Configuration Summary:${NC}"
echo "- journald: Persistent storage enabled with 2-month retention"
echo "- rsyslog: High precision timestamps and structured logging"
echo "- Log rotation: Managed by logrotate"
if $REMOTE_LOGGING; then
echo "- Remote logging: Configured to $LOG_SERVER"
fi
echo ""
echo -e "${YELLOW}Next steps:${NC}"
echo "- Review log files in /var/log/"
echo "- Monitor journald with: journalctl -f"
echo "- Check rsyslog status: systemctl status rsyslog"
if $REMOTE_LOGGING; then
echo "- Verify remote log delivery to $LOG_SERVER"
fi
Review the script before running. Execute with: bash install.sh