Troubleshooting Nginx 502 Bad Gateway with PHP-FPM Unix Socket on Ubuntu 22.04 LTS

Resolve Nginx 502 Bad Gateway errors when using PHP-FPM via a Unix socket on Ubuntu 22.04 LTS. A definitive guide for common misconfigurations and resource issues.


Resolve Nginx 502 Bad Gateway errors when using PHP-FPM via a Unix socket on Ubuntu 22.04 LTS. A definitive guide for common misconfigurations and resource issues.

A "502 Bad Gateway" error is a common and often frustrating issue encountered when Nginx acts as a reverse proxy for a backend application server like PHP-FPM. Specifically, when Nginx is configured to communicate with PHP-FPM using a Unix socket on Ubuntu 22.04 LTS, this error indicates that Nginx was able to connect to PHP-FPM but received an invalid response, no response at all, or the connection was prematurely closed. This guide provides a highly technical, step-by-step approach to diagnosing and resolving this issue.

Symptom & Error Signature

When a 502 Bad Gateway error occurs, users typically see a generic error page in their web browser, often stating "502 Bad Gateway" or "Nginx 502 Bad Gateway." The more critical indicators, however, are found in your server's log files.

Typical Nginx Error Log Entries (/var/log/nginx/error.log):

2023/10/26 14:35:01 [crit] 12345#12345: *123 connect() to unix:/var/run/php/php8.1-fpm.sock failed (2: No such file or directory) while connecting to upstream, client: 192.168.1.10, server: example.com, request: "GET /index.php HTTP/1.1", upstream: "fastcgi://unix:/var/run/php/php8.1-fpm.sock:", host: "example.com"

2023/10/26 14:35:02 [crit] 12346#12346: *124 connect() to unix:/var/run/php/php8.1-fpm.sock failed (13: Permission denied) while connecting to upstream, client: 192.168.1.10, server: example.com, request: "GET /index.php HTTP/1.1", upstream: "fastcgi://unix:/var/run/php/php8.1-fpm.sock:", host: "example.com"

2023/10/26 14:35:03 [error] 12347#12347: *125 upstream prematurely closed connection while reading response header from upstream, client: 192.168.1.10, server: example.com, request: "GET /index.php HTTP/1.1", upstream: "fastcgi://unix:/var/run/php/php8.1-fpm.sock:", host: "example.com"

2023/10/26 14:35:04 [error] 12348#12348: *126 recv() failed (104: Connection reset by peer) while reading response header from upstream, client: 192.168.1.10, server: example.com, request: "GET /index.php HTTP/1.1", upstream: "fastcgi://unix:/var/run/php/php8.1-fpm.sock:", host: "example.com"

These specific messages provide crucial clues about the underlying problem.

Root Cause Analysis

The 502 Bad Gateway error, in this context, signifies a communication breakdown between Nginx and PHP-FPM. Nginx, acting as the frontend web server, attempts to pass PHP requests to PHP-FPM, which processes the PHP code and returns the output. When a Unix socket is used, this communication relies on a special file (the socket) residing in the filesystem.

The primary reasons for a 502 error in this setup are:

  1. PHP-FPM Service Status: PHP-FPM is not running, has crashed, or is unable to start, meaning the Unix socket file doesn't exist or isn't actively listened to.
  2. Socket Path Mismatch: Nginx is configured to connect to a different Unix socket path than where PHP-FPM is actually listening.
  3. Permissions Issues: Nginx, running as the www-data user, lacks the necessary read/write permissions to access the PHP-FPM Unix socket file or its parent directory.
  4. PHP-FPM Resource Exhaustion or Instability: PHP-FPM processes might be crashing due to script errors, memory limits, execution timeouts, or the process pool has run out of available children to handle requests.
  5. Nginx Timeouts: Nginx itself might be timing out waiting for a response from PHP-FPM, especially for long-running PHP scripts.
  6. AppArmor/SELinux Restrictions: While less common on default Ubuntu 22.04 installations, security modules like AppArmor could be preventing Nginx from accessing the socket or PHP-FPM from creating it.

Step-by-Step Resolution

Follow these steps sequentially to diagnose and resolve the Nginx 502 Bad Gateway error.

1. Verify PHP-FPM Service Status

The most common reason for a 502 is PHP-FPM not running.

  1. Check PHP-FPM service status: Ubuntu 22.04 LTS typically uses PHP 8.1. Adjust the version number (8.1) if you are using a different one.

    sudo systemctl status php8.1-fpm
    

    You should see output similar to active (running).

  2. If PHP-FPM is not running: Start and enable the service.

    sudo systemctl start php8.1-fpm
    sudo systemctl enable php8.1-fpm
    
  3. Examine PHP-FPM logs for startup errors: If PHP-FPM fails to start or crashes immediately, its logs will contain crucial information.

    sudo journalctl -u php8.1-fpm -n 50 --no-pager
    

    Look for ERROR, WARNING, or CRITICAL messages indicating configuration issues, memory problems, or permission errors.

  4. Attempt to restart PHP-FPM (even if running): A simple restart can sometimes resolve transient issues.

    sudo systemctl restart php8.1-fpm
    

2. Confirm PHP-FPM Socket Path and Listening Configuration

A mismatch between where Nginx expects the socket and where PHP-FPM creates it is a frequent cause.

  1. Identify Nginx's configured socket path: Open your Nginx site configuration file (e.g., /etc/nginx/sites-available/your_site.conf). Locate the location ~ .php$ block and the fastcgi_pass directive.

    sudo nano /etc/nginx/sites-available/your_site.conf
    

    Look for a line similar to:

    location ~ .php$ {
        include snippets/fastcgi-php.conf;
        fastcgi_pass unix:/var/run/php/php8.1-fpm.sock; # <-- This path
        # ... other fastcgi parameters
    }
    

    Note down the exact path after unix:.

  2. Identify PHP-FPM's listening socket path: Open your PHP-FPM pool configuration file (e.g., /etc/php/8.1/fpm/pool.d/www.conf).

    sudo nano /etc/php/8.1/fpm/pool.d/www.conf
    

    Look for the listen directive:

    listen = /run/php/php8.1-fpm.sock # <-- This path
    

    The path specified in fastcgi_pass in Nginx MUST exactly match the listen path in your PHP-FPM pool configuration. Pay close attention to /var/run/php vs. /run/php – these are often symlinked but can cause issues if not consistent. /run is the standard for systemd.

  3. Verify the socket file exists: After ensuring both Nginx and PHP-FPM configurations match and PHP-FPM is running, check if the socket file is actually created.

    ls -l /run/php/php8.1-fpm.sock
    # Or your specific path, e.g., ls -l /var/run/php/php8.1-fpm.sock
    

    If the file does not exist, check PHP-FPM logs again (journalctl -u php8.1-fpm) for errors during socket creation.

  4. Reload Nginx and PHP-FPM if paths were changed:

    sudo systemctl reload php8.1-fpm
    sudo systemctl reload nginx
    

3. Check Socket Permissions

Even if the socket path matches and PHP-FPM is running, Nginx might not have permission to access it.

  1. Inspect socket permissions: Use ls -l on the socket file.

    ls -l /run/php/php8.1-fpm.sock
    

    A typical healthy output looks like:

    srw-rw-rw- 1 www-data www-data 0 Oct 26 14:30 /run/php/php8.1-fpm.sock
    

    This indicates a socket file (s at the beginning) owned by www-data:www-data with read/write permissions for everyone.

  2. Verify PHP-FPM pool user/group: In /etc/php/8.1/fpm/pool.d/www.conf, ensure the listen.owner, listen.group, and listen.mode directives are correctly set.

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

    0660 ensures that the owner (www-data) and group (www-data) have read/write access. Nginx typically runs as the www-data user, so being in the same group allows access. 0666 or 0777 can also work but are less secure. 0660 is generally preferred.

  3. Confirm Nginx user is in the PHP-FPM group: By default, both Nginx and PHP-FPM run under the www-data user and group on Ubuntu. Verify this for Nginx:

    grep "user" /etc/nginx/nginx.conf
    

    Output usually shows user www-data;. Then check the www-data user's groups:

    id www-data
    

    It should show uid=33(www-data) gid=33(www-data) groups=33(www-data). If Nginx's user is different or not in the PHP-FPM socket's group, you might have a permission issue.

  4. Adjust if necessary: If listen.owner, listen.group, or listen.mode were changed in www.conf, restart PHP-FPM:

    sudo systemctl restart php8.1-fpm
    

4. Investigate PHP-FPM Logs for Crashes or Errors

If the connection is made but Nginx receives an invalid response or connection resets, PHP-FPM itself might be encountering fatal errors or running into resource limits.

  1. Monitor PHP-FPM logs in real-time:

    sudo journalctl -u php8.1-fpm -f
    

    Then try to access your website. Watch for any PHP fatal errors, warnings, or notices related to script execution, memory exhaustion, or child process exits. Look for messages like child exited with code 70 or memory limit of XXXXX bytes exceeded.

  2. Check application-specific PHP error logs: Many PHP applications (e.g., WordPress, Laravel) have their own error logging mechanisms. Consult your application's documentation to find its error log location and review it for specific script failures.

5. Adjust PHP-FPM Process Management Settings & Resource Limits

PHP-FPM might be unable to handle the load or specific requests due to insufficient resources or aggressive timeout settings.

  1. Edit PHP-FPM pool configuration:

    sudo nano /etc/php/8.1/fpm/pool.d/www.conf
    
  2. Review Process Manager (PM) settings:

    • pm = dynamic (default, good for varying loads) or pm = ondemand (saves memory for low traffic sites). pm = static (fixed number of children, good for high traffic and stable memory).
    • pm.max_children: The maximum number of child processes that will be created.
    • pm.start_servers: The number of children created on startup.
    • pm.min_spare_servers: The minimum number of idle server processes.
    • pm.max_spare_servers: The maximum number of idle server processes. If pm.max_children is too low, requests will queue or fail, leading to 502s. Monitor your system's RAM usage to determine appropriate values.

    Increasing pm.max_children substantially without sufficient physical RAM will lead to swapping, severely degrading performance and potentially crashing the server.

  3. Adjust request_terminate_timeout: This setting in PHP-FPM defines how long a single PHP script can run before PHP-FPM kills it. If your scripts are long-running (e.g., processing large files, complex database queries), this can cause 502s if the script times out.

    request_terminate_timeout = 300s # Example: 5 minutes. Default is often 0 (off) or 30s.
    

    Set this to a value higher than your longest expected script execution time.

  4. Increase php_admin_value[memory_limit]: If PHP scripts are exhausting memory, they will crash.

    php_admin_value[memory_limit] = 256M # Or 512M, 1G depending on your application needs
    

    This value overrides the memory_limit set in php.ini for this specific pool.

  5. Restart PHP-FPM after changes:

    sudo systemctl restart php8.1-fpm
    

6. Tune Nginx FastCGI Timeouts

Nginx has its own set of timeouts for FastCGI connections. If PHP-FPM is processing a request but takes too long, Nginx might give up prematurely.

  1. Edit Nginx configuration: You can set these in your server block, location block, or globally in http block (e.g., /etc/nginx/nginx.conf).

    sudo nano /etc/nginx/sites-available/your_site.conf
    
  2. Adjust FastCGI timeout directives:

    location ~ .php$ {
        include snippets/fastcgi-php.conf;
        fastcgi_pass unix:/var/run/php/php8.1-fpm.sock;
    
        fastcgi_read_timeout 300s;  # How long Nginx waits for a response from PHP-FPM
        fastcgi_send_timeout 300s;  # How long Nginx waits to send data to PHP-FPM
        fastcgi_connect_timeout 300s; # How long Nginx waits to connect to PHP-FPM
    
        # Optional: Buffer settings can sometimes help with large responses
        fastcgi_buffers 16 16k;
        fastcgi_buffer_size 32k;
    }
    

    Increase Nginx timeouts after addressing potential PHP script performance issues. Using long timeouts as a primary fix without optimizing your PHP code is often a temporary workaround. Ensure fastcgi_read_timeout is at least as long as or longer than PHP-FPM's request_terminate_timeout.

  3. Test Nginx configuration and reload:

    sudo nginx -t
    sudo systemctl reload nginx
    

7. AppArmor (Advanced / Rare)

Ubuntu 22.04 uses AppArmor for mandatory access control. In rare cases, a misconfigured or custom AppArmor profile could prevent Nginx from accessing the PHP-FPM socket.

  1. Check AppArmor status:

    sudo aa-status
    

    This will show which profiles are loaded and in what mode (enforce/complain).

  2. Look for AppArmor denials in kernel logs:

    sudo dmesg | grep -i apparmor
    sudo journalctl -k | grep -i apparmor
    

    Look for DENIED messages involving nginx or php-fpm attempting to access /run/php/php8.1-fpm.sock or its parent directory.

  3. Temporary test (if suspected): If you suspect AppArmor is the cause, you can temporarily set the Nginx profile to 'complain' mode to see if the error disappears.

    sudo aa-complain /etc/apparmor.d/usr.sbin.nginx
    sudo systemctl restart nginx
    

    If the 502 error goes away, you've identified an AppArmor issue. You would then need to modify the Nginx AppArmor profile to allow socket access, rather than leaving it in complain mode or disabled. Remember to revert to aa-enforce once done testing if this wasn't the issue.

    sudo aa-enforce /etc/apparmor.d/usr.sbin.nginx
    sudo systemctl restart nginx
    

By methodically working through these steps, checking logs, and verifying configurations, you should be able to pinpoint and resolve the Nginx 502 Bad Gateway error stemming from PHP-FPM Unix socket communication issues on your Ubuntu 22.04 LTS server.