Skip to main content

Production stack

The production stack is docker-compose.prod.yml — a single-server deploy with dedicated containers for each concern:

ServicePortNotes
backend—php-fpm, production image
backend-nginx8080Serves the API
migrate—One-shot php artisan migrate --force; fpm/queue/scheduler wait for it
queue—php artisan queue:work
scheduler—php artisan schedule:work
reverb—Laravel Reverb websocket server; backend-nginx proxies /app/ to it
admin8081Built admin SPA served as static files
storefront8082Next.js standalone server
mysql—MySQL 8 with healthcheck; no published port by default
redis—Redis 7 with AOF persistence

Running it​

docker compose --env-file .env.production -f docker-compose.prod.yml up -d --build
warning

A bare docker compose up -d (without -f) starts the development stack — always pass --env-file and -f in production.

Notes​

  • Migrations are one-shot. The migrate service runs to completion first; backend, queue, and scheduler wait for it, so they never race migrations against each other.
  • Images are self-contained. Build contexts are the repo root, so both images are reusable as-is in Kubernetes later.
  • Frontend env vars are bake-time. NEXT_PUBLIC_API_BASE_URL and the VITE_* variables are build arguments; SERVER_API_BASE_URL for the storefront is provided at runtime. Realtime-notification client config (REVERB_APP_KEY/HOST/PORT/SCHEME) is baked into both frontends the same way.
  • Websockets ride the API host. backend-nginx proxies the Reverb websocket endpoint (/app/) under the backend's TLS, so clients need no extra port or domain.
  • Database access. Reach MySQL via the compose network, or publish a port explicitly if you need host access.
  • Build assets (Dockerfiles, nginx configs, php.ini) live in infrastructure/docker/production/ in the monorepo.