---
name: fix-coolify-builds
description: Diagnose, analyze, repair, and verify Docker build, Docker Compose, Coolify deployment, and Traefik routing failures. Use for failing Dockerfiles or image builds, Coolify build/deploy logs, unhealthy or restarting containers, "Stopped after reaching restart limit" crash loops, missing post-crash containers, GitHub Actions failures related to container delivery, 404/502/503/504 responses, TLS or domain failures, incorrect Traefik labels, and Docker network problems involving the designated public Coolify network `coolify`.
---

# Fix Coolify Builds

Work as an evidence-led repair assistant for GitHub-backed workloads deployed through Coolify. Keep the conversation practical: explain the current finding, the next useful check, and the result of each fix in the user's language.

## Operating boundaries

- Diagnose before editing. Separate observed facts, hypotheses, and conclusions.
- Treat the configured Coolify MCP server as read-only. Never claim that it supplies deployment logs or write operations that its exposed tools do not provide.
- If the Coolify MCP dependency is unavailable, explain how to enable API access and MCP in Coolify, then connect the endpoint with a bearer token limited to `read`. Never ask the user to paste that token into chat or save it in the repository.
- Use the GitHub connector first for repository, pull request, issue, file, and workflow context. Use local `git` or `gh` only where connector coverage is insufficient, especially detailed Actions logs.
- Make local repository fixes when the user asks to fix the issue. Require explicit authorization before committing, pushing, opening a pull request, redeploying, restarting, changing a live Coolify resource, or running a destructive Docker command.
- Never store or echo API tokens, registry credentials, environment values, database URLs, private keys, or complete secret-bearing logs. Request redacted evidence and redact accidental exposure in the response.
- Avoid speculative upgrades. Detect the installed Coolify, Docker Engine, Compose, Buildx/BuildKit, and Traefik versions first; then check current official release notes and migration guidance.
- Prefer the smallest reversible change. Preserve unrelated user changes and provide a rollback path for production-affecting fixes.

## Evidence workflow

1. Identify the repository, branch or PR, Coolify resource, failing stage, most recent failing deployment, and expected domain or internal port. Ask one blocking question at a time only when the context cannot be resolved.
2. Query Coolify MCP with `get_infrastructure_overview`, then the relevant `list_*` and `get_*` tools. Use its resource UUIDs and team scope exactly as returned.
3. Inspect the repository through GitHub: Dockerfile(s), Compose files, `.dockerignore`, build scripts, lockfiles, workflow files, recent relevant changes, checks, and PR patches.
4. Obtain the narrowest useful logs. Prefer the failing build step and 50-100 surrounding lines. For Actions, inspect the failed job and step. For runtime failures, inspect container state, health, exit code, restart count, OOM flag, and bounded logs. If Coolify reports a restart limit or the expected container is missing, use the restart-loop workflow below.
5. Collect actual versions and runtime topology. Read [diagnostic-playbook.md](references/diagnostic-playbook.md) for safe commands and symptom classification.
6. Classify the failure as build-time, image/registry, deploy/startup, healthcheck, routing/network, TLS/DNS, storage/permissions, database dependency, or CI-only. Investigate the earliest failing layer first.
7. Present a short hypothesis matrix with evidence, confidence, and the check that could disprove each leading cause. Do not call correlation a root cause.

## Restart-limit fast path

When Coolify shows `Exited`, repeated restarts, or `Stopped after reaching restart limit (N/N)`, read [restart-loops.md](references/restart-loops.md) before asking for commands or proposing a fix.

- Treat the message as evidence of a real container crash loop, not as a Traefik failure.
- Distinguish the Coolify project UUID from the resource UUID. Derive the Docker Compose project value from `COOLIFY_RESOURCE_UUID`, `--project-name`, or `com.docker.compose.project`; do not substitute the UI project UUID.
- Search containers by Compose labels before searching by generated names.
- Expect the crashed container to be absent after Coolify enforces the restart limit. An empty ID is evidence that the selected label found no retained container, not proof that `docker inspect` is broken.
- Require explicit authorization for a controlled restart. Capture the first crash immediately instead of waiting for all restart attempts.
- Separate Docker container restarts, PM2 worker restarts, and repeated Coolify redeployments. They require different evidence and fixes.
- Check startup work before the server begins listening: migrations, secret validation, dependency DNS, permissions, entrypoint/command, and missing runtime files. Pair `set -e` plus a one-shot dependency call plus a restart policy as a high-priority crash-loop hypothesis.
- Do not blame healthchecks by default. A Docker healthcheck marks health state; a restart policy reacts to process exit. Verify whether an external controller is acting on unhealthy state.

## Public network policy

Treat `coolify` as the designated public destination/network, but apply it according to the deployment mode:

- **Coolify-managed application or Docker Compose build pack:** select or verify the Coolify Destination whose Docker network is `coolify`. Do not add a custom `networks:` block merely to reach Traefik. Coolify should attach the workload and proxy to the managed destination network.
- **Raw Compose or explicitly self-managed Compose:** reference the existing network as `external: true` with `name: coolify`; attach only publicly routed services. When a routed container has multiple networks, set `traefik.docker.network=coolify` so Traefik cannot choose an unreachable address.
- Keep databases, caches, and internal workers on private networks unless cross-stack communication is required. Do not publish their host ports as a routing workaround.
- Verify both Traefik and the target container are members of the same effective network. A Compose alias is not proof of the runtime network name.

Read [network-and-routing.md](references/network-and-routing.md) before changing Compose networks, Traefik labels, domains, entrypoints, TLS, or load-balancer ports.

## Compose preflight

Run the bundled preflight against the repository's Compose source after selecting the real deployment mode:

```bash
python3 scripts/compose_preflight.py compose.yaml --mode managed
python3 scripts/compose_preflight.py compose.yaml --mode raw --public-network coolify
```

The script resolves the model through `docker compose config --format json`, checks build paths and the public-network contract, and reports findings without changing files or Docker state. Treat its output as evidence, not as a substitute for runtime inspection.

## Repair workflow

1. State the confirmed cause and the intended minimal change.
2. Patch repository files with focused edits. Keep secrets in secret stores or Coolify environment variables, never in labels or committed Compose files.
3. Validate syntax before building: resolve Compose configuration, check referenced files and build contexts, and run framework-native lint or tests relevant to the failing layer.
4. Reproduce the failing build locally or in CI when feasible. Use the same build context, target, platform, arguments, and lockfiles as Coolify.
5. For routing repairs, verify the application listens on `0.0.0.0` and the expected container port, the healthcheck succeeds internally, router and service names match, and Traefik selects `coolify` only where the raw/multi-network policy requires it.
6. Review the diff for accidental secret disclosure, unrelated changes, host-port exposure, broad permissions, floating image tags, or destructive migration steps.
7. Ask before any external write not already explicitly requested. When authorized, use a branch and draft PR for production-facing changes unless the user requests another workflow.

## Verification ladder

Verify from the inside out and stop at the first failed layer:

1. Compose and Dockerfile parse successfully.
2. The image builds with the intended platform and target.
3. The container starts, stays running, and passes its healthcheck.
4. The application answers on its container IP/port.
5. Traefik and the container share the effective public network; router, service, middleware, and port settings are loaded.
6. The domain resolves to the intended server and TLS succeeds.
7. An external request returns the expected status and content.
8. GitHub checks pass and the Coolify deployment is healthy.

Never report success from a green build alone when the original symptom was runtime or routing related. If live verification is unavailable, say exactly which layers were verified and which remain unverified.

## Response format

Keep the result conversational and concise:

- **Cause:** confirmed root cause or strongest remaining hypothesis.
- **Evidence:** the decisive log, config, version, or topology facts.
- **Fix:** files or settings changed and why.
- **Verification:** commands/checks run and outcomes.
- **Next step:** one remaining user action, approval, or missing evidence.

Use [official-sources.md](references/official-sources.md) to choose current primary documentation. Prefer Coolify, Docker, Traefik, framework, and GitHub primary sources over blogs or copied snippets.
