Console Login

Scaling PHP in 2012: Migrating from Apache mod_php to Nginx & PHP-FPM

Scaling PHP in 2012: Migrating from Apache mod_php to Nginx & PHP-FPM

If you are still running a high-traffic site on a default LAMP stack (Linux, Apache, MySQL, PHP) with mod_php in mid-2012, you are likely burning money. I’ve seen it happen time and time again: a marketing campaign goes live, traffic spikes, and the server starts swapping because Apache is spawning hundreds of heavy child processes, each carrying a full PHP interpreter.

The solution isn't just "buy more RAM." The solution is architectural. It is time to decouple your web server from your PHP processing.

The Problem with Apache and mod_php

The traditional Apache prefork MPM (Multi-Processing Module) with mod_php is stable, but it is architecturally inefficient for high concurrency. Every time Apache serves a static file (like a CSS file or a JPEG), it still spins up a process that contains the overhead of the PHP engine. This is wasteful.

In a recent migration for a media client in Oslo, we saw their 4GB RAM VPS choking on just 200 concurrent users. The httpd processes were consuming 40MB each. 200 * 40MB = 8GB. The math doesn't work. The server hit swap, I/O went through the roof, and latency to users in Trondheim spiked to over 2 seconds.

Enter Nginx and PHP-FPM

PHP-FPM (FastCGI Process Manager) allows you to run PHP as a standalone service, independent of the web server. Nginx acts as a lightweight reverse proxy, handling static files with negligible memory footprint and passing only the dynamic .php requests to the FPM socket.

Step 1: Installing the Stack (CentOS 6)

Since the default CentOS repositories are often outdated, we recommend using the REMI or EPEL repositories to get PHP 5.3.13 or the new PHP 5.4.3.

# Install Nginx and PHP-FPM
yum install nginx php-fpm php-common php-pecl-apc

# ensure they start on boot
chkconfig nginx on
chkconfig php-fpm on

Step 2: Configuring PHP-FPM Pools

The default configuration in /etc/php-fpm.d/www.conf is rarely optimized for production. The most critical directive is the process manager (pm). For a stable production environment with predictable memory usage, I often prefer static over dynamic to prevent the overhead of forking processes under load.

Here is a robust configuration for a server with 2GB of RAM dedicated to web serving:

; /etc/php-fpm.d/www.conf

[www]
user = nginx
group = nginx
listen = 127.0.0.1:9000

; Use static if you have plenty of RAM and want zero ramp-up time
pm = dynamic
pm.max_children = 50
pm.start_servers = 5
pm.min_spare_servers = 5
pm.max_spare_servers = 35

; Prevent memory leaks by recycling processes
pm.max_requests = 500

; Slow log is essential for debugging bottlenecks
request_slowlog_timeout = 5s
slowlog = /var/log/php-fpm/www-slow.log
Pro Tip: Never expose your PHP-FPM listening port to the public internet. If you are splitting your web server and PHP application server across different nodes (a common setup on CoolVDS private networks), bind to a private IP and use iptables to restrict access strictly to the web server's IP.

Step 3: Nginx Vhost Configuration

Nginx needs to know how to pass the PHP requests. This configuration handles static files directly and passes PHP to the backend.

server {
    listen       80;
    server_name  example.no;
    root         /var/www/html;
    index        index.php index.html;

    # Serve static assets immediately
    location ~* \.(jpg|jpeg|gif|png|css|js|ico|xml)$ {
        expires           30d;
        access_log        off;
    }

    # Pass PHP scripts to PHP-FPM
    location ~ \.php$ {
        try_files $uri =404;
        fastcgi_pass 127.0.0.1:9000;
        fastcgi_index index.php;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        include fastcgi_params;
    }
}

The Importance of Opcode Caching (APC)

In 2012, running PHP without an opcode cache is professional negligence. PHP is an interpreted language; without a cache, it compiles your code on every single request. APC (Alternative PHP Cache) stores the compiled bytecode in shared memory.

Add this to your php.ini or /etc/php.d/apc.ini:

extension=apc.so
apc.enabled=1
apc.shm_segments=1
apc.shm_size=64M
apc.ttl=7200
apc.user_ttl=7200
apc.stat=1

With APC enabled, we typically see execution times drop by 300% and CPU load decrease significantly.

Infrastructure Matters: The CoolVDS Advantage

Software optimization can only go so far. If your underlying virtualization platform has "noisy neighbors" stealing your I/O cycles, your database queries will hang regardless of your PHP config.

This is why serious system administrators in Norway prefer KVM-based virtualization over container-based solutions like OpenVZ for high-load projects. KVM (Kernel-based Virtual Machine) provides true hardware isolation. At CoolVDS, our instances rely on this strict isolation coupled with high-performance storage arrays. When you configure innodb_buffer_pool_size on a CoolVDS instance, you know that RAM is guaranteed, not oversold.

Performance Comparison

Metric Apache (mod_php) Nginx + PHP-FPM + APC
Memory per Process ~35-50 MB ~15-25 MB
Concurrency Limit (2GB RAM) ~150 req/sec ~450+ req/sec
Static File Delivery Blocking Non-blocking (Async)

Local Compliance and Reliability

For Norwegian businesses, data sovereignty is becoming a hotter topic. While the Cloud is global, the Personopplysningsloven (Personal Data Act) requires strict control over customer data. Hosting on servers physically located in Norway or the EEA ensures you are compliant with the Data Protection Directive. Furthermore, low latency to the NIX (Norwegian Internet Exchange) ensures your local users get snappy response times.

Don't let legacy configurations slow you down. By switching to Nginx and PHP-FPM, you prepare your infrastructure for the traffic of tomorrow.

Ready to test your new stack? Deploy a developer-friendly KVM instance on CoolVDS today and experience the stability of true resource isolation.