php runtime and server environment

FastCGI Sockets

When Nginx, Caddy, Apache with proxy FastCGI, or another web server needs PHP-FPM to execute a PHP script, it connects to a PHP-FPM listener. That listener is usually either a Unix socket file or a TCP address.

This is a small configuration detail, but it causes many real deployment failures. If the web server points to one listener and PHP-FPM is listening somewhere else, users see a gateway error before PHP application code runs.

Unix socket listener

A Unix socket is a file-like endpoint on the same machine:

; PHP-FPM pool example
listen = /run/php/php8.3-fpm.sock
listen.owner = www-data
listen.group = www-data
listen.mode = 0660

Nginx might point to it like this:

fastcgi_pass unix:/run/php/php8.3-fpm.sock;

Unix sockets are common when the web server and PHP-FPM run on the same host or same container filesystem. They avoid TCP networking overhead and can be protected with filesystem permissions.

The common failure is permissions. The web server user must be allowed to open the socket. If PHP-FPM creates the socket as one user/group and the web server runs as another, the path can exist but still be unusable.

TCP listener

A TCP listener uses an IP address and port:

; PHP-FPM pool example
listen = 127.0.0.1:9000

Nginx might point to it like this:

fastcgi_pass 127.0.0.1:9000;

TCP listeners are common when the web server and PHP-FPM are in separate containers, separate hosts, or a networked deployment. In Docker Compose, the web container may connect to the PHP container by service name:

fastcgi_pass php:9000;

The common failure is binding to the wrong interface. 127.0.0.1:9000 means "inside this same network namespace". In containers, that may point back to the Nginx container, not the PHP container.

Choosing between them

Use a Unix socket when:

  • the web server and PHP-FPM are on the same host
  • filesystem permissions are easy to manage
  • the deployment does not need network routing between services

Use TCP when:

  • the web server and PHP-FPM run in separate containers
  • the web server and PHP-FPM run on different hosts
  • the platform expects network service discovery

Both options are normal. The important thing is that the web server configuration and PHP-FPM pool configuration match.

Diagnosing mismatch errors

Common symptoms include:

  • 502 Bad Gateway
  • connect() to unix:/run/php/php8.3-fpm.sock failed
  • connect() failed (111: Connection refused)
  • No such file or directory for a socket path
  • Permission denied for a socket path
  • requests hang until timeout because the listener is unreachable

The review path is straightforward:

  1. Find the PHP-FPM pool listen value.
  2. Find the web server fastcgi_pass or equivalent value.
  3. Confirm both values describe the same endpoint.
  4. For Unix sockets, check socket ownership and mode.
  5. For TCP, check host, port, container network, firewall, and bind address.
  6. Reload the services after configuration changes.

Safe diagnostics

From PHP, you can inspect which SAPI handled the request, but PHP cannot prove the web server's fastcgi_pass value after the request has already succeeded.

PHP example
<?php

declare(strict_types=1);

echo 'SAPI: ' . PHP_SAPI . PHP_EOL;
echo 'Server software: ' . ($_SERVER['SERVER_SOFTWARE'] ?? 'CLI or unknown') . PHP_EOL;

// Example output from CLI:
// SAPI: cli
// Server software: CLI or unknown

Use server logs for listener errors. Nginx error logs, PHP-FPM logs, and container logs usually show the exact socket path or TCP endpoint that failed.

What you should be able to do

After this lesson, you should be able to explain the difference between a Unix socket and a TCP listener, match fastcgi_pass to the PHP-FPM listen value, and diagnose common gateway errors caused by listener mismatches or permissions.

Practice

Task: Match The FastCGI Listener

Review a web server and PHP-FPM configuration pair and decide whether they match.

Requirements

  • Write one matching Unix socket example.
  • Write one matching TCP example.
  • Write one broken example and explain the likely symptom.
  • Include checks for socket permissions or TCP bind address.
  • Add a short note explaining why this problem appears as a web server error before PHP application code runs.

Check your work

The answer should help another developer diagnose a 502 Bad Gateway or "Primary script unknown" style deployment issue.

Show solution

A good review compares the endpoint PHP-FPM creates with the endpoint the web server tries to use.

Matching Unix socket

PHP-FPM pool:
listen = /run/php/php8.3-fpm.sock
listen.owner = www-data
listen.group = www-data
listen.mode = 0660

Nginx:
fastcgi_pass unix:/run/php/php8.3-fpm.sock;

Review:
The paths match. The web server user must be www-data or in the www-data group.
Matching TCP listener

PHP-FPM pool:
listen = 0.0.0.0:9000

Nginx in Docker Compose:
fastcgi_pass php:9000;

Review:
This is plausible when the PHP container is named php and both services share the same Docker network.
Broken example

PHP-FPM pool:
listen = /run/php/php8.3-fpm.sock

Nginx:
fastcgi_pass 127.0.0.1:9000;

Likely symptom:
The web server returns 502 because it is trying to connect to a TCP listener that PHP-FPM is not using.

This problem appears as a web server error because the request fails during the handoff from the web server to PHP-FPM. The PHP application has not started yet, so changing controller or framework code will not fix the listener mismatch.