CresignSys Learn — Lesson 060

Written by

in

PHP-FPM Deep Dive — How Nginx Runs WordPress PHP

We now move from Nginx to the PHP execution layer.

The complete flow is:

Browser
   ↓
DNS
   ↓
IP
   ↓
TCP 443
   ↓
Nginx
   ↓
FastCGI
   ↓
PHP-FPM
   ↓
WordPress
   ↓
MySQL

The key concept:

Nginx does not execute PHP. PHP-FPM executes PHP for Nginx.


1. What Is PHP?

PHP is a server-side programming language.

WordPress is primarily written in PHP.

For example:

index.php
wp-load.php
wp-settings.php

are PHP files.

The browser does not normally receive the PHP source code.

Instead:

PHP source
   ↓
PHP execution
   ↓
HTML
   ↓
Browser

2. Why PHP-FPM Exists

Nginx is excellent at:

HTTP
HTTPS
static files
connections
proxying

But it doesn’t execute PHP.

Therefore:

Nginx
   ↓
FastCGI
   ↓
PHP-FPM
   ↓
PHP

3. PHP-FPM

PHP-FPM means:

PHP FastCGI Process Manager

It manages PHP worker processes.

Conceptually:

PHP-FPM
│
├── Worker 1
├── Worker 2
├── Worker 3
└── Worker 4

Each worker can execute PHP requests.


4. Check PHP-FPM

On Ubuntu, first check which PHP version is installed:

php -v

Then:

systemctl list-units --type=service | grep php

You may see something similar to:

php8.3-fpm.service

The exact version on your server may be different.


5. Check the Service

For example:

sudo systemctl status php8.3-fpm

If your installed version differs, substitute it.

You want:

Active: active (running)

6. PHP CLI vs PHP-FPM

These are different.

PHP CLI

php

runs PHP from the command line.

PHP-FPM

php-fpm

runs PHP workers that applications such as Nginx can communicate with.

So:

CLI
=
command-line PHP

while:

FPM
=
web-request PHP execution

7. PHP-FPM Master Process

PHP-FPM generally has a master process.

Conceptually:

PHP-FPM
   │
   └── Master
         │
         ├── Worker
         ├── Worker
         ├── Worker
         └── Worker

The master manages the worker pool.


8. Worker Processes

When PHP requests arrive:

Nginx
 ↓
PHP-FPM
 ↓
available worker
 ↓
execute PHP

The worker processes the PHP request.


9. Why Multiple Workers?

Suppose:

User A → WordPress
User B → WordPress
User C → WordPress
User D → WordPress

You don’t want one PHP process to handle everything serially.

Multiple workers allow concurrent processing.

Conceptually:

Request A → Worker 1
Request B → Worker 2
Request C → Worker 3
Request D → Worker 4

10. PHP-FPM Pool

A group of PHP workers is called a:

Pool

A PHP-FPM installation can have multiple pools.

For example:

PHP-FPM
│
├── www pool
├── site1 pool
├── site2 pool
└── site3 pool

11. Why Pools Matter for Hosting

If you have:

site1.com
site2.com
site3.com

you could use one shared pool:

All websites
      ↓
www pool

or separate pools:

site1 → site1 pool
site2 → site2 pool
site3 → site3 pool

For a hosting platform, separate pools can provide stronger isolation and more controllable resource limits.


12. Shared Pool

Simple architecture:

Nginx
   │
   ▼
PHP-FPM
   │
   ▼
www pool
   │
   ├── site1
   ├── site2
   └── site3

Advantages:

simple
fewer processes
easy management

Disadvantages:

weaker isolation
one busy site can consume shared PHP capacity

13. Separate Pools

More isolated:

Nginx
│
├── site1 → PHP pool 1
├── site2 → PHP pool 2
└── site3 → PHP pool 3

Advantages:

better isolation
different users
different limits
different PHP settings

Disadvantages:

more configuration
more process-management complexity
more memory overhead

14. Hosting Architecture

For your CresignSys hosting platform, the long-term architecture can be:

site1
 ├── Linux user
 ├── files
 ├── Nginx config
 ├── PHP-FPM pool
 ├── PHP socket
 └── database

site2
 ├── Linux user
 ├── files
 ├── Nginx config
 ├── PHP-FPM pool
 ├── PHP socket
 └── database

15. Unix Socket

Nginx and PHP-FPM can communicate using a Unix socket.

Example:

/run/php/site1.sock

Flow:

Nginx
 ↓
Unix socket
 ↓
PHP-FPM

16. Why Unix Socket?

When both services are on the same server, a Unix socket is often a simple and efficient local communication mechanism.

You don’t need a network IP/port between Nginx and PHP-FPM.


17. TCP Socket

PHP-FPM can also listen on TCP.

For example:

127.0.0.1:9000

Then:

Nginx
 ↓
127.0.0.1:9000
 ↓
PHP-FPM

18. Unix vs TCP

For your single-server hosting setup:

Unix socket

is often convenient.

For distributed architectures:

TCP

can be more appropriate.

For example:

Nginx Server
     ↓
network
     ↓
PHP Application Server

requires network communication.


19. PHP-FPM Configuration

Configuration locations vary by PHP version.

A common structure is:

/etc/php/<version>/fpm/

with:

php-fpm.conf
pool.d/

Inside:

pool.d/

you may find:

www.conf

20. Default Pool

A common default pool is:

www

with configuration such as:

/etc/php/8.x/fpm/pool.d/www.conf

The exact path depends on your installed PHP version.


21. Pool Configuration

A simplified pool configuration might look like:

[site1]

user = site1
group = site1

listen = /run/php/site1.sock

Then process-management settings can be added.


22. User and Group

This is extremely important for hosting.

Suppose:

site1

has its own Linux user.

PHP-FPM workers for that pool can run as:

site1

instead of:

www-data

This improves isolation between websites.


23. Why User Isolation Matters

Suppose:

site1
site2

are owned by different customers.

If both PHP applications run as:

www-data

then filesystem separation can become more difficult.

With:

site1 → user1
site2 → user2

you can enforce stronger boundaries.


24. Example

/storage/websites/
│
├── site1.com/
│   └── public/
│
└── site2.com/
    └── public/

Ownership:

site1.com → site1
site2.com → site2

PHP:

site1 pool → site1
site2 pool → site2

This creates a consistent security model.


25. Nginx Worker User

Nginx may still run workers as:

www-data

while PHP runs as:

site1

This is possible if the relevant filesystem and socket permissions are configured correctly.


26. Socket Permission Problem

Suppose PHP-FPM creates:

/run/php/site1.sock

owned by:

site1:site1

If Nginx cannot access it:

Nginx
 ↓
socket permission denied
 ↓
502 Bad Gateway

This is one of the most important causes of PHP-related 502 errors.


27. Socket Ownership

Pool configuration can specify socket ownership and permissions.

Conceptually:

listen.owner = www-data
listen.group = www-data
listen.mode = 0660

This is only an example; the correct ownership model depends on how you isolate Nginx and PHP-FPM.


28. Process Manager

PHP-FPM has process management settings.

The most important modes are:

static
dynamic
ondemand

29. static

With:

pm = static

PHP-FPM maintains a fixed number of worker processes.

For example:

pm.max_children = 5

means approximately five worker processes are maintained.


30. dynamic

With:

pm = dynamic

PHP-FPM adjusts the number of workers within configured limits.

Important settings include:

pm.max_children
pm.start_servers
pm.min_spare_servers
pm.max_spare_servers

31. ondemand

With:

pm = ondemand

workers are created when requests arrive and can be terminated after being idle.

This can be useful for sites with relatively low or irregular traffic.


32. pm.max_children

This is one of the most important settings.

Example:

pm.max_children = 10

It limits the maximum number of simultaneous PHP worker processes in that pool.


33. Why This Matters

Suppose one PHP request consumes:

100 MB RAM

and you allow:

10 workers

Very roughly:

10 × 100 MB
=
1000 MB

plus:

Nginx
MySQL
OS
cache
other processes

So PHP worker limits must be based on actual memory usage, not arbitrary large numbers.


34. Too Few Workers

Suppose:

pm.max_children = 2

but:

20 requests

arrive simultaneously.

Only two PHP requests can execute at once.

The others wait.

This can increase response time.


35. Too Many Workers

Suppose:

pm.max_children = 100

but your VPS has limited RAM.

If PHP workers consume significant memory:

100 workers
 ↓
RAM exhaustion
 ↓
swap/OOM
 ↓
slow server
 ↓
possible crashes

Therefore:

More PHP workers does not automatically mean more performance.


36. CPU Also Matters

PHP workers consume:

RAM
CPU

Some requests are CPU-intensive.

For example:

large WordPress plugin
image processing
complex database operations

can consume significant resources.


37. Worker Concurrency

Think:

pm.max_children
=
maximum PHP concurrency for that pool

It is not simply:

number of visitors

One visitor can generate multiple requests.

And not every request requires PHP.


38. Static Files Don’t Need PHP

For:

logo.png
style.css
script.js

Nginx can often serve them directly.

Therefore:

100 static requests

do not necessarily mean:

100 PHP workers

39. WordPress Dynamic Requests

Requests such as:

/wp-admin/
login
uncached pages
POST requests
AJAX/API operations

may require PHP.

The exact behavior depends on the application and caching configuration.


40. PHP-FPM Queue

If all workers are busy:

Request
 ↓
PHP-FPM
 ↓
no free worker
 ↓
wait

Too much waiting can produce slow responses and eventually upstream timeouts.


41. pm.max_requests

Another useful setting:

pm.max_requests = 500

This tells a worker to process a limited number of requests before being recycled.

Why?

Long-running PHP processes can sometimes accumulate memory or other state.

Recycling workers can help mitigate certain forms of gradual memory growth.


42. pm.start_servers

For dynamic mode:

pm.start_servers = 3

controls how many workers are started initially.


43. pm.min_spare_servers

Example:

pm.min_spare_servers = 2

controls the minimum number of idle workers maintained in dynamic mode.


44. pm.max_spare_servers

Example:

pm.max_spare_servers = 5

controls the maximum number of idle workers maintained.


45. Example Pool

A simplified educational example:

[site1]

user = site1
group = site1

listen = /run/php/site1.sock

pm = dynamic
pm.max_children = 10
pm.start_servers = 2
pm.min_spare_servers = 2
pm.max_spare_servers = 5
pm.max_requests = 500

These numbers are examples, not recommended defaults for your VPS.


46. Resource Calculation

Before choosing:

pm.max_children

measure actual PHP worker memory usage.

For example:

ps --no-headers -o rss,cmd -C php-fpm8.3

The exact process name depends on your PHP version.


47. RSS

RSS means:

Resident Set Size

It provides an approximation of how much physical memory a process currently occupies.

For PHP-FPM tuning, this is useful.


48. Better Principle

Don’t say:

My VPS has 8 GB RAM, so I’ll set 50 PHP workers.

Instead:

Available RAM
 ↓
reserve RAM for OS
 ↓
reserve RAM for MySQL
 ↓
reserve RAM for Nginx
 ↓
reserve RAM for other services
 ↓
remaining RAM
 ↓
measure PHP worker size
 ↓
calculate reasonable concurrency

49. Example Calculation

Suppose:

VPS RAM = 8 GB

Reserve approximately:

OS + services = 2 GB
MySQL = 2 GB

Remaining:

4 GB

If average PHP worker usage is:

100 MB

then a theoretical upper bound is roughly:

4000 / 100
=
40 workers

But you should not automatically configure 40.

You need safety margin and real workload measurements.


50. WordPress Can Vary Greatly

One PHP request might use:

50 MB

while another might use:

250 MB

depending on:

plugins
theme
queries
image processing
API calls
application state

Therefore average and peak behavior matter.


51. PHP-FPM Slow Requests

PHP-FPM can be configured with a:

Slowlog

This helps identify requests that take too long.

A slowlog can help you discover:

slow plugin
slow WordPress operation
slow PHP script
database-related delay

52. Request Timeout

Nginx also has upstream timeout settings.

Conceptually:

Nginx
 ↓
waiting for PHP-FPM
 ↓
too long
 ↓
timeout

This can produce:

504 Gateway Timeout

53. 502 vs 504

Remember:

502

Often:

Nginx
 ↓
can't properly communicate with upstream

504

Often:

Nginx
 ↓
upstream didn't respond in time

These are clues, not absolute diagnoses.


54. Check PHP-FPM Logs

Depending on your installation:

sudo journalctl -u php8.3-fpm

or:

sudo journalctl -u php8.3-fpm --since "30 minutes ago"

Replace the version with your installed PHP-FPM service.


55. Check Nginx Errors

sudo tail -f /var/log/nginx/error.log

Then load the website.

Watch what appears.

This is an excellent troubleshooting technique.


56. Real-Time Debugging

Open terminal 1:

sudo tail -f /var/log/nginx/error.log

Open terminal 2:

curl -I https://learn.cresignsys.com

Now observe whether Nginx reports an error.


57. PHP-FPM Status

You can also inspect:

systemctl status php8.3-fpm

Then:

ps aux | grep php-fpm

You may see:

master process
pool site1
pool site2

58. One Pool Per Website

Your future CresignSys architecture could look like:

PHP-FPM
│
├── site1.com
│    ├── user = site1
│    └── socket = site1.sock
│
├── site2.com
│    ├── user = site2
│    └── socket = site2.sock
│
└── site3.com
     ├── user = site3
     └── socket = site3.sock

59. Nginx Mapping

Then:

site1.com
 ↓
Nginx server block
 ↓
site1.sock
 ↓
site1 PHP-FPM pool

and:

site2.com
 ↓
Nginx server block
 ↓
site2.sock
 ↓
site2 PHP-FPM pool

60. Stronger Isolation

Now imagine:

site1

is compromised through a vulnerable plugin.

If its PHP processes run as:

site1

rather than a shared hosting user, access to other sites can be more strongly restricted by filesystem permissions.

This is one reason shared-hosting systems isolate accounts.


61. Important Security Rule

Do not assume:

different directories
=
security isolation

If all applications run under the same powerful user:

www-data

one compromised application may potentially access other files that user can read.

User/process isolation is therefore important in multi-tenant hosting.


62. Database Isolation Too

The same principle applies to MySQL.

Instead of:

all websites
 ↓
one database
 ↓
one powerful database user

prefer:

site1
 ↓
database1
 ↓
dbuser1

site2
 ↓
database2
 ↓
dbuser2

with only the required privileges.


63. Complete Per-Site Isolation Model

A strong hosting model looks like:

SITE 1
│
├── Linux user
├── filesystem
├── Nginx server block
├── PHP-FPM pool
├── PHP socket
├── database
└── database user


SITE 2
│
├── Linux user
├── filesystem
├── Nginx server block
├── PHP-FPM pool
├── PHP socket
├── database
└── database user

64. Your Hosting Automation

When you create a new domain:

create-site example.com

your automation can eventually perform:

1. Create Linux user
2. Create website directories
3. Set ownership
4. Create PHP-FPM pool
5. Create PHP socket
6. Create Nginx configuration
7. Validate Nginx
8. Reload Nginx
9. Create MySQL database
10. Create database user
11. Install WordPress
12. Configure SSL

65. The Most Important PHP-FPM Settings

At your current level, memorize:

user
group
listen
pm
pm.max_children
pm.start_servers
pm.min_spare_servers
pm.max_spare_servers
pm.max_requests

66. Their Meaning

user
→ Which Linux user executes PHP?

group
→ Which Linux group?

listen
→ Where does Nginx connect?

pm
→ How are PHP workers managed?

pm.max_children
→ Maximum simultaneous PHP workers

pm.start_servers
→ Initial workers

pm.min_spare_servers
→ Minimum idle workers

pm.max_spare_servers
→ Maximum idle workers

pm.max_requests
→ Requests before recycling a worker

67. The Complete PHP Request

Now combine everything:

Browser
   ↓
HTTPS
   ↓
Nginx
   ↓
location /
   ↓
try_files
   ↓
index.php
   ↓
FastCGI
   ↓
PHP-FPM socket
   ↓
PHP-FPM pool
   ↓
PHP worker
   ↓
WordPress
   ↓
MySQL

68. Where 502 Happens

Nginx
   ↓
PHP-FPM

If this communication fails:

502 Bad Gateway

Investigate:

PHP-FPM running?
 ↓
socket exists?
 ↓
socket permissions?
 ↓
correct socket path?
 ↓
correct PHP-FPM pool?

69. Where 504 Happens

Usually:

Nginx
   ↓
PHP-FPM
   ↓
long-running request

If the upstream takes too long:

504 Gateway Timeout

Investigate:

slow PHP
slow WordPress
slow plugin
slow MySQL
external API
resource exhaustion

70. Lesson 060 — Core Principle

Remember this:

Nginx receives the web request; PHP-FPM provides the PHP execution environment.

The architecture is:

                  INTERNET
                     │
                     ▼
                   NGINX
                     │
               FastCGI │
                     ▼
                 PHP-FPM
                     │
              ┌──────┴──────┐
              ▼             ▼
           Site 1        Site 2
           Pool 1        Pool 2
              │             │
              ▼             ▼
          WordPress      WordPress
              │             │
              ▼             ▼
           MySQL 1        MySQL 2

This is the foundation for turning your Ubuntu VPS into a proper multi-website hosting server.


Next Lesson — 061

MySQL for Hosting — Databases, Users, Privileges & WordPress

We will next learn:

MySQL
 ↓
Database
 ↓
Table
 ↓
Row
 ↓
Column
 ↓
Database user
 ↓
Privileges
 ↓
WordPress wp-config.php
 ↓
PHP → MySQL

Then we will design the correct one-database + one-database-user-per-website model for your CresignSys hosting platform and learn how to create it safely from the command line.

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *