Skip to content

CleanupDocker prunes standalone database containers when any service is deleted #9582

@frederikkrohn

Description

@frederikkrohn

Head-Up

This was AI-written because I can't code, but maybe this is true and helpful.

Summary

CleanupDocker runs docker container prune -f --filter "label=coolify.managed=true" after every service deletion. This indiscriminately removes any stopped container managed by Coolify — including standalone databases that are temporarily stopped (crash, OOM, restart loop). This permanently destroys production databases without any warning or soft-delete record.

Steps to Reproduce

  1. Have a standalone PostgreSQL (or Redis) database running and healthy.
  2. The database container crashes or stops briefly (OOM, healthcheck failure, temporary blip).
  3. Delete any service in the same Coolify instance — this triggers DeleteResourceJobStopServiceDeleteService, each of which dispatches CleanupDocker.
  4. CleanupDocker runs docker container prune -f --filter "label=coolify.managed=true" while the DB container is in Exited state.
  5. The standalone database container is permanently removed. Its volume may be subsequently pruned by Docker garbage collection or a later cleanup pass.

Observed Behavior

  • Standalone Database Postgres container (postgres-data-<uuid>) and its volume were completely gone from Docker after the above sequence.
  • The Coolify DB record for the postgres survived (no deleted_at, no soft delete) — only the Docker container and volume were destroyed.
  • DatabaseStatusChanged event fired ~14 seconds after the service deletion, confirming Docker detected the resource as gone.
  • No warning, no activity log entry, no UI notification.
  • Service depending on the database (trigger.dev) silently failed with no upstream.

Root Cause

In DeleteResourceJob.php (in the finally block) and in both StopService.php and DeleteService.php, CleanupDocker::dispatch($server, false, false) is called — resulting in 3 parallel CleanupDocker dispatches per service deletion.

CleanupDocker.php then runs:

'docker container prune -f --filter "label=coolify.managed=true" --filter "label!=coolify.proxy=true"',

This label filter matches all Coolify-managed containers — including standalone databases — not just ephemeral helper/builder containers. Any standalone database that is transiently stopped (crash window, restart loop, OOM) at the time of a service deletion will be removed.

The unless-stopped Docker restart policy creates a race condition: after a crash, the container briefly passes through Exited state before Docker restarts it. If CleanupDocker fires in that window, the container is gone before it can restart.

Expected Behavior

CleanupDocker should only prune ephemeral containers (helper containers, build containers) — not persistent resources like standalone databases. Standalone databases have their own coolify.type=database label that should be used to exclude them from container pruning.

Suggested Fix

Add an exclusion filter for database containers in the prune command:

// Before
'docker container prune -f --filter "label=coolify.managed=true" --filter "label!=coolify.proxy=true"',

// After
'docker container prune -f --filter "label=coolify.managed=true" --filter "label!=coolify.proxy=true" --filter "label!=coolify.type=database"',

Or alternatively, scope CleanupDocker to only target containers with coolify.type=helper or coolify.type=builder labels.

Environment

  • Coolify version: 4.0.0-beta.472
  • Docker version: (standard install via Coolify)
  • Server: VPS (Hetzner), single-server setup
  • Affected resources: Standalone PostgreSQL, Standalone Redis

Impact

Data loss risk. Any temporarily-stopped standalone database can be silently and permanently destroyed the next time a service is deleted from the Coolify UI. The Coolify database record survives (misleading the user into thinking the resource still exists), but the Docker container and volume are gone.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions