Web Server Intermediate

Troubleshooting Nginx 504 Gateway Timeout on Alpine Linux with PHP-FPM

Resolve Nginx 504 Gateway Timeout errors on Alpine Linux setups, often due to PHP-FPM timeouts, resource issues, or misconfigurations. A guide for SysAdmins.

👨‍💻
Senior Systems Architect • Verified in Staging Labs

Resolve Nginx 504 Gateway Timeout errors on Alpine Linux setups, often due to PHP-FPM timeouts, resource issues, or misconfigurations. A guide for SysAdmins.

A 504 Gateway Timeout error in Nginx indicates that Nginx, acting as a reverse proxy, did not receive a timely response from an upstream server (such as PHP-FPM, a Node.js application, or another microservice) it was expecting to communicate with. When encountered on Alpine Linux, this often points to performance bottlenecks or misconfigurations within the upstream application server or the communication parameters between Nginx and its backend. This guide provides a comprehensive, step-by-step approach to diagnosing and resolving this common web server issue.

Symptom & Error Signature

Users attempting to access your web application will see a "504 Gateway Timeout" error page in their browser. On the server side, your Nginx error logs will typically contain entries similar to these:

2026/09/21 14:35:01 [error] 12345#12345: *1234 upstream timed out (110: Connection timed out) while reading response header from upstream, client: 192.168.1.100, server: example.com, request: "GET /long-running-script.php HTTP/1.1", upstream: "fastcgi://unix:/var/run/php-fpm.sock:", host: "example.com"

2026/09/21 14:35:02 [warn] 12346#12346: *1234 a client request body is buffered to a temporary file /var/cache/nginx/client_temp/0000000001, client: 192.168.1.100, server: example.com, request: "POST /upload-large-file.php HTTP/1.1", host: "example.com"

The key phrase to look for is upstream timed out. The upstream specified will often be a fastcgi path for PHP-FPM, or an http path for other proxy scenarios.

Root Cause Analysis

The 504 Gateway Timeout is a consequence of the upstream server failing to respond within a configured timeframe. The underlying reasons can be diverse:

  1. Upstream Server Overload/Crash: The application server (e.g., PHP-FPM) might be overwhelmed by requests, experiencing a crash, or simply not running.
  2. Long-Running Scripts/Operations: The backend application is executing a task that exceeds the defined timeout limits. This could involve complex database queries, external API calls with slow responses, or intensive data processing.
  3. Insufficient Resources: The server hosting the upstream application might be experiencing resource starvation (CPU, RAM, I/O), leading to slow processing and eventual timeouts.
  4. PHP-FPM Worker Pool Exhaustion: The PHP-FPM process manager might not have enough worker processes configured to handle the current load, causing requests to queue up and time out.
  5. Incorrect Timeout Configurations: The timeout settings in Nginx and/or the upstream server (e.g., PHP-FPM's request_terminate_timeout) are set too low for the application's typical processing time.
  6. Network Latency/Connectivity Issues: Though less common in typical local Nginx-to-PHP-FPM setups (e.g., via Unix socket), network delays or disconnections can cause timeouts when Nginx proxies to a remote upstream.
  7. Deadlock/Blocking Issues: A specific application script might be stuck in a loop, waiting for a resource, or deadlocked, preventing it from responding.

Step-by-Step Resolution

Given Alpine Linux's lightweight nature and common use in containerized environments, these steps consider both standalone and Docker-based deployments.

1. Verify Upstream Service Status

The first step is to ensure your upstream application server is running and healthy. For PHP applications, this is typically PHP-FPM.

On a standalone Alpine server (using OpenRC):

# Check PHP-FPM service status
sudo rc-service php-fpm status

# If not running or unhealthy, attempt to restart it
sudo rc-service php-fpm restart

# Check logs for immediate errors
sudo tail -f /var/log/php-fpm.log

In a Docker container:

# List running containers to find your PHP-FPM container
docker ps

# Check logs of the PHP-FPM container
docker logs <php-fpm-container-name-or-id>

# If needed, restart the container
docker restart <php-fpm-container-name-or-id>

If PHP-FPM is repeatedly crashing, inspect its logs (/var/log/php-fpm.log or container logs) for fatal errors, memory limits being hit, or unhandled exceptions. This might indicate an application-level bug requiring code fixes.

2. Adjust Nginx Proxy Timeout Settings

Nginx has several timeout directives that control how long it waits for a response from the upstream server. The default values might be too low for complex applications.

Locate Nginx Configuration: On Alpine, Nginx configuration files are typically in /etc/nginx/. Site-specific configurations are often in /etc/nginx/http.d/default.conf or a custom file like /etc/nginx/http.d/your-site.conf.

Edit Nginx Configuration:

# Use your preferred editor, e.g., vi or nano (install nano if not present: apk add nano)
sudo vi /etc/nginx/http.d/default.conf

Inside your location ~ .php$ block or location / block (if proxying to a non-PHP upstream), add or modify the following directives:

http {
    # ... other http settings ...
    fastcgi_read_timeout 300s; # For PHP-FPM
    proxy_read_timeout 300s; # For generic HTTP proxy

    server {
        # ... other server settings ...

        location ~ .php$ {
            # ... existing PHP-FPM settings ...
            include fastcgi.conf; # Or fastcgi_params
            fastcgi_pass unix:/var/run/php-fpm.sock; # Or your specific PHP-FPM socket/IP:port

            # Add or increase these if they exist
            fastcgi_connect_timeout 60s; # How long to wait for a connection to PHP-FPM
            fastcgi_send_timeout 300s; # How long to wait for data to be sent to PHP-FPM
            fastcgi_read_timeout 300s; # How long to wait for data from PHP-FPM
        }

        # Example for a generic HTTP proxy upstream
        location /api/ {
            proxy_pass http://your_api_backend:8080;
            proxy_connect_timeout 60s;
            proxy_send_timeout 300s;
            proxy_read_timeout 300s;
        }
    }
}

Setting timeouts excessively high (e.g., thousands of seconds) can make your server vulnerable to slowloris attacks or prevent Nginx from quickly freeing up resources from unresponsive backend processes. Choose values that are reasonable for your application's expected maximum processing time.

Test and Reload Nginx:

sudo nginx -t
sudo rc-service nginx reload # Or `systemctl reload nginx` if systemd is installed

3. Adjust PHP-FPM Timeout and Resource Settings

PHP-FPM has its own timeout settings, notably request_terminate_timeout. If Nginx's timeout is higher than PHP-FPM's, Nginx will wait indefinitely while PHP-FPM has already killed the script, leading to the 504.

Locate PHP-FPM Configuration: On Alpine, PHP-FPM configuration is typically in /etc/php*/php-fpm.conf and pool-specific configurations in /etc/php*/php-fpm.d/www.conf (or default.conf).

Edit PHP-FPM Pool Configuration:

sudo vi /etc/php*/php-fpm.d/www.conf # Adjust path for your PHP version (e.g., php81)

Find and modify the request_terminate_timeout directive:

[www]
; The timeout for serving a single request after which the worker process will
; be killed. This option should be used when the 'max_execution_time' PHP
; directive is not enough to stop bad scripts.
; Unit: seconds. Default value: 0 (disabled).
;
request_terminate_timeout = 300s

Ensure request_terminate_timeout is equal to or slightly less than Nginx's fastcgi_read_timeout. This allows PHP-FPM to terminate a hung script before Nginx times out, providing a cleaner error message in PHP-FPM logs.

Adjust PHP-INI Settings: The global PHP max_execution_time and memory_limit also play a crucial role. If a script exceeds these, it will be terminated by PHP itself.

sudo vi /etc/php*/php.ini

Modify these values:

max_execution_time = 300
memory_limit = 256M

Restart PHP-FPM:

sudo rc-service php-fpm restart # Or `docker restart <php-fpm-container-name-or-id>`

4. Optimize PHP-FPM Worker Pool Configuration

If your server is under high load, an insufficient number of PHP-FPM workers can cause requests to queue up and time out.

Edit PHP-FPM Pool Configuration:

sudo vi /etc/php*/php-fpm.d/www.conf

Adjust the pm (process manager) settings. A common strategy is pm = ondemand or pm = dynamic. ondemand is good for lower memory usage on idle, dynamic for consistent performance under varying load, and static for predictable high load.

Example for pm = dynamic:

[www]
; Choose how the process manager will control the number of child processes.
; Possible values: static, ondemand, dynamic
pm = dynamic

; The number of child processes to be created when pm is set to 'static' and the
; maximum number of child processes to be created when pm is set to 'dynamic'.
; This value is mandatory.
pm.max_children = 50 ; Adjust based on available RAM (e.g., 20-50 per GB RAM)

; The number of child processes created on startup when pm is set to 'dynamic'.
pm.start_servers = 10

; The minimum number of idle server processes; if the number of idle processes
; drops below this value, new children will be created.
pm.min_spare_servers = 5

; The maximum number of idle server processes; if the number of idle processes
; exceeds this value, children will be killed.
pm.max_spare_servers = 20

; The number of requests each child process should execute before respawning.
; Useful for working around memory leaks in 3rd party libraries.
pm.max_requests = 1000 ; Set to 0 for unlimited, or a reasonable number like 1000-5000

Setting pm.max_children too high can lead to the server running out of memory and crashing, especially on Alpine systems where resources are often constrained. Monitor your RAM usage carefully (free -h or htop). A good rule of thumb: (Total RAM - OS_Overhead) / (Avg_PHP_Process_Memory_Usage). If a typical PHP process uses 50MB and you have 2GB RAM, (2048 - 200) / 50 = ~36 processes.

Restart PHP-FPM:

sudo rc-service php-fpm restart # Or `docker restart <php-fpm-container-name-or-id>`

5. Analyze Application and System Logs

Logs are your best friends for diagnosing the true cause of long-running requests.

Nginx Access Logs: Check for requests taking an unusually long time.

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

Look for the $request_time or $upstream_response_time values if you have them configured to identify slow requests.

PHP-FPM Error Logs: This is crucial for identifying PHP errors, warnings, or scripts being terminated by request_terminate_timeout.

sudo tail -f /var/log/php-fpm.log # Or your specific PHP-FPM error log path

Application-Specific Logs: Many frameworks (Laravel, Symfony, WordPress) have their own logging mechanisms. Check these for database query times, external API call latencies, or application-level errors.

System Resource Monitoring: Use tools like htop, top, free -h, iotop to monitor server resources (CPU, Memory, I/O). Install them if needed:

sudo apk add htop iotop
htop
free -h
iotop

Look for high CPU usage, low free memory, or excessive I/O wait times, which can indicate bottlenecks causing slowdowns.

6. Docker-Specific Considerations

If running in a Docker environment, ensure:

  • Resource Limits: Your Docker containers have sufficient CPU and memory allocated. Use docker update --cpu-shares <value> --memory <value> <container-name> if needed.
  • Networking: Nginx can correctly resolve and connect to the PHP-FPM service (e.g., using Docker Compose service names, or correct IP addresses). If using a Unix socket, ensure it's mapped correctly (e.g., via a shared volume or in the same container).
  • Health Checks: Implement Docker health checks for your PHP-FPM container to automatically restart unhealthy instances.
# Example docker-compose.yml snippet
services:
  nginx:
    image: nginx:alpine
    # ...
    ports:
      - "80:80"
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf
      - ./nginx-site.conf:/etc/nginx/http.d/default.conf
      - /var/run/php-fpm.sock:/var/run/php-fpm.sock # Shared socket if both in same network namespace or mounted

  php-fpm:
    image: php:8.1-fpm-alpine
    # ...
    volumes:
      - ./:/var/www/html
      - ./php-fpm.conf:/usr/local/etc/php-fpm.d/www.conf
      - ./php.ini:/usr/local/etc/php/php.ini
      - /var/run/php-fpm.sock:/var/run/php-fpm.sock # Create socket here
    healthcheck:
      test: ["CMD", "php-fpm", "-t"]
      interval: 10s
      timeout: 5s
      retries: 3

By systematically checking and adjusting these configurations, monitoring logs, and analyzing resource usage, you can effectively diagnose and resolve Nginx 504 Gateway Timeout errors on your Alpine Linux web server.

👨‍💻

Johnathon Wheeler

Senior Systems Architect & DevOps Engineer • Austin, TX

Connect on LinkedIn →

Johnathon has over 16 years of hands-on experience designing, debugging, and scaling Linux web hosting stacks, container clusters, and high-availability database architectures. Every guide on ButItWorkedLocal is independently tested against Debian 12, Ubuntu 24.04/22.04 LTS, Rocky Linux, and Docker environments to guarantee reproducibility in production.

🛡️

Our Production Verification Guarantee

Encountering a bug not covered here or running a non-standard kernel configuration? Our solutions are continually refined against real production incidents. Submit an environment trace for our editorial team to replicate.