Logrotate è l’utility standard di Linux per la gestione automatizzata dei file di log testuali. Opera attraverso rotazione, compressione e rimozione programmata, evitando che i log di servizi come Nginx, Apache, MySQL e PHP-FPM saturino il disco. Su un web server LEMP/LAMP di produzione, logrotate gestisce tipicamente 15-30 configurazioni distinte.
Questa guida copre l’intero ciclo operativo di logrotate: dall’installazione alla configurazione avanzata, dall’esecuzione con systemd timer (che ha sostituito cron come default) fino alle configurazioni production-ready per i servizi più comuni. Include anche le sezioni su journald, container Docker/Kubernetes, sicurezza e troubleshooting.
A riguardo potrebbe interessarti la guida su come leggere il log del web server e l’approfondimento sull’analisi dei log di un web server Linux.
Cos’è logrotate e perché è ancora rilevante
Nel panorama Linux attuale convivono due sistemi di logging. Da un lato systemd-journald, che raccoglie log strutturati in formato binario da tutti i servizi gestiti da systemd, interrogabili con journalctl. Dall’altro, i tradizionali file di log testuali scritti direttamente dalle applicazioni in /var/log/ o in directory custom.
Logrotate opera esclusivamente sulla seconda categoria. Servizi come Nginx, Apache, MySQL, PHP-FPM, Varnish e qualsiasi applicazione custom che scrive log su file di testo necessitano ancora di un meccanismo di rotazione esterno. Senza logrotate, un access log di Nginx su un sito con 50.000 visite/giorno può crescere di 500 MB al mese, saturando rapidamente il disco.
Logrotate risolve il problema con un approccio dichiarativo: per ogni file di log si definisce una configurazione che specifica frequenza di rotazione, numero di copie da conservare, compressione, e comandi da eseguire prima o dopo la rotazione. Il tutto viene eseguito automaticamente da un timer di sistema.
Se logrotate è già installato sulla macchina, basta aprire una shell ed eseguire il comando seguente per verificare come i log di sistema vengano periodicamente ruotati e compressi:
ls -lh /var/log/*.gz /var/log/*.1 2>/dev/null
Installazione e versioni
Logrotate è preinstallato su tutte le distribuzioni Linux server principali. In caso contrario, l’installazione richiede un singolo comando.
Installazione su distribuzioni principali
# Debian / Ubuntu
apt install logrotate
# RHEL 9 / Rocky Linux / AlmaLinux
dnf install logrotate
# Verifica versione installata
logrotate --version
L’installazione crea i seguenti file e directory:
/etc/logrotate.conf— configurazione principale/etc/logrotate.d/— configurazioni per-servizio/var/lib/logrotate/status— file di stato con i timestamp delle ultime rotazioni/lib/systemd/system/logrotate.timer— timer systemd (distribuzioni moderne)
Versioni recenti e changelog
Il progetto logrotate è ospitato su GitHub e rilascia aggiornamenti regolari. Le versioni recenti hanno introdotto miglioramenti significativi in termini di sicurezza e funzionalità.
| Versione | Data | Novità principali |
|---|---|---|
| 3.22.0 | Giugno 2024 | Specifier %z in dateformat per offset timezone. Nomi utente/gruppo tra virgolette nella direttiva create. Permessi default olddir impostati a 0755. File di stato non scritto su file non regolari. |
| 3.21.0 | Dicembre 2023 | Nuova direttiva ignoreduplicates per pattern che matchano file duplicati. Opzione CLI --wait-for-state-lock per sincronizzazione tra istanze concorrenti. Espansione home directory in olddir. |
| 3.20.1 | Maggio 2023 | Fix critico CVE-2022-1348: vulnerabilità denial-of-service via file di stato. Hardening permessi del file di stato. Supporto time_t unsigned. |
Architettura di logrotate nel sistema operativo
Logrotate non è un demone residente in memoria. È un comando che viene eseguito periodicamente da un trigger esterno — storicamente cron, oggi systemd timer. A ogni esecuzione, logrotate segue questo flusso:
- Legge la configurazione principale (
/etc/logrotate.conf) e tutti i file inclusi tramite la direttivainclude - Consulta il file di stato (
/var/lib/logrotate/status) per determinare la data dell’ultima rotazione di ogni file di log - Per ogni file di log configurato, verifica se le condizioni di rotazione sono soddisfatte (tempo trascorso, dimensione del file)
- Esegue la rotazione: rinomina i file, crea nuovi file, esegue gli script
prerotate/postrotate, comprime i file archiviati - Aggiorna il file di stato con i nuovi timestamp
La configurazione è modulare: /etc/logrotate.conf contiene i default globali e una direttiva include /etc/logrotate.d che carica tutti i file presenti in quella directory. Ogni pacchetto software installa la propria configurazione in /etc/logrotate.d/, mantenendo il sistema organizzato e manutenibile.
Esecuzione con systemd timer
Su RHEL 9, Ubuntu 22.04+, Debian 12 e le distribuzioni derivate, logrotate non viene più eseguito tramite cron. Il meccanismo di default è un systemd timer, che offre vantaggi significativi in termini di affidabilità, logging e controllo delle risorse.
Perché systemd timer ha sostituito cron
Il passaggio da cron a systemd timer non è stato arbitrario. I timer systemd risolvono problemi concreti che cron non gestisce nativamente: esecuzione garantita dopo il boot se il timer è scaduto durante lo spegnimento (Persistent=true), integrazione diretta con il journal per logging centralizzato, isolamento delle risorse tramite cgroup, e gestione delle dipendenze tra servizi.
Su RHEL 9, il file /etc/cron.daily/logrotate non esiste più. Su Ubuntu 24.04, il pacchetto logrotate installa direttamente le unità systemd senza dipendenza da cron.
Unità logrotate.timer e logrotate.service
Il timer è composto da due file unit. Il primo definisce la schedulazione:
# /lib/systemd/system/logrotate.timer
[Unit]
Description=Daily rotation of log files
[Timer]
OnCalendar=daily
AccuracySec=12h
Persistent=true
[Install]
WantedBy=timers.target
Il secondo definisce il comando da eseguire:
# /lib/systemd/system/logrotate.service
[Unit]
Description=Rotate log files
[Service]
Type=oneshot
ExecStart=/usr/sbin/logrotate /etc/logrotate.conf
OnCalendar=daily schedula l’esecuzione una volta al giorno. AccuracySec=12h consente a systemd di ritardare l’esecuzione fino a 12 ore per ottimizzare le risorse. Persistent=true garantisce che, se il timer è scaduto durante lo spegnimento della macchina, logrotate venga eseguito immediatamente al boot successivo.
Comandi di gestione
# Verificare che il timer sia attivo
systemctl status logrotate.timer
# Vedere tutti i timer schedulati
systemctl list-timers --all | grep logrotate
# Consultare i log delle esecuzioni precedenti
journalctl -u logrotate.service --since "7 days ago"
# Eseguire manualmente (senza aspettare il timer)
systemctl start logrotate.service
Personalizzazione della frequenza
Per modificare la frequenza di esecuzione, ad esempio ogni 6 ore per server ad alto traffico, creare un override con systemctl edit:
# Crea un override del timer
systemctl edit logrotate.timer
Inserire nel file di override:
[Timer]
OnCalendar=
OnCalendar=*-*-* 00/6:00:00
La prima riga OnCalendar= (vuota) resetta il valore precedente; la seconda imposta l’esecuzione ogni 6 ore. Dopo la modifica, ricaricare la configurazione con systemctl daemon-reload.
Confronto systemd timer vs cron
| Aspetto | systemd timer | cron |
|---|---|---|
| Logging | Integrato in journald, consultabile con journalctl | Dipende da syslog/rsyslog |
| Catch-up dopo reboot | Persistent=true esegue al boot se scaduto | Richiede anacron |
| Isolamento risorse | Supporto cgroup nativo | Nessuno |
| Dipendenze | After/Requires per ordinamento | Non supportato |
| Debugging | systemctl status, journalctl -u | Grep su /var/log/syslog |
| Distribuzione | Default su RHEL 9, Ubuntu 22.04+, Debian 12 | Legacy, ancora presente su sistemi più vecchi |
Esecuzione con cron (legacy)
Sui sistemi che non utilizzano systemd o su distribuzioni più datate, logrotate viene eseguito tramite uno script in /etc/cron.daily/. Questo metodo è ancora funzionante ma non è più il default sulle distribuzioni recenti.
Lo script /etc/cron.daily/logrotate ha un contenuto minimale:
#!/bin/sh
test -x /usr/sbin/logrotate || exit 0
/usr/sbin/logrotate /etc/logrotate.conf
Lo script verifica l’esistenza del binario logrotate e lo esegue con il file di configurazione principale. L’orario di esecuzione è determinato da /etc/crontab:
25 6 * * * root test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.daily )
In questo esempio gli script giornalieri vengono eseguiti alle 6:25. È fondamentale assicurarsi che la macchina sia accesa in quell’orario; in caso contrario logrotate non verrà eseguito, causando la crescita incontrollata dei file di log. Per server non attivi 24/7, installare Anacron o migrare al timer systemd.
Come funziona la rotazione dei log
La rotazione prevede la cancellazione dell’ultimo file ruotato, mentre il suo posto viene preso dal penultimo, e così via lungo la catena. Consideriamo un esempio concreto: il log di accesso Nginx /var/log/nginx/access.log con rotazione settimanale e 3 copie (rotate 3).
Settimana 1
access.log viene rinominato in access.log.1. Viene creato un nuovo file access.log vuoto. Il processo Nginx riceve il segnale per scrivere sul nuovo file.
Risultato: access.log, access.log.1
Settimana 2
access.log.1 viene rinominato in access.log.2 (e compresso in access.log.2.gz se delaycompress è attivo). access.log diventa access.log.1. Viene creato un nuovo access.log.
Risultato: access.log, access.log.1, access.log.2.gz
Settimana 3
La catena si sposta di una posizione. access.log.2.gz diventa access.log.3.gz, e così via.
Risultato: access.log, access.log.1, access.log.2.gz, access.log.3.gz
Settimana 4 e successive
access.log.3.gz viene eliminato (superato il limite di rotate 3). Il file più vecchio viene sempre rimosso, mantenendo al massimo il numero di copie specificato.
Con la direttiva dateext, il naming cambia: invece di numerazione progressiva, logrotate aggiunge la data al nome del file (access.log-20260331.gz), rendendo più immediata l’identificazione temporale delle copie archiviate.
File di configurazione
La configurazione di logrotate è distribuita su più file, letti in sequenza come un unico flusso. Le opzioni definite nei file successivi sovrascrivono quelle dei file precedenti.
/etc/logrotate.conf
File di configurazione principale. Contiene i default globali applicati a tutti i log e la direttiva include che carica le configurazioni aggiuntive. Un esempio moderno da Ubuntu 24.04:
# /etc/logrotate.conf — Ubuntu 24.04
# Rotazione settimanale di default
weekly
# Mantieni 4 copie
rotate 4
# Crea nuovi file dopo la rotazione
create
# Comprimi i file ruotati
compress
# Ritarda la compressione di un ciclo
delaycompress
# Usa date nel nome dei file ruotati
dateext
# Non generare errore se il log non esiste
missingok
# Esegui come root:syslog su Ubuntu
su root syslog
# Carica le configurazioni per-servizio
include /etc/logrotate.d
La direttiva su root syslog (presente di default su Ubuntu) specifica con quali credenziali logrotate opera sui file, evitando problemi di permessi quando la directory dei log è di proprietà del gruppo syslog.
/etc/logrotate.d/
In questa directory sono contenuti i file di configurazione installati dai vari pacchetti software. Ogni servizio che genera log di testo installa qui la propria configurazione. Per vedere tutte le configurazioni attive:
ls -la /etc/logrotate.d/
Esempi comuni: /etc/logrotate.d/nginx, /etc/logrotate.d/mysql-server, /etc/logrotate.d/rsyslog. Ogni file contiene la configurazione specifica per i log di quel servizio e le opzioni scritte all’interno delle parentesi graffe sovrascrivono i default globali.
Nota: tutti i file in /etc/logrotate.d/ sono file di configurazione completi di logrotate. Un’opzione globale (fuori dalle parentesi graffe) si applica a tutti i file di log successivi. A meno che non ci sia un motivo specifico, le direttive in questi file devono essere sempre racchiuse dentro le parentesi graffe.
File di stato
Il file /var/lib/logrotate/status (il path può variare tra distribuzioni: /var/lib/logrotate.status su alcune) contiene i timestamp dell’ultima rotazione per ogni file di log. Logrotate consulta questo file a ogni esecuzione per decidere se la rotazione è necessaria.
# Esempio contenuto file di stato
"/var/log/nginx/access.log" 2026-3-31-6:25:1
"/var/log/nginx/error.log" 2026-3-31-6:25:1
"/var/log/mysql/error.log" 2026-3-28-6:25:1
A partire dalla versione 3.20.1, i permessi del file di stato sono stati rafforzati per prevenire la vulnerabilità CVE-2022-1348. Il file non viene più scritto su file non regolari (symlink, device file) come misura di sicurezza aggiuntiva.
Ordine di elaborazione e precedenza
Logrotate legge i file di configurazione in questo ordine:
/etc/logrotate.conf— dall’inizio fino alla rigainclude- I file in
/etc/logrotate.d/— in ordine alfabetico /etc/logrotate.conf— dalla riga dopoincludefino alla fine
Le opzioni globali (fuori dalle parentesi graffe) si applicano a cascata: un’opzione definita in logrotate.conf viene ereditata da tutti i file successivi, a meno che non venga sovrascritta localmente dentro le parentesi graffe di una specifica configurazione. I file con estensioni taboo (.rpmorig, .rpmsave, .swp, ~) vengono ignorati.
Direttive di logrotate
Le direttive si inseriscono nei file di configurazione dentro /etc/logrotate.d/ per controllare il comportamento della rotazione. Sono organizzate qui per categoria funzionale.
Rotazione e frequenza
| Direttiva | Descrizione |
|---|---|
daily | Rotazione giornaliera. |
weekly | Rotazione settimanale (quando il giorno corrente è inferiore a quello dell’ultima rotazione o è passata più di una settimana). |
monthly | Rotazione al primo giorno del mese. |
yearly | Rotazione quando l’anno corrente cambia. |
rotate N | Mantieni N copie ruotate. rotate 0 elimina subito i file ruotati. |
maxage N | Elimina i file ruotati più vecchi di N giorni. |
size S | Ruota solo quando il file supera la dimensione S (100k, 10M, 1G). Ignora i criteri temporali. |
minsize S | Ruota quando il file supera S E l’intervallo temporale è scaduto. |
maxsize S | Ruota quando il file supera S, indipendentemente dall’intervallo temporale. Utile per log ad alto volume. |
notifempty | Non ruotare il log se è vuoto. |
ifempty | Ruota anche se vuoto (default). |
missingok | Non generare errore se il file di log non esiste. |
Compressione
| Direttiva | Descrizione |
|---|---|
compress | Comprimi i file ruotati con gzip (default). |
nocompress | Non comprimere i file ruotati. |
compresscmd CMD | Usa un comando di compressione alternativo (es. bzip2, xz, zstd). |
uncompresscmd CMD | Comando per la decompressione (default: gunzip). |
compressext EXT | Estensione per i file compressi (segue il comando di compressione configurato). |
compressoptions OPT | Opzioni per il comando di compressione. Default per gzip: -9 (compressione massima). |
delaycompress | Rinvia la compressione al ciclo successivo. Essenziale quando il servizio potrebbe ancora scrivere sul file appena ruotato. |
Naming e archiviazione
| Direttiva | Descrizione |
|---|---|
dateext | Usa la data nel nome del file ruotato (es. access.log-20260331) invece della numerazione progressiva. |
dateformat FMT | Formato della data per dateext. Specifier ammessi: %Y, %m, %d, %s, %z (3.22.0+). Default: -%Y%m%d. I valori devono essere ordinabili lessicograficamente. |
extension EXT | Mantieni l’estensione originale dopo la rotazione. Es. mylog.1.foo.gz anziché mylog.foo.1.gz. |
olddir DIR | Sposta i file ruotati nella directory specificata. Deve trovarsi sullo stesso filesystem. |
noolddir | Ruota nella stessa directory del file originale (default). |
start N | Numerazione iniziale dei file ruotati. Default: 1. |
Creazione e permessi
| Direttiva | Descrizione |
|---|---|
create MODE OWNER GROUP | Crea il nuovo file di log subito dopo la rotazione con i permessi specificati. Es. create 0640 www-data adm. |
nocreate | Non creare un nuovo file di log dopo la rotazione. |
copy | Copia il file di log senza modificare l’originale. Utile per snapshot. |
copytruncate | Copia il file e tronca l’originale a zero byte. Usare solo quando il servizio non supporta la riapertura del file di log. Rischio: piccola finestra di perdita dati tra copia e troncamento. |
su USER GROUP | Esegui la rotazione con le credenziali specificate. Fondamentale quando la directory dei log non è di proprietà di root. Es. su www-data adm. |
Dalla versione 3.22.0, i nomi utente e gruppo nella direttiva create possono essere racchiusi tra virgolette per supportare nomi contenenti spazi.
Script hooks
| Direttiva | Descrizione |
|---|---|
prerotate/endscript | Comandi eseguiti (con /bin/sh) prima della rotazione, solo se la rotazione avverrà effettivamente. |
postrotate/endscript | Comandi eseguiti dopo la rotazione. Uso tipico: segnalare al servizio di riaprire il file di log. |
firstaction/endscript | Eseguito una volta prima di qualsiasi rotazione nel pattern. |
lastaction/endscript | Eseguito una volta dopo tutte le rotazioni nel pattern. |
sharedscripts | Esegui prerotate/postrotate una sola volta per l’intero pattern, non per ogni singolo file. Indispensabile quando il pattern matcha più file. |
nosharedscripts | Esegui gli script per ogni singolo file ruotato (default). |
Inclusione e filtering
| Direttiva | Descrizione |
|---|---|
include FILE_OR_DIR | Legge il file o tutti i file nella directory specificata come configurazioni aggiuntive. I file nella directory vengono letti in ordine alfabetico. |
tabooext [+] LIST | Lista di estensioni da ignorare quando si leggono directory con include. Default: .rpmorig, .rpmsave, .swp, ~. Il prefisso + aggiunge alla lista anziché sostituirla. |
ignoreduplicates | (3.21.0+) Ignora i file duplicati matchati da pattern diversi, evitando errori di “duplicate log entry”. |
Opzioni della riga di comando
| Opzione | Descrizione |
|---|---|
-d, --debug | Dry-run: mostra cosa verrebbe fatto senza apportare modifiche. Implica -v. |
-f, --force | Forza la rotazione di tutti i log, anche se non necessaria. Utile dopo modifiche alla configurazione. |
-v, --verbose | Modalità verbosa. Mostra i dettagli delle operazioni eseguite. |
-s, --state FILE | Usa un file di stato alternativo. Utile quando logrotate viene eseguito da utenti diversi per set di log distinti. |
-l, --log FILE | Scrivi i messaggi di log nel file specificato anziché su stderr. |
-m, --mail CMD | Comando per l’invio dei log via email. Default: /bin/mail -s. |
--wait-for-state-lock | (3.21.0+) Attendi il rilascio del lock sul file di stato anziché fallire immediatamente. Utile quando più istanze di logrotate possono essere eseguite in parallelo. |
Configurazioni pratiche per servizi comuni
Le configurazioni seguenti sono testate in produzione e rappresentano le best practice attuali per i servizi più comuni su un web server Linux.
Nginx
/var/log/nginx/*.log {
daily
rotate 14
compress
delaycompress
missingok
notifempty
create 0640 www-data adm
sharedscripts
postrotate
[ -f /var/run/nginx.pid ] && kill -USR1 $(cat /var/run/nginx.pid)
endscript
}
Il segnale USR1 dice a Nginx di riaprire i file di log senza reload della configurazione. Questo è il metodo corretto per Nginx: non usare copytruncate perché Nginx mantiene un file descriptor aperto e continuerebbe a scrivere nel file ruotato (ora rinominato), non nel nuovo file. Con create + USR1, Nginx chiude il vecchio descriptor e apre il nuovo file.
Per approfondire la configurazione di Nginx, vedi la guida ai certificati SSL con Certbot su Nginx.
Apache HTTP Server
/var/log/apache2/*.log {
daily
rotate 14
compress
delaycompress
missingok
notifempty
create 0640 root adm
sharedscripts
postrotate
if invoke-rc.d apache2 status > /dev/null 2>&1; then
invoke-rc.d apache2 reload > /dev/null
fi
endscript
}
Apache gestisce la riapertura dei log tramite un reload graceful della configurazione. Lo script postrotate verifica prima che Apache sia in esecuzione per evitare errori.
MySQL / MariaDB
/var/log/mysql/*.log {
daily
rotate 7
compress
delaycompress
missingok
notifempty
create 0640 mysql adm
su mysql adm
postrotate
if [ -x /usr/bin/mysqladmin ]; then
/usr/bin/mysqladmin --defaults-file=/etc/mysql/debian.cnf flush-logs
fi
endscript
}
La direttiva su mysql adm è fondamentale: i file di log MySQL sono di proprietà dell’utente mysql e senza questa direttiva logrotate fallirebbe con errori di permessi. Il comando flush-logs dice a MySQL di chiudere e riaprire i file di log.
PHP-FPM
/var/log/php*-fpm.log {
daily
rotate 7
compress
delaycompress
missingok
notifempty
create 0640 www-data adm
postrotate
[ -r /run/php/php-fpm.pid ] && kill -USR1 $(cat /run/php/php-fpm.pid)
endscript
}
Come Nginx, PHP-FPM supporta il segnale USR1 per la riapertura dei file di log. Il pattern php*-fpm.log copre multiple versioni di PHP installate in parallelo.
Applicazioni custom
Per applicazioni che non supportano la riapertura dei file di log tramite segnale, usare copytruncate:
/var/log/myapp/*.log {
daily
rotate 30
compress
delaycompress
missingok
notifempty
copytruncate
su myapp myapp
maxsize 100M
}
In questo caso, copytruncate copia il contenuto del file e poi lo tronca a zero byte. L’applicazione continua a scrivere sullo stesso file descriptor senza interruzioni. La direttiva maxsize 100M forza la rotazione anche prima della scadenza temporale se il file supera i 100 MB — utile per log ad alto volume.
Logrotate e journald
Su sistemi con systemd, journald è il sistema di logging primario. Raccoglie log strutturati in formato binario da tutti i servizi systemd, dal kernel e dai messaggi syslog. La gestione dello spazio è automatica e configurabile in /etc/systemd/journald.conf.
# /etc/systemd/journald.conf — parametri di gestione spazio
[Journal]
SystemMaxUse=500M # Spazio massimo occupato dai journal
SystemKeepFree=1G # Spazio libero minimo da mantenere su disco
MaxRetentionSec=30day # Elimina i journal più vecchi di 30 giorni
MaxFileSec=1week # Ruota il file journal corrente ogni settimana
Logrotate e journald sono complementari, non in competizione. Journald gestisce i log dei servizi systemd (e li ruota autonomamente), mentre logrotate gestisce i file di log testuali scritti direttamente dalle applicazioni. Nella pratica, questa è la suddivisione tipica:
- Journald gestisce: log del kernel, log di systemd-resolved, log di servizi configurati per scrivere su stdout/stderr (catturati da systemd)
- Logrotate gestisce: access/error log di Nginx e Apache, slow query log di MySQL, log di PHP-FPM, log di applicazioni custom che scrivono su file
Per consultare i log di un servizio specifico tramite journald: journalctl -u nginx.service --since "1 hour ago". Per la rotazione manuale: journalctl --rotate && journalctl --vacuum-time=30d.
Logrotate in ambienti containerizzati
Nei container, la strategia di logging è fondamentalmente diversa rispetto ai server tradizionali. La regola generale è: le applicazioni containerizzate devono scrivere log su stdout/stderr, delegando la gestione alla piattaforma di orchestrazione.
Docker
Docker cattura stdout/stderr dei container tramite logging driver. Il driver di default (json-file) scrive i log in file JSON sul filesystem dell’host e supporta rotazione nativa:
# /etc/docker/daemon.json
{
"log-driver": "json-file",
"log-opts": {
"max-size": "10m",
"max-file": "5"
}
}
Questa configurazione limita ogni file di log a 10 MB e mantiene 5 copie, per un massimo di 50 MB per container. Logrotate è necessario in Docker solo quando le applicazioni scrivono su file di log montati come bind mount, una pratica da evitare quando possibile.
Kubernetes
In Kubernetes, il kubelet gestisce la rotazione dei log dei container con due parametri:
containerLogMaxSize— dimensione massima di ogni file di log (default: 10 MB)containerLogMaxFiles— numero massimo di file di log per container (default: 5)
Logrotate in Kubernetes è rilevante solo per i log a livello di nodo (/var/log/ sull’host) o per pod specifici che scrivono su persistent volume. Per il logging centralizzato, la pratica standard prevede agent di raccolta come Fluentd, Filebeat o Promtail che inviano i log a sistemi centralizzati (Elasticsearch, Loki).
Quando NON usare logrotate
La decisione è lineare:
- L’applicazione scrive su stdout/stderr → la piattaforma (Docker, Kubernetes) gestisce la rotazione. Non serve logrotate.
- L’applicazione scrive su file di testo su disco (direttamente o su volume montato) → serve logrotate o un meccanismo equivalente.
- I log vanno a un sistema centralizzato (syslog remoto, Fluentd, agent) → il sistema centralizzato gestisce retention e rotazione. Non serve logrotate.
Sicurezza e hardening
La direttiva su
Logrotate viene eseguito come root. Senza la direttiva su, logrotate accede alle directory dei log con i privilegi di root, il che può causare errori quando la directory dei log è di proprietà di un utente di servizio. L’errore tipico è:
error: skipping "/var/log/mysql/error.log" because parent directory has insecure permissions
(It's world readable and writable, or not owned by root)
La soluzione è sempre specificare su con l’utente e il gruppo proprietari della directory:
/var/log/mysql/*.log {
su mysql adm
# ...altre direttive
}
Permessi del file di stato
La vulnerabilità CVE-2022-1348 permetteva a un utente locale di causare un denial-of-service manipolando il file di stato. Dalla versione 3.20.1, logrotate applica controlli più stringenti:
- Il file di stato non viene scritto su file non regolari (symlink, device, pipe)
- I permessi del file di stato sono più restrittivi anche in presenza di ACL
Verificare che il file di stato abbia permessi corretti: ls -la /var/lib/logrotate/status. Deve essere leggibile/scrivibile solo da root.
Sicurezza degli script postrotate
Gli script postrotate vengono eseguiti come root tramite /bin/sh. Seguire queste regole:
- Usare sempre path assoluti nei comandi (
/usr/sbin/nginx, nonnginx) - Evitare interpolazione di variabili da fonti esterne
- Verificare l’esistenza del processo prima di inviare segnali (
[ -f /var/run/nginx.pid ] && ...) - Mantenere gli script minimali: un singolo comando per segnalare il servizio
Distruzione sicura con shred
Per file di log contenenti dati sensibili (log di autenticazione, log di transazioni), la direttiva shred sovrascrive i file prima della cancellazione, rendendo il recupero molto più difficile:
/var/log/auth.log {
daily
rotate 7
compress
shred
shredcycles 3
}
shredcycles 3 specifica il numero di passaggi di sovrascrittura. Considerare le implicazioni sulle performance per file di grandi dimensioni e il fatto che shred non è efficace su tutti i tipi di filesystem (es. filesystem copy-on-write come ZFS o Btrfs).
Per approfondimenti sulla sicurezza dei server, vedi la guida alla sicurezza di WordPress.
Troubleshooting
Errori comuni e soluzioni
| Errore | Causa | Soluzione |
|---|---|---|
parent directory has insecure permissions | La directory dei log non è di proprietà di root e manca la direttiva su | Aggiungere su USER GROUP con l’utente proprietario della directory |
error: stat of /var/log/X failed | Il file di log specificato nel pattern non esiste | Aggiungere missingok alla configurazione |
duplicate log entry for /var/log/X | Lo stesso file è matchato da più pattern in configurazioni diverse | Rimuovere il duplicato o usare ignoreduplicates (3.21.0+) |
| File di stato corrotto | Interruzione durante la scrittura, crash, disco pieno | Rinominare il file di stato (mv status status.bak) e lasciare che logrotate ne crei uno nuovo. Tutti i log verranno ruotati alla prossima esecuzione. |
| Log non vengono ruotati | Timer systemd non attivo o cron non configurato | Verificare con systemctl status logrotate.timer o controllare /etc/cron.daily/logrotate |
Debug con dry-run
Il dry-run è lo strumento essenziale per testare le configurazioni senza apportare modifiche. Esegue l’intera logica di logrotate mostrando cosa verrebbe fatto:
# Dry-run dell'intera configurazione
logrotate -d /etc/logrotate.conf
# Dry-run di un singolo file di configurazione
logrotate -d /etc/logrotate.d/nginx
L’output mostra per ogni file di log: se la rotazione è necessaria, quali file verrebbero rinominati, quali script verrebbero eseguiti. Eventuali errori di sintassi o di permessi vengono segnalati senza conseguenze. Eseguire sempre un dry-run dopo ogni modifica alla configurazione prima di attendere la prossima esecuzione automatica.
Forzare la rotazione manuale
# Forza la rotazione di tutti i log
logrotate -f /etc/logrotate.conf
# Forza la rotazione solo di Nginx
logrotate -f /etc/logrotate.d/nginx
La rotazione forzata è utile dopo l’aggiunta di nuove configurazioni, la rimozione manuale di vecchi file di log, o per verificare che lo script postrotate funzioni correttamente. Il file di stato viene aggiornato con i nuovi timestamp.
Verificare i log di esecuzione
Per verificare che logrotate venga eseguito regolarmente e senza errori:
# Sistemi con systemd timer
journalctl -u logrotate.service --since "7 days ago"
# Sistemi con cron
grep logrotate /var/log/syslog
# Ultimo timestamp di esecuzione
cat /var/lib/logrotate/status | head -20
Per un monitoraggio più completo dei log del server, vedi la guida all’analisi log con tail e l’approfondimento su come fare SEO da terminale.
Conclusione
Logrotate resta il tool di riferimento per la gestione dei file di log testuali su Linux. I punti chiave da ricordare:
- Execution layer: il meccanismo di trigger è migrato da cron a systemd timer su tutte le distribuzioni recenti. Verificare con
systemctl status logrotate.timer. - Direttiva su: sempre specificarla quando la directory dei log non è di proprietà di root. È la causa più comune di errori.
- create vs copytruncate: preferire
createcon segnaleUSR1/reloadal servizio. Usarecopytruncatesolo come fallback quando il servizio non supporta la riapertura dei log. - Container: in ambienti Docker/Kubernetes, valutare se logrotate è davvero necessario. Se l’applicazione scrive su stdout/stderr, la piattaforma gestisce la rotazione autonomamente.
- Test: eseguire
logrotate -ddopo ogni modifica alla configurazione prima di affidarsi all’esecuzione automatica.
Riferimenti: repository GitHub logrotate, man page logrotate.conf(5), man page logrotate(8).
Articoli correlati
Autore
Mi chiamo Giovanni Sacheli e dal 2009 aiuto le aziende a farsi trovare online. Sono specializzato in SEO tecnica e PPC, competenze che applico quotidianamente nella mia agenzia, Searcus Swiss Sagl. Mi piace sviluppare strumenti a supporto del mio lavoro, ho creato SEOdata.app e cluster.army e co-scritto il libro SEO Audit Avanzato. Curo maniacalmente questo blog per colleghi e appassionati, dove mi "appunto" quello che imparo. Sono un NERD anni '80, motociclista e orgoglioso papà di due bambini.
Link:
Giovanni Sacheli
SEO Audit Avanzato
Searcus Swiss Sagl
SEOdata.app
cluster.army