Configure retention and compression for Docker container logs with journald + logrotate + rsyslog on a low-disk VPS

Linux & Sistemas · By · Published on · 8 min read

stacked cut logs showing circular cross-sections and wood texture
Visual metaphor for system logs and data retention Photo: Birgit Böllinger / Pexels

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 case

See also