Description
When using a multi-stage Dockerfile with dockerfile_target_build set to a specific stage, Coolify's HEALTHCHECK detection parses the entire Dockerfile text instead of only the target stage. This causes incorrect healthcheck configuration to be applied.
Steps to Reproduce
- Create a multi-stage Dockerfile with two targets:
# === Stage: builder ===
FROM node:20-alpine AS builder
# ... build steps ...
# === Stage: api ===
FROM node:20-alpine AS api
COPY --from=builder /app/dist ./dist
HEALTHCHECK --interval=30s --timeout=5s --start-period=15s --retries=3 \
CMD node -e "require('http').get('http://localhost:3000/health', (r) => { process.exit(r.statusCode === 200 ? 0 : 1) })"
CMD ["node", "dist/main.js"]
# === Stage: worker ===
FROM node:20-alpine AS worker
COPY --from=builder /app/dist ./dist
# No HEALTHCHECK — this stage has no HTTP server
CMD ["node", "dist/worker.js"]
-
Create two Coolify applications from the same repo:
- API app:
dockerfile_target_build = api
- Worker app:
dockerfile_target_build = worker, Health Check disabled in UI
-
Deploy the Worker app.
Expected Behavior
- Worker app should have no healthcheck, because the
worker stage has no HEALTHCHECK instruction.
- Coolify should only parse HEALTHCHECK from the stage specified in
dockerfile_target_build.
Actual Behavior
- Coolify detects
HEALTHCHECK from the api stage and sets custom_healthcheck_found = true on the Worker app.
- The Worker container gets the API's healthcheck configuration applied, which fails because there's no HTTP server on port 3000.
- Adding
HEALTHCHECK NONE to the worker stage doesn't help — Coolify still detects the string "HEALTHCHECK" and parses the first occurrence (from the api stage).
Root Cause
In app/Models/Application.php, the parseHealthcheckFromDockerfile method:
// Line ~2146 (latest main branch, confirmed on v4.0.0-beta.470)
$hasHealthcheck = str($dockerfile)->contains('HEALTHCHECK');
This checks the entire Dockerfile content for the substring "HEALTHCHECK" without considering which stage is the build target. The subsequent foreach loop also processes the first HEALTHCHECK instruction found, regardless of which stage it belongs to.
The dockerfile_target_build value (used in ApplicationDeploymentJob.php for docker build --target) is not passed to or considered by parseHealthcheckFromDockerfile.
Suggested Fix
parseHealthcheckFromDockerfile should be stage-aware when dockerfile_target_build is set:
- Parse
FROM ... AS <stage_name> lines to identify stage boundaries
- Only search for
HEALTHCHECK within the target stage's line range
- Handle
HEALTHCHECK NONE as an explicit disable (currently not handled)
Workaround
Separate the Dockerfile into two files (e.g., Dockerfile.api and Dockerfile.worker) so each Coolify application only sees its own HEALTHCHECK configuration.
Environment
- Coolify version: v4.0.0-beta.470 (also confirmed on earlier v4.x)
- Build pack: Dockerfile
- Multi-stage: Yes, with
dockerfile_target_build
Additional Context
This issue affects any multi-stage Dockerfile where different stages have different healthcheck requirements (e.g., API server + background worker from the same codebase).
Description
When using a multi-stage Dockerfile with
dockerfile_target_buildset to a specific stage, Coolify's HEALTHCHECK detection parses the entire Dockerfile text instead of only the target stage. This causes incorrect healthcheck configuration to be applied.Steps to Reproduce
Create two Coolify applications from the same repo:
dockerfile_target_build=apidockerfile_target_build=worker, Health Check disabled in UIDeploy the Worker app.
Expected Behavior
workerstage has noHEALTHCHECKinstruction.dockerfile_target_build.Actual Behavior
HEALTHCHECKfrom theapistage and setscustom_healthcheck_found = trueon the Worker app.HEALTHCHECK NONEto the worker stage doesn't help — Coolify still detects the string "HEALTHCHECK" and parses the first occurrence (from the api stage).Root Cause
In
app/Models/Application.php, theparseHealthcheckFromDockerfilemethod:This checks the entire Dockerfile content for the substring "HEALTHCHECK" without considering which stage is the build target. The subsequent
foreachloop also processes the firstHEALTHCHECKinstruction found, regardless of which stage it belongs to.The
dockerfile_target_buildvalue (used inApplicationDeploymentJob.phpfordocker build --target) is not passed to or considered byparseHealthcheckFromDockerfile.Suggested Fix
parseHealthcheckFromDockerfileshould be stage-aware whendockerfile_target_buildis set:FROM ... AS <stage_name>lines to identify stage boundariesHEALTHCHECKwithin the target stage's line rangeHEALTHCHECK NONEas an explicit disable (currently not handled)Workaround
Separate the Dockerfile into two files (e.g.,
Dockerfile.apiandDockerfile.worker) so each Coolify application only sees its own HEALTHCHECK configuration.Environment
dockerfile_target_buildAdditional Context
This issue affects any multi-stage Dockerfile where different stages have different healthcheck requirements (e.g., API server + background worker from the same codebase).