Move a PHP app from Apache to Nginx with PHP-FPM

Moving a PHP application from Apache to Nginx with PHP-FPM changes more than the process listening on port 80. Apache currently combines HTTP handling, URL rewriting, static delivery and PHP execution; the replacement splits those duties between Nginx and a FastCGI worker pool. A safe migration therefore treats request handling as a contract, not as a server preference. Learn more about Msi Afterburnerでフレームレートキャップを設定して消費電力を抑える方法と遅延への影響.

For Australian teams, the contract must survive both geography and usage. Sydney and Melbourne hosting regions can keep latency sensible, while customers using mobile services or NBN connections, including Fibre-to-the-Node, can expose the application to interruptions and timeouts. The application should also account for its audit trail and privacy controls under the Privacy Act 1988 and applicable state laws.

Audit Apache behaviour before changing servers

Start by exporting every virtual host, alias, directory index and .htaccess file. Record active Apache modules, rewrite rules, redirects, authentication requirements, MIME types, compression, cache headers, custom error pages and security rules. Shared Australian hosting based on cPanel often makes Apache rules part of the site contract, even when the application code never mentions them.

Turn those findings into a URL parity matrix: public path, method, expected status, headers, body and destination. Include uploads, webhooks, language routes, trailing slashes, encoded characters and query strings. Test the behaviour that clients actually consume rather than comparing only homepages.

Choose the target from workload and operating ownership, not from a desire to use Nginx everywhere. If the target is still undecided, the comparison at https://karlkatzke.com/cloud-vs-in-house-infrastructure helps separate application architecture from hosting ownership. Record expected concurrency, memory per worker, traffic peaks and acceptable latency before moving a socket.

Design the Nginx and PHP-FPM boundary

Nginx should terminate TLS, serve eligible static assets, route requests and enforce request-level limits. PHP-FPM should own PHP execution through a Unix socket or a protected TCP listener. A Unix socket avoids unnecessary network handling on one host; TCP becomes reasonable for separate application and worker tiers, provided authentication, encryption and network policy are explicit.

A generic front-controller configuration might begin like this, with paths adapted to the application:

server {
    root /srv/example/current/public;
    index index.php;

    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }

    location ~ \.php$ {
        try_files $uri =404;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_pass unix:/run/php/php8.3-fpm.sock;
    }
}

Give each application its own FPM pool and operating-system user. Set pm.max_children from measured memory per process rather than copying a common default. Define php_admin_value entries for upload limits, execution limits and error settings where needed, and expose pool status only through a protected route. If the web tier scales horizontally, use shared sessions or deliberate stickiness so users are not logged out during failover.

Translate rewrite and hosting rules

Nginx does not read .htaccess, so those rules must be translated into server or location configuration. Apache RewriteRule patterns, QSA, RewriteBase and internal redirects do not map one-for-one to Nginx rewrite and try_files. Preserve query strings, slash behaviour and redirect status codes, then test rules in order because a front controller can easily create a rewrite loop.

Audit directory-specific authorisation, mod_auth_basic, mod_security, MIME handling, compression and expiry headers separately. Conditional authorisation may require auth_request; server-side includes, WebDAV methods or Apache-only modules may need an application change or an upstream proxy. Raise client_max_body_size deliberately for uploads, and reproduce custom 404 and 50x handling instead of allowing infrastructure pages to leak through.

PHP settings also move. The pool's php.ini, .user.ini, environment variables, open_basedir, session path and working directory must match the old runtime. Confirm that release directories, writable logs, sessions, temporary uploads and the vendor tree have the correct ownership. Run scheduled jobs through PHP CLI with the same extensions and environment as the web process, and warm or reset OPcache deliberately during deployment.

Build a repeatable migration checklist

Use repeatable gates rather than relying on a final click-through test:

  • Export all hosts, aliases and .htaccess files.
  • Map each public route to its expected response.
  • Record PHP, Composer, database and system versions.
  • Reproduce TLS, DNS, firewall and mail settings.

After the foundation is staged, verify the behaviour that carries the most business risk:

  • Compare status codes, headers, redirects and response bodies.
  • Exercise login, checkout, uploads, webhooks and email flows.
  • Load-test bursts while watching memory, workers and queueing.
  • Verify cron timing across Australian Eastern Standard Time and daylight-saving changes.
  • Rehearse rollback and confirm application logs remain searchable.

Store each result with the commit, configuration revision and test data. A parity matrix should mark failures as release blockers, accepted differences or tracked follow-up work. This prevents a known Apache quirk from disappearing into deployment notes.

Test from Australian networks

Test from Australian conditions rather than only from the server console. Run synthetic probes through Sydney and Melbourne, then repeat over mobile and fixed broadband paths, including a lossy or interrupted connection. Confirm that browser retries, API clients and webhook senders receive predictable responses when latency rises or a worker is busy.

Watch Nginx status codes, upstream timing, FPM queue depth, worker saturation, CPU, memory, database latency and PHP error rate. Compare those signals before and after the change. Resource ceilings need measurement rather than folklore. The Afterburner frame rate cap guide illustrates the same discipline for a graphics workstation used in load generation: constrain one variable, then check power and latency instead of assuming a lower limit is always better.

Before cutover, verify backups, log shipping, uptime monitoring and certificate renewal paths. Define a rollback trigger using observed symptoms, such as sustained 502 responses, checkout failures or abnormal worker growth. A traffic-weighted canary is more informative than a single synthetic request.

Roll out with a reversible release plan

Lower the relevant DNS TTL in advance, then shift traffic gradually through a load balancer or origin target while Apache remains warm. Keep the old application release available until error rates, latency and key transactions stay within agreed limits. DNS caches in Australian networks can extend the transition, so rely on measured traffic rather than a calendar estimate.

Check compliance as part of release acceptance. The Australian Privacy Principles and Notifiable Data Breaches scheme apply to eligible organisations; health information may also engage Victorian or New South Wales privacy legislation. Ensure logs, debug output and support screenshots do not expose personal information, and rehearse incident escalation with the people who must make notifications.

After the switch, retain both stacks for an agreed observation window and compare application logs with Nginx and FPM logs. Schedule follow-up work for genuine improvements, but do not alter several layers during the canary, since that makes cause and effect ambiguous. Record the final configuration and recovery procedure in the runbook.

Create the URL parity matrix today, assign owners to every failed behaviour check, and schedule the first production canary for a low-traffic Australian business window. That gives the team a concrete migration path, observable success criteria and a safe route back to Apache if the evidence calls for it.

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.