Deploying and Operating PHP Applications

A deployment process should be repeatable, observable, and reversible. Performance work should begin with measurement, not assumptions.

Atomic Release Layout

/var/www/customer-portal/
├── current -> releases/20260716-134500
├── releases/
│   ├── 20260715-101200/
│   └── 20260716-134500/
└── shared/
    ├── .env
    ├── storage/
    └── uploads/

Build a complete release, run checks, link shared writable data, then switch the current symlink. A rollback becomes another symlink change, provided the database remains compatible.

A Deployment Pipeline

  1. Install dependencies from the lock file.
  2. Run syntax checks, static analysis, and tests.
  3. Build front-end assets if applicable.
  4. Create the release directory and copy the build.
  5. Run backward-compatible database migrations.
  6. Warm caches and optimize autoloading.
  7. Switch traffic to the new release.
  8. Reload PHP-FPM and restart workers gracefully.
  9. Run health checks and verify logs and metrics.

Safe Database Migrations

For changes that cannot be instantaneous, use an expand-and-contract process:

  1. Add the new column or table without removing the old one.
  2. Deploy code that can work with both shapes.
  3. Backfill data in controlled batches.
  4. Switch reads and writes to the new shape.
  5. Remove the old structure in a later release.

PHP-FPM Capacity

Size worker pools from measured memory use and expected concurrency. Too few workers cause queueing; too many can exhaust memory and make the host unstable. Monitor active workers, idle workers, max-children hits, request duration, and upstream timeouts.

OPcache

Enable OPcache in production so PHP does not parse and compile source files on every request. In immutable release directories, validate timestamps conservatively or reset/reload OPcache during deployment.

A Performance Workflow

  1. Define the slow user action or endpoint.
  2. Measure total request time and break it into application, SQL, external API, and rendering time.
  3. Find the largest component.
  4. Change one thing.
  5. Measure again under realistic load.

Common High-Value Improvements

  • Add a missing database index discovered through EXPLAIN.
  • Remove N+1 queries.
  • Paginate large result sets.
  • Cache stable expensive results with clear invalidation.
  • Move email, exports, and API synchronization to background jobs.
  • Set connection and request timeouts.
  • Compress and cache static assets at the web server or CDN.
Health checks: A basic process check is not enough. Separate liveness from readiness, and verify critical dependencies without making the health endpoint itself expensive.