Migrating Survais from an old VPS to Coolify
Today I migrated Survais from an old VPS setup to a new VPS managed through Coolify, using a single Docker Compose stack for both the PHP app and MariaDB.
The main goal was operational predictability: deploy the same way every time, make first boot deterministic, and avoid fragile one-off setup steps.
What I changed
- split runtime into two services in
docker-compose.yml:app(PHP/Apache)db(MariaDB)
- added service health checks and
depends_onreadiness behavior so app startup waits for DB health - switched app networking to internal
expose: 80rather than fixed host port mapping for Coolify
Database seeding strategy
The key migration decision was to bake seed SQL into a custom DB image:
Dockerfile.mariadbextendsmariadb:10.3- copies
ops/initdb/01-seed.sqlinto/docker-entrypoint-initdb.d/01-seed.sql
That means first boot on an empty volume imports data automatically, while later deploys keep existing data and skip reseeding.
I also documented recovery paths in ops/COOLIFY.md:
- manual import if DB exists but tables are missing
- full destructive reseed via
docker compose down -vwhen intentionally rebuilding from scratch
PHP container hardening
I updated the app image defaults to be safer for production:
display_errors=Offdisplay_startup_errors=Offhtml_errors=Offlog_errors=On- stricter
error_reportingto reduce noisy deprecated/strict output for this legacy stack
That keeps user-facing output clean while still preserving server-side logging.
Why this migration matters
For legacy PHP apps, deployment failures often come from environment drift and undocumented init steps.
This migration reduced those risks by making runtime behavior explicit:
- one compose file
- one seeded DB path
- clear env var contract (
DB_NAME,DB_USER,DB_PASS,DB_ROOT_PASSWORD) - written runbook for Coolify
What is next
After landing the infrastructure migration, I followed up with widget-level compatibility and escaping fixes. I documented those in:

