Configure retention and compression for Docker container logs with journald + logrotate + rsyslog on a low-disk VPS
Linux & Sistemas · By Kevin Marcondes · Published on · 8 min read
This tutorial shows how to configure retention and compression for Docker container logs using journald + logrotate + rsyslog on a VPS with limited disk. You will limit disk usage, compress old per-container files, and keep traceability without relying on json-file, using testable and reversible steps.
Prerequisites and goals of this setup
The idea is to use journald as Docker's logging driver, extract events via rsyslog and rotate/compress them with logrotate. This way you control disk usage without losing recent history.
You need a Linux server with systemd (e.g. Debian/Ubuntu), root access, Docker installed and the rsyslog and logrotate packages. Tests must be done outside production first. For an overview of strategies, see the guide on reducing disk usage from Docker container logs: Reduce Docker container log disk usage on VPS.
- Linux with systemd (journald active)
- Docker Engine installed
- rsyslog and logrotate installed
- Root or sudo access
# Instalar rsyslog e logrotate (Debian/Ubuntu)
sudo apt-get update && sudo apt-get install -y rsyslog logrotate
# Garantir que rsyslog e journald estão ativos
systemctl is-active rsyslog systemd-journald
How much space are logs using now?
Before changing anything, measure current usage. If you're still using Docker's json-file, the .log files are under /var/lib/docker/containers. journald reports total usage with journalctl --disk-usage.
# Se o Docker ainda usa json-file (padrão), estime o espaço atual
sudo du -sh /var/lib/docker/containers/*/*-json.log 2>/dev/null | sort -h | tail -n 20
# Uso de disco do journald (persistente e runtime somados)
journalctl --disk-usage
# Espaço livre no filesystem de logs
df -h /var/log /var/lib/docker /
Which retention and compression policy to use on the VPS?
Limits come from two places: journald (the .journal binary files) and the text files generated by rsyslog. journald needs a cap on disk usage. Text files are rotated and compressed by logrotate.
The table below helps decide where each setting belongs.
| Component | What controls | Where to configure |
|---|---|---|
| systemd-journald | Maximum size and compression of .journal files | /etc/systemd/journald.conf |
| Docker (logging driver) | Where the container writes logs | /etc/docker/daemon.json |
| rsyslog (imjournal) | Reading from journald and writing text files | /etc/rsyslog.d/*.conf |
| logrotate | Rotation, compression and retention of text .log files | /etc/logrotate.d/*.conf |
Set Docker to use journald with a predictable tag
Configure Docker to use the journald driver and set a tag prefix. The tag becomes the program identifier (SYSLOG_IDENTIFIER) in journald and rsyslog. We'll use the ctn- prefix to filter only container messages.
Note: this change only affects new containers. Existing containers keep their current driver until recreated.
- Tag includes the container name: ctn-{{.Name}}
- Avoid slashes in the tag so it can become a filename later
- Recreate containers to apply the change
sudo mkdir -p /etc/docker
sudo tee /etc/docker/daemon.json >/dev/null <<'JSON'
{
"log-driver": "journald",
"log-opts": {
"tag": "ctn-{{.Name}}"
}
}
JSON
# Reinicie o Docker (impacta somente criação/stop/start de containers)
sudo systemctl restart docker
# Exemplo de (re)criação para aplicar o driver:
# docker compose up -d --force-recreate
Adjust journald retention (space limit and compression)
Set journald limits so it doesn't consume the entire disk. Storage=persistent ensures logs go to disk; SystemMaxUse/RuntimeMaxUse set caps. Compress=yes enables native compression of old journal files.
Choose values proportional to available disk. Do not copy the numbers below without evaluating your situation. See the journald retention and compression guide for more details.
- Storage=persistent creates/uses /var/log/journal
- SystemMaxUse limits the persistent total
- RuntimeMaxUse caps /run/log/journal (volatile)
- Compress=yes enables built-in compression
sudo sed -i.bak 's/^#\(Storage=\).*/\1persistent/' /etc/systemd/journald.conf
sudo sed -i 's/^#\(Compress=\).*/\1yes/' /etc/systemd/journald.conf
# Acrescente (ou ajuste) limites; edite conforme sua VPS
sudo tee -a /etc/systemd/journald.conf >/dev/null <<'CONF'
SystemMaxUse=500M
RuntimeMaxUse=100M
CONF
sudo systemctl restart systemd-journald
journalctl --disk-usage
Enable rsyslog to read from the journal and write per-container files
rsyslog can read events from journald (imjournal) and write text files. Since we set the tag ctn-{{.Name}}, we filter only messages from those containers and create one file per container under /var/log/containers.
Permissions: ensure only authorized users can read /var/log/containers. Logs may contain sensitive data.
- Load imjournal
- Per-container file template
- Filter by the ctn- prefix
- Create /var/log/containers directory
# Diretório para os arquivos em texto
sudo install -d -m 0750 -o root -g adm /var/log/containers
# Configuração do rsyslog
sudo tee /etc/rsyslog.d/30-containers.conf >/dev/null <<'RSYS'
module(load="imjournal" StateFile="imjournal.state")
# Template: um arquivo por container usando a tag (programname)
template(name="CtnLog" type="string" string="/var/log/containers/%programname%.log")
# Filtra somente mensagens com tag iniciando em ctn-
if $programname startswith "ctn-" then {
action(type="omfile" DynaFile="CtnLog" FileCreateMode="0640" DirCreateMode="0750")
stop
}
RSYS
sudo systemctl restart rsyslog
# Gere um log e confira a criação do arquivo em /var/log/containers
Rotation and compression with logrotate for rsyslog files
Use logrotate to rotate and compress files under /var/log/containers. copytruncate allows rotation without restarting rsyslog; adjust frequency and retention to match your policy.
You can combine size-based rotation and daily rotation. Force-rotating logs in production can discard buffers; proceed with caution.
- Compression with gzip (compress + delaycompress)
- copytruncate avoids reloading rsyslog
- rotate N sets how many copies to keep
- size X triggers rotation by size
sudo tee /etc/logrotate.d/containers >/dev/null <<'LR'
/var/log/containers/*.log {
daily # ou weekly
rotate 7 # ajuste retenção
size 50M # gira ao atingir ~50MB
compress
delaycompress
missingok
notifempty
copytruncate
dateext
dateformat -%Y%m%d
}
LR
# Teste em modo debug (não executa ações destrutivas)
sudo logrotate -d /etc/logrotate.d/containers
How to confirm it worked and common issues
Validate each layer: journald receiving from containers, rsyslog writing files, and logrotate rotating/compressing. Generate test logs and observe results. If something doesn't appear, check that the container was recreated with the correct driver.
Old containers still using json-file keep their previous driver. Recreate them with Docker Compose or stop/start them with the same options.
Files growing too large: lower SystemMaxUse/RuntimeMaxUse in journald and/or reduce size/rotate in logrotate. Combine with cleaning images/volumes. See the BuildKit GC & systemd timers guide for cleanup automation.
Reading permissions: restrict the group on /var/log/containers and review legal retention requirements. For policies on servers, see the auditd, log rotation & LGPD guide.
Conflict with external centralization: if you ship logs to an aggregator, keep rsyslog writing only what's necessary, or skip the text-file step and rely solely on journald with proper limits.
- Check journald by tag ctn-
- Verify creation/rotation in /var/log/containers
- Force a controlled rotation for testing
# Suba um container de teste e gere logs
docker run --rm --name demo-log alpine sh -c 'for i in $(seq 1 2000); do echo "linha $i"; done'
# 1) journald por tag (SYSLOG_IDENTIFIER = ctn-demo-log)
journalctl -t ctn-demo-log -n 20 --no-pager
# 2) rsyslog escreveu arquivo por container
ls -lh /var/log/containers/
grep -n "linha" /var/log/containers/ctn-demo-log.log | head
# 3) Forçar rotação (apenas para teste)
sudo logrotate -vf /etc/logrotate.d/containers
ls -lh /var/log/containers/ | grep demo-log
Frequently asked questions
Do I need to restart all containers to use journald?
Yes. Docker's default driver setting only applies to new containers. Existing containers keep their current driver until recreated. Use docker compose up -d --force-recreate or stop and start the containers again.
Does journald compress logs by itself?
Yes. When Compress=yes is enabled in journald.conf, old journal files are compressed automatically. Still, set limits like SystemMaxUse to keep total disk usage under control.
Why use rsyslog and logrotate if journald already rotates?
journald rotates and compresses its own binary journal files. rsyslog lets you produce per-container text files useful for audits and integrations. logrotate controls retention and compression of those text files.
Can I keep only journald without text files?
Yes. Set Storage=persistent, enforce space limits, and use journalctl for queries. The rsyslog+logrotate flow is optional and useful when you need readable files for external tools.
Will this affect container performance?
In general, the journald driver has low overhead. Impact depends on log volume and VPS I/O. If you see spikes, tune buffers and rotation limits and avoid verbose logging in production.
How do I choose correct values for SystemMaxUse and rotate/size?
Use available disk and average log volume as guides. Start with conservative limits, monitor for a few days (journalctl --disk-usage and du on the directories) and adjust gradually.
Want this logging policy applied safely?
If you need to adapt retention, compression and rotation for your container logs, let's discuss your environment and disk constraints.
Discuss your caseSee also
- Tutorial: set up mTLS between Traefik and Docker Compose services using smallstep CA and automatic certificates — step by step
- Tutorial: integrate Sentry into your GitHub Actions deploy pipeline — automatic source map upload & issue creation (PHP & JavaScript)
- Tutorial: Configure GitHub Actions for integration tests with PostgreSQL in ephemeral containers and automatic migration rollback — a practical guide
- Configure BuildKit garbage collection and systemd timers to auto‑clean Docker images and volumes: a practical tutorial