Deploying Reliable PHP Applications With Docker Compose

Running a PHP application in production involves more than copying files to a web server. The operating system, PHP extensions, web server, database client, background workers, scheduled tasks, and environment variables all need to work together in a predictable way. Docker packages those dependencies into repeatable units, while Docker Compose provides a practical way to define how the services interact.

For a small business, internal tool, or client project, this approach can remove much of the uncertainty from deployment. A developer can test against the same PHP version and extensions used in production, while an administrator gains a clear description of the application stack. That consistency is especially useful when infrastructure is split between a local server, a cloud provider, and managed services.

Australian teams also need to account for practical operating conditions. A Melbourne office might use the NBN for development access, host production in an AWS Sydney region, and support staff working from Perth with different network latency. Clear container boundaries and sensible health checks help keep those arrangements manageable.

The method still requires sound operational habits. Containers do not replace backups, patching, access control, monitoring, or capacity planning. They provide a cleaner foundation for those tasks, allowing a PHP deployment to be treated as an observable system rather than a collection of manually configured machines.

Define The Application Runtime

Start by identifying what the application actually needs. Choose a supported PHP version, list required extensions, and decide whether the application uses Apache with mod_php or Nginx with PHP-FPM. A framework such as Laravel, Symfony, or a custom PHP codebase may also require Composer, queue workers, image processing libraries, or command-line utilities.

The Dockerfile should install only the packages needed at runtime. A multi-stage build can use a Composer image or a PHP build stage to assemble dependencies, then copy the finished vendor directory into a smaller production image. This keeps compilers and development tools out of the running container, reducing both image size and attack surface.

Pin important versions rather than relying on floating tags. php:8.3-fpm-bookworm communicates more than php:latest, and a lock file ensures that Composer dependencies do not unexpectedly change during deployment. Review PHP release support regularly so the image remains secure without introducing an untested upgrade during a busy Friday arvo.

Build A Useful Compose Definition

A Compose file should describe the services that make up the application: the PHP process, web server, database, cache, and perhaps a worker. Each service needs a clear responsibility. The web server can serve static assets and pass dynamic requests to PHP-FPM, while the PHP container handles application code and database connections.

Use named networks and service names instead of hard-coded IP addresses. The application can connect to a database at db:3306 and to Redis at cache:6379, regardless of which internal address Docker assigns. Volumes should be deliberate as well: database data needs persistence, while application containers should generally remain disposable.

Environment-specific values belong outside the image. Compose supports .env files and variable substitution, but secrets such as database passwords should be managed through a protected secret store or deployment system when possible. Never bake credentials into a Dockerfile or commit a production .env file to a public repository.

Separate Development And Production

A single Compose file often becomes unwieldy when it contains every local-development convenience and production requirement. Use a base definition for shared service relationships, then add an override or separate production file for bind mounts, debugging tools, resource limits, and external services.

Local development may mount source code from a laptop and expose Xdebug, whereas production should copy a tested application build into an immutable image. Developers can use Mailpit, a local database, and verbose error reporting; production should send mail through an approved provider and keep detailed errors out of HTTP responses.

That separation is valuable for Australian consulting and managed-service work, where a client may run development in Brisbane but host the live system in Sydney. It prevents a local shortcut from quietly becoming a production dependency and makes the release process easier to explain to another administrator.

Checks Worth Automating Before Release

  • Build the image from a clean checkout using the locked Composer dependencies.
  • Run unit, integration, and framework-specific tests inside the container.
  • Scan the image and PHP packages for known vulnerabilities.
  • Confirm database migrations are reviewed, reversible where practical, and backed up.
  • Verify that the application starts without relying on an interactive shell.

Handle Data, Migrations, And Storage

Containers should usually be treated as replaceable, but application data must have a durable home. A managed database service is often preferable for production because it provides backups, patching, replication, and operational tooling. If the database runs in Compose, place its data on a persistent volume and define a tested backup process outside the container lifecycle.

Database migrations need an explicit deployment step. Running them automatically every time a web container starts can create race conditions when multiple replicas launch together. A release job or one-off administrative command gives operators a visible point at which schema changes happen.

Uploaded files deserve the same attention. Local container storage disappears when a container is recreated, so user uploads should use object storage or a persistent shared filesystem. For a Sydney-hosted application serving customers across Australia, object storage can also simplify backup retention and delivery through a content delivery network.

Make Networking And Security Intentional

Only the reverse proxy or load balancer should normally be exposed to the public internet. Keep PHP-FPM, the database, and Redis on private Docker networks. Avoid publishing database ports to the host unless an administrative workflow genuinely requires it, and then restrict access through firewall rules or a private management network.

Run the application as a non-root user where possible. Set file permissions during the image build, make writable directories explicit, and use read-only filesystems or dropped Linux capabilities when the application supports them. Update base images and Composer dependencies through a regular maintenance process rather than waiting for a security incident.

TLS termination may happen in Traefik, Caddy, Nginx, a cloud load balancer, or a managed edge service. Ensure forwarded headers are configured correctly so PHP understands the original protocol and client address. This matters for secure cookies, redirects, audit logs, and rate limiting, particularly when traffic crosses a provider edge before reaching infrastructure in an AWS Sydney availability zone.

Add Health Checks And Operational Visibility

A container being “up” does not prove that the application is usable. A health check should test a lightweight endpoint or command that confirms the web process can respond. Deeper checks can verify database connectivity and cache availability, but they should be designed carefully so a temporary dependency issue does not cause an unnecessary restart loop.

Logs should go to standard output and standard error, allowing Docker or the hosting platform to collect them consistently. Include request identifiers, timestamps, response status, and useful application context, while excluding passwords, session tokens, and personal information. Metrics such as request duration, PHP-FPM queue depth, worker failures, disk usage, and database connections reveal problems before users report them.

Operational discipline benefits from real experience. Reading a sysadmin’s story is a useful reminder that deployments are connected to people, support processes, and accumulated infrastructure knowledge, not just configuration files.

Signals To Watch In Production

  • HTTP error rates, latency percentiles, and upstream timeout counts.
  • PHP-FPM saturation, worker restarts, and queue depth.
  • Database connection usage, slow queries, replication lag, and storage growth.
  • Queue backlog, failed jobs, scheduled task delays, and retry volume.
  • Host memory, CPU, filesystem space, and container restart frequency.

Plan Releases And Recovery

A release should produce a versioned image identified by a commit or build number. Deploy that exact image to staging, run smoke tests, and promote it to production without rebuilding. This makes rollback practical because the previous image remains a known artifact rather than an uncertain reconstruction.

Blue-green or rolling deployment strategies can reduce interruption, but they must account for database compatibility. A new application version should generally work with the existing schema before destructive changes are removed. Keep migrations backwards-compatible across the transition when multiple application versions may run simultaneously.

Backups need regular restoration tests. A successful backup job is only evidence that data was copied; it does not prove that the data can be recovered within the required time. Document who can restore it, where credentials are stored, and how the business will operate during recovery. Australian businesses should also consider retention, privacy obligations, and the location of replicated data.

Make The Deployment Repeatable

Docker and Compose work best when treated as part of a delivery system rather than as commands typed manually on a server. Store the Dockerfile, Compose definitions, deployment scripts, health checks, and operational notes in version control. A CI pipeline can build, test, scan, publish, and deploy the same artifact with an auditable trail.

For a modest application, this may be a straightforward virtual machine running Docker Compose behind a managed load balancer. Larger systems may move the same images to ECS, Kubernetes, or another container platform later. A clean service boundary and disciplined configuration make that transition less disruptive.

Document the routine tasks that matter during an incident: checking logs, restarting a worker, rolling back an image, restoring a database, and rotating a credential. Then put the process through a staging exercise before customers depend on it. Build the stack, test the failure paths, and deploy the PHP application with enough automation that the next release is calm, observable, and repeatable.

Experience

Information Technology Consulting

Independent Practice

Provides IT consulting services focused on infrastructure planning, cloud migration strategy, and systems architecture. Engagements draw on years of hands-on sysadmin and development experience across Linux, Windows, and hybrid environments.

K9 Search & Rescue Volunteer

Ongoing

Active participant in K9 Search & Rescue operations, combining technical logistics skills with field support for canine search teams.

Karl Katzke's Blog

October 2006 – May 2014

Published a long-running personal technology blog covering cloud vs. in-house infrastructure, F# and Mono on OSX, hardware vendor critiques, RAID card performance analysis, and sysadmin storytelling. Notable posts include "When Sysadmins Ruled the Earth" (May 15, 2014) and "Getting Started with F# and Mono on OSX" (December 22, 2012).

Credentials

A small badge icon with a shield shape in muted blue tones on a light background

Systems Administration

Deep experience with Linux (RHEL, SLES, CentOS), high-availability clusters, and STONITH configurations.

A small badge icon with a gear shape in muted blue tones on a light background

Cloud Infrastructure

Practical knowledge of AWS EC2, reserved instances, and cost analysis for cloud vs. on-premises deployments.

A small badge icon with a code symbol in muted blue tones on a light background

Development

Proficient in F#, PHP (Symfony), and cross-platform tooling including Mono and MonoDevelop on OSX.

Studies

F# & Functional Programming

Self-directed, 2012

Explored strongly typed functional programming with F# on OSX using the Mono runtime. Published a detailed getting-started guide covering toolchain setup and cross-platform game development research.

High-Availability & Cluster Management

Professional Development, 2009

Configured and documented crm_mon email alerting for STONITH events on SLES11-HAE clusters, integrating with Nagios monitoring for production environments.

Hardware & Storage Performance

Ongoing

Conducted hands-on benchmarking of SATA/SAS RAID controllers including HighPoint RocketRaid 2740 and LSI/SuperMicro AOC-USASLP2-H8iR, comparing against software RAID configurations.

Skills

A small icon representing a server with clean geometric lines in slate blue

Linux Administration

RHEL, SLES, CentOS — package management, kernel tuning, HA clustering, and monitoring integration.

A small icon representing a cloud shape with clean geometric lines in slate blue

Cloud Architecture

AWS EC2, reserved-instance planning, cost modeling, and hybrid infrastructure strategy.

A small icon representing code brackets with clean geometric lines in slate blue

F# & .NET/Mono

Functional programming on OSX, MonoDevelop toolchain, and cross-platform game-dev exploration.

A small icon representing a database cylinder with clean geometric lines in slate blue

PHP & Symfony

Web application development with the Symfony framework and the broader PHP ecosystem.

A small icon representing a storage drive with clean geometric lines in slate blue

Storage & RAID

SATA/SAS controller evaluation, md RAID configuration, and performance benchmarking.

A small icon representing a shield with clean geometric lines in slate blue

High Availability

Pacemaker, STONITH, crm_mon alerting, and Nagios integration for production cluster monitoring.