1. Docs
  2. Self-Hosted
  3. Best Practices

Maintaining your Docker Compose host

A Tines deployment on Docker Compose uses more disk space over time. Each upgrade leaves the images from the previous version on the host, containers write logs continuously, and the build cache grows. When the host runs out of space, Tines stops processing events and PostgreSQL refuses writes.

This page covers what uses disk space, how to reclaim it safely, and which commands delete your data.

What uses disk space

Named volumes

The Docker Compose topology we supply defines five named volumes. Docker prefixes each one with the Compose project name, which is usually the directory you run Tines from, so db-data appears as tines_db-data.

Deleting db-data or db-pg18-data destroys your Tines database. Deleting redis-data loses queued work and valid user sessions. Deleting python-packages or npm-packages breaks script actions until you republish those packages.

Data you can reclaim

Images from previous versions usually take the most space. Every upgrade pulls new tines-app, tines-nginx, and tines-command-runner images and leaves the previous ones on the host.

Container logs grow continuously. The tines-app and tines-sidekiq services produce the most.

Build cache accumulates only when you build images on the host, such as custom runtimes.

Checking disk usage

Check free space on the host:

df -h

Check how much of that Docker uses:

docker system df

The RECLAIMABLE column shows how much you can recover. For a breakdown by image, container, and volume:

docker system df -v

Container logs do not appear in docker system df. To find large log files:

docker ps -a --format '{{.Names}}' | while read -r c; do
  log=$(docker inspect --format '{{.LogPath}}' "$c" 2>/dev/null)
  [ -n "$log" ] && printf '%-40s %s\n' "$c" "$(sudo du -h "$log" 2>/dev/null | cut -f1)"
done | sort -k2 -h

Reading log files requires root, so this command uses sudo.

Taking a backup

See data backup recommendations for a full backup strategy. We recommend that you take one of the following before you reclaim space.

Dump the database with pg_dump

Confirm the database name first. It is the DATABASE_NAME in your .env file, and is typically tines_production:

docker compose exec -T db sh -c 'PGPASSWORD="$POSTGRES_PASSWORD" psql -U "$POSTGRES_USER" -l'

Then dump it:

docker compose exec -T db sh -c 'PGPASSWORD="$POSTGRES_PASSWORD" pg_dump -U "$POSTGRES_USER" -d tines_production' \
  | gzip > tines-$(date +%F).sql.gz

Use db-pg18 in place of db after you migrate to PostgreSQL 18.

Use pg_dump rather than pg_dumpall. pg_dumpall reads pg_authid and fails unless the database user is a superuser, and Tines supports a non-superuser PostgreSQL user.

Copy the volume

Tines must be stopped while you copy the volume:

docker compose stop
docker run --rm -v tines_db-data:/data:ro -v "$PWD":/backup alpine \
  tar czf /backup/db-data-$(date +%F).tar.gz -C /data .
docker compose start

Replace tines_db-data with the volume name from docker volume ls, and use tines_db-pg18-data after you migrate to PostgreSQL 18. A container running as root writes the archive, so root owns it. Use sudo to read or move it.

On an air-gapped host, use an image you already hold, such as your PostgreSQL image, in place of alpine. Any image that provides tar works.

Use docker compose stop rather than docker compose down. Both stop Tines, but down also removes the containers, which makes your volumes eligible for deletion by the prune commands below. To stop the services gracefully, follow the scale-down order in infrastructure maintenance, which drains the tines-sidekiq queue before it stops the data services.

Reclaiming space

Run these commands while Tines is running. None of them affect volumes.

Remove images from previous versions

docker image prune -a

This removes every image that no container references. After an upgrade, that means the images from your previous Tines version. The images the stack currently uses stay, because its containers reference them.

Run this while Tines is running. After docker compose down, no containers exist to reference the current images, so Docker removes those as well and the next docker compose up pulls them again. On an air-gapped host that pull fails.

Remove build cache

docker builder prune

Tines images are pulled rather than built, so this is usually safe. If you build custom runtimes on this host, the next build takes longer.

Remove stopped containers

docker container prune

This removes containers that have exited. It does not affect the containers in a running stack.

Remove the PostgreSQL 14 volume after migrating

The migration to PostgreSQL 18 leaves the PostgreSQL 14 volume in place so that you can roll back. We recommend that you keep it for at least 24 hours after the migration. Once you have confirmed that Tines works on PostgreSQL 18, remove it with the docker volume rm command the migration script prints when it finishes. See upgrading from PostgreSQL 14 to PostgreSQL 18.

This usually recovers the most space, because the volume holds a complete copy of your database.

Commands that delete your data

The following commands delete named volumes. We recommend that you do not run them on a Tines host unless you have a current backup and intend to destroy data.

docker compose down --volumes

This removes every named volume declared in your Compose file, including both database volumes. It does not ask for confirmation.

docker volume prune --all

This removes all unused volumes, including named ones. A volume counts as unused when no container references it. docker compose down removes the containers, so after it runs every Tines volume qualifies.

docker volume rm <volume>

This removes a named volume directly.

Commands that do not delete named volumes

From Docker 23.0, docker volume prune without --all removes only anonymous volumes. Your named Tines volumes remain, even when the stack is stopped. docker system prune --volumes also removes only anonymous volumes.

Docker versions before 23.0 removed named volumes with docker volume prune. Check which version you run:

docker version --format '{{.Server.Version}}'

The --all and --volumes flags are what change this behavior.

Reducing future disk usage

Rotate container logs

The docker-compose.yml we supply applies a log rotation policy to every service:

x-default-logging: &default-logging
  driver: json-file
  options:
    max-size: "100m"
    max-file: "10"
    compress: "true"

This limits each service to about 1 GB before compression. A full stack still uses several gigabytes, so include that in your disk sizing.

If you deployed Tines before we added this policy, your services may have no limit and a log file can grow until the host fills. We recommend that you either add the policy to each service in your docker-compose.yml, or set a default for the host in /etc/docker/daemon.json:

{
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "100m",
    "max-file": "10"
  }
}

Restart Docker after you edit daemon.json. The policy applies only to containers created afterwards, so recreate the stack to apply it:

docker compose up -d --force-recreate

If you ship logs off the host, or rotate them at the host level, set the driver to journald and remove the json-file options.

Remove old images after every upgrade

We recommend that you run docker image prune -a at the end of each upgrade, once Tines is running and you have confirmed that the new version works. This stops images from previous versions accumulating on the host.

Monitor free disk space

We recommend that you alert on the Tines host at 75% disk usage, so that you have time to act before it fills.

Was this helpful?