---
title: Maintaining your Docker Compose host
url: https://www.tines.com/stories/docs/self-hosted/best-practices/maintaining-your-docker-compose-host/
updated: 2026-10-23T17:56:30+00:00
---

*[tines.com](https://www.tines.com/llms.txt) › [Docs](https://www.tines.com/stories/docs/llms.txt) › [Self-Hosted](https://www.tines.com/llm/stories/docs/self-hosted.md) › [Best Practices](https://www.tines.com/llm/stories/docs/self-hosted/best-practices.md)*

# Maintaining your Docker Compose host

*[View on tines.com](https://www.tines.com/stories/docs/self-hosted/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.

> **WARNING:** Several Docker cleanup commands delete volumes, and Tines stores its database in a volume. We recommend that you take a current backup before you run any of them.

## 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`.


| Volume | Contents | If you delete it |
| --- | --- | --- |
| `db-data` | PostgreSQL 14 data directory | Destroys your Tines database |
| `db-pg18-data` | PostgreSQL 18 data directory | Destroys your Tines database |
| `redis-data` | Redis append-only file | Loses queued work and signed-in sessions |
| `python-packages` | Packages served by `pypi-server` | Breaks script actions until you republish |
| `npm-packages` | Packages served by `npm-registry` | Breaks script actions until you republish |



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:

```bash
df -h
```

Check how much of that Docker uses:

```bash
docker system df
```

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

```bash
docker system df -v
```

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

```bash
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](/stories/docs/self-hosted/best-practices/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`:

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

Then dump it:

```bash
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](/stories/docs/self-hosted/configuring-tines/using-a-non-superuser-postgres-user).

### Copy the volume

Tines must be stopped while you copy the volume:

```bash
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](/stories/docs/self-hosted/upgrade-tines/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

```bash
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

```bash
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

```bash
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](/stories/docs/self-hosted/upgrade-tines/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.

```bash
docker compose down --volumes
```

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

```bash
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.

```bash
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:

```bash
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:

```yaml
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`:

```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:

```bash
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.
