fix(deploy): make the prod compose profile boot out of the box#496
Conversation
Three defects prevented 'COMPOSE_PROFILES=prod docker compose up' from ever serving a page: - nginx forwards FastCGI to phpfpm:9000 but no service or alias with that name existed -> 502 for every PHP request. The app service now carries a phpfpm network alias. - the production image ships no .env, but bin/console and index.php boot Symfony Dotenv unconditionally -> the migration entrypoint crashed before PHP-FPM could start. The image now contains an empty .env; configuration comes from real environment variables. - compose interpolated APP_ENV/APP_DEBUG from the repository's Symfony .env (dev/1) into the 'prod' container, overriding the image's APP_ENV=prod. The two lines are gone (image defaults rule) and the variables the app actually needs (DATABASE_URL, APP_SECRET, LDAP_*, branding) are passed through explicitly, defaulting to the bundled db service. Verified: rebuilt the production image and booted the prod profile — /login returns 200 and /status/check responds; before the fix the same sequence produced 502 and '[entrypoint] ERROR: database not reachable'. Signed-off-by: Sebastian Mendel <info@sebastianmendel.de>
There was a problem hiding this comment.
Code Review
This pull request configures the production Docker image to ship with an empty .env file and updates compose.yml to pass through all necessary runtime configuration environment variables. It also adds a phpfpm network alias to the app service, simplifying the deployment guide. The review feedback correctly points out that the AUTO_MIGRATE environment variable was omitted from the compose.yml environment list, which prevents users from opting out of automatic database migrations.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
There was a problem hiding this comment.
Pull request overview
This PR fixes production deployment defaults so COMPOSE_PROFILES=prod docker compose up -d serves the Symfony app correctly without requiring extra overrides, aligning runtime configuration with image-baked defaults and Compose wiring.
Changes:
- Add a
phpfpmnetwork alias to theappservice to match nginx’sfastcgi_pass phpfpm:9000. - Ensure the production image contains an empty
.envso Symfony Dotenv bootstrapping doesn’t crash when the file is absent. - Adjust prod-profile Compose env handling to avoid unintended
APP_ENV/APP_DEBUGoverrides and document the updated behavior.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.
| File | Description |
|---|---|
| docs/DEPLOYMENT_GUIDE.md | Updates deployment guidance to reflect prod profile working without nginx alias overrides and with env-vars-driven config. |
| Dockerfile | Ships an empty .env in the production image to prevent Dotenv startup failures. |
| compose.yml | Aligns prod service wiring (env vars + network alias) with nginx and image defaults. |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #496 +/- ##
=========================================
Coverage 84.15% 84.15%
Complexity 2814 2814
=========================================
Files 187 187
Lines 7588 7588
=========================================
Hits 6386 6386
Misses 1202 1202
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
…_URL default, required APP_SECRET - pass AUTO_MIGRATE through so the documented opt-out actually reaches the container (Gemini) - flatten the DATABASE_URL default; nested interpolation is not reliably portable across compose implementations (Copilot) - APP_SECRET now fails fast via :? instead of defaulting to an empty string, which Symfony cannot boot with (Copilot) - reword the guide's env-source paragraph: Compose reads the project directory's .env (or --env-file), shell takes precedence (Copilot) Re-verified: prod profile still boots — /login 200. Signed-off-by: Sebastian Mendel <info@sebastianmendel.de>
…credentials SonarCloud flags the password literal in the flattened default (S6437). DATABASE_URL now fails fast via :? like APP_SECRET; the repository .env supplies a matching value for local runs, real deployments must set it. Re-verified: prod profile still boots — /login 200. Signed-off-by: Sebastian Mendel <info@sebastianmendel.de>
|



Summary
COMPOSE_PROFILES=prod docker compose up -dnever served a page. Three stacked defects, found while verifying the deployment guide in #494:docker/nginx/default.confforwards FastCGI tophpfpm:9000, but no service or network alias with that name existed → 502 for every PHP request. Theappservice now carries aphpfpmnetwork alias..envin the production image —bin/console/public/index.phpboot Symfony Dotenv unconditionally and it throws when the file is absent → the auto-migration entrypoint died before PHP-FPM ever started ([entrypoint] ERROR: database not reachable after 60s). The image now ships an empty.env; all runtime configuration comes from real environment variables.APP_ENV=${APP_ENV:-prod}picked updevfrom the repository's committed Symfony.env, overriding the image'sENV APP_ENV=prod. Those lines are removed (image defaults rule) and the variables the app actually needs (DATABASE_URL,APP_SECRET,LDAP_*, branding,SENTRY_DSN) are passed through explicitly, with defaults matching the bundleddbservice.APP_ENCRYPTION_KEYis a bare passthrough because an empty string would defeat itsenv(default:secret:…)fallback.The deployment guide's workaround note is replaced by the actual behavior.
Verification
Rebuilt the production image (
docker buildx bake app) and booted the prod profile without the dev override:502on /login, entrypoint loopdatabase not reachable after 60s/login→ 200,/status/check→{"loginStatus":false}, FPM up, auto-migration completed