Blog

Docker, CI/CD, and Coolify deploys for Laravel, Node, and WordPress

Updated: 14 min read
DockerCI/CDCoolifyDevOpsLaravelWordPress

"Works on my machine" is expensive. The goal of Docker + CI/CD + Coolify is reproducibility: the same artifact that passed tests reaches staging and, when done right, production.

Applies to Laravel APIs, Node apps, modern front ends (including Astro SSR), and, when it makes sense, containerized WordPress. On projects with checkout or gateways, the pipeline is part of the product.

Recommended minimum pipeline

  1. PR: lint + typecheck + unit tests (and critical e2e if applicable).
  2. Multi-stage build: dependencies → build → small runtime.
  3. Immutable tag: registry/app:gitsha.
  4. Basic image scan.
  5. Deploy to staging on Coolify with the same variables (different values).
  6. Smoke / healthcheck.
  7. Promote to production with the same digest/tag.

Multi-stage (Laravel / Node)

  • deps: install Composer/npm with cache.
  • build: npm run build, php artisan optimize, assets.
  • runtime: final image with non-root user, no toolchain, no secrets.

Details that prevent incidents:

  • Ordered layers to avoid invalidating Composer cache on every change.
  • npm ci in CI, not loose npm install.
  • Non-root user + permissions on storage and bootstrap/cache.

Laravel release checklist

  1. Multi-stage image with PHP-FPM or Octane.
  2. Variables in Coolify/CI secrets, never in the image.
  3. Migrations as an explicit deploy step.
  4. Queues and scheduler with restart policy.
  5. Healthcheck: cheap route that verifies app + DB.
  6. Rollback: redeploy the previous SHA tag.

WordPress in Docker

  • Persistent volume for wp-content/uploads.
  • Secrets via env / wp-config generated at runtime.
  • Object cache (Redis) as a separate service when traffic demands it.
  • Multisite: watch domains, cookies, and paths.
  • DB + uploads backups before major updates.

Coolify configuration

  • Variables and secrets outside the Dockerfile.
  • Real healthcheck (HTTP 200, not just "the process exists").
  • Domains: canonical apex; www with 301 redirect.
  • Let's Encrypt SSL on both hosts.
  • Restart policies and accessible logs.
  • Staging and production separated.

Pre-production checklist

  • Tag = git SHA (not just latest)
  • Secrets absent from repo and Docker layers
  • Green healthcheck on staging
  • Migrations rehearsed + recent backup
  • Apex/www and SSL verified
  • Workers/cron alive after deploy
  • Written rollback plan

Common mistakes

  • Different rebuild in prod and you no longer know what is running.
  • Healthcheck hitting / with 301 redirect and marking unhealthy in a loop.
  • WordPress volumes owned by root.
  • Running migrate --force twice in parallel.
  • Forgetting the queue worker: web is up but webhooks are not processed.

A badly deployed checkout is a time bomb. The pipeline connects with payments, and security auditing .

Frequently asked questions

Does Coolify replace a CI pipeline?

Not entirely. Coolify shines at deploy, SSL, variables, and restarts. CI (lint/tests/build) remains the responsibility of GitHub Actions, GitLab CI, or another runner. The usual approach is to combine them.

Can WordPress run in Docker?

Yes, with care: volumes for uploads, correct permissions, and never leaving wp-config with secrets in the image. For simple sites it may not be worth it; for teams already living in containers, it is.

Should you use the latest tag in production?

It is best to avoid `latest` as the only reference. Tags with git SHA enable exact rollback.

What about database migrations?

Versioned migrations, executed as a controlled release step, with a reverse plan when applicable. Not as an official "manual in production" process.

Is www and SSL configured too?

Yes. On proxy/Coolify set canonical apex, Let's Encrypt SSL, and www→non-www redirect. Misconfigured DNS is a product bug, not a minor detail.