Discover Centmin Mod today
Register Now

Nginx Insight Guide How To Guide For Nginx & PHP-FPM Debugging

Discussion in 'Centmin Mod Insights' started by eva2000, May 16, 2019.

Tags:
Thread Status:
Not open for further replies.
  1. eva2000

    eva2000 Administrator Staff Member

    55,802
    12,272
    113
    May 24, 2014
    Brisbane, Australia
    Ratings:
    +18,858
    Local Time:
    7:37 PM
    Nginx 1.27.x
    MariaDB 10.x/11.4+
    Nginx and PHP-FPM debugging is a last resort to figure out issues you may have with Nginx and PHP-FPM which normal logs can no provide any insight into.

    If you have a lot of free disk space, you can enable debug nginx version and compile a nginx debug build of nginx with NGINX_DEBUG=y variable via persistent config /etc/centminmod/custom_config.inc outlined at centminmod.com/upgrade.html#persistent so place in file /etc/centminmod/custom_config.inc
    Code:
    NGINX_DEBUG=y
    then recompile nginx via centmin.sh menu option 4 and then in your nginx error_log directive add debug option outlined at debugging log and restart nginx and check logs

    They will be very very very verbose and lot alot to disk usage logged to error logs, so ensure you have a lot of disk free space.

    You can minimise this by limiting it to specific ip based client connections too
    After debugging is done, reverse the debug now by setting NGINX_DEBUG=n and recompile Nginx again


    Also check output for these commands - post output wrapped in CODE tags
    Code (Text):
    php -v

    Code (Text):
    php -m

    Code (Text):
    php-config --configure-options


    Examples with strace below:
    With gdb backtrace and PHP debug compiled mode where centmin.sh has a PHPDEBUGMODE variable which you can set to PHPDEBUGMODE=y and recompile php via centmin.sh menu option 5 to enable debug mode for PHP-FPM. After troubleshooting set PHPDEBUGMODE=n and recompile php via centmin.sh menu option 5 again to disable debug mode.
    Code:
    PHPDEBUGMODE=n # --enable-debug PHP compile flag
    Centmin Mod is provide as is, so short of scripted related bugs or issues, any further optimisation to the web stack components - nginx, php-fpm, mariadb mysql, csf firewall etc or web app specific configurations are left to the Centmin Mod user to deal with. So I do not provide any free support for such. Interpretation of the debug logs and outputs are left for you to figure out.

    You'll need to tune your PHP-FPM settings and this is left up to end user to do but here's a thread for starters to enable php status page output outlined at PHP-FPM - CentminMod.com LEMP Nginx web stack for CentOS and PHP-FPM - pm.max_children which outlines the official PHP-FPM config documentation as well. Also read How to troubleshoot & optimize PHP-FPM server?
     
  2. eva2000

    eva2000 Administrator Staff Member

    55,802
    12,272
    113
    May 24, 2014
    Brisbane, Australia
    Ratings:
    +18,858
    Local Time:
    7:37 PM
    Nginx 1.27.x
    MariaDB 10.x/11.4+
    Centmin Mod 140.00beta01 was updated on May 6, 2025 and 132.00stable on May 7, 2025 with improved PHPDEBUGMODE='y' PHP-FPM debug compilation routine/mode for better gdb backtracing support as outlined at PHP :: Generating a gdb backtrace for troubleshooting PHP-FPM crashes i.e. signal 11 segfaults etc.

    1. Layman’s Overview

    When you see
    Code (Text):
    WARNING: [pool www] child 233636 exited on signal 11 (SIGSEGV - core dumped) after 6680.030202 seconds from start
    


    it means one of PHP-FPM’s worker processes tried to access memory it shouldn’t have—like picking up a puzzle piece that doesn’t fit. The operating system immediately stops (“kills”) that process to protect the rest of the system. In everyday terms:
    • PHP-FPM forks off many “child” workers to run your scripts.
    • A “signal 11” (SIGSEGV) is the kernel’s way of saying, “Hold on—this process just poked outside its sandbox.”
    • The worker dies, often leaving a “core dump” (a snapshot of its memory) you can use to debug.
    • If too many children die in a short time, PHP-FPM will reload the pool to try to recover.
    2. Technical Deep Dive
    • Process Memory Layout
      Each PHP-FPM child has its own virtual address space divided roughly into:
      1. Text segment (compiled code)
      2. Data/heap (dynamically allocated variables, arrays, opcodes)
      3. Stack (function calls, local variables)
    • What Triggers SIGSEGV?
      • Invalid Read/Write: Dereferencing a pointer that’s NULL, uninitialized, or already freed.
      • Buffer Overrun: Writing past the end of an allocated block.
      • Stack Overflow: Deep recursion or allocating too much on the stack.
      • Memory Corruption: Heap metadata gets clobbered (e.g., double free()) so subsequent allocations return garbage.
    3. Ten Common Causes (with Examples)
    • Buggy C-level Extensions
      Lay Explanation: Third-party add-ons written in C can contain memory-management bugs that crash PHP-FPM.
      Technical Detail & Example: An off-by-one in Imagick’s pixel buffer handling can write past the end of an array, triggering a segfault when code later reads that corrupted memory.
    • Library Version Mismatch
      Lay Explanation: If PHP or its extensions expect different versions of system libraries, pointers and symbols can misalign.
      Technical Detail & Example: Upgrading glibc to 2.35 while using an OPCache built against 2.30 can cause zend_hash_index_find() to dereference invalid pointers and crash.
    • OPcache Shared-Memory Corruption
      Lay Explanation: Opcode caches live in shared memory; if that segment is corrupted, workers fault when fetching code.
      Technical Detail & Example: On an NFS-mounted /tmp, two PHP-FPM masters race to write the same OPcache segment, leading to invalid bytecode reads and SIGSEGV.
    • Heap Metadata Corruption
      Lay Explanation: Double-freeing or mismatched allocations can clobber the allocator’s internal structures.
      Technical Detail & Example: A custom extension calls efree() twice on the same string, corrupting glibc’s malloc bins so subsequent ecalloc() returns garbage pointers.
    • Stack Overflow / Deep Recursion
      Lay Explanation: Scripts that recurse too deeply exhaust the worker’s call stack and crash.
      Technical Detail & Example: A recursive JSON walker on a limited 8 KB stack (ulimit -s 8192) corrupts the return address, causing a segfault on function return.
    • ZTS vs Non-ZTS Build Mismatch
      Lay Explanation: Running a non-thread-safe PHP build in a threaded FPM mode can lead to race conditions.
      Technical Detail & Example: PHP compiled without ZTS but run under pm = dynamic with threading causes two threads to free the same Zend resource concurrently, corrupting memory.
    • Hardware / ECC Memory Errors
      Lay Explanation: Failing RAM or transient bit-flips can randomly poison process memory.
      Technical Detail & Example: A single bit-flip flips a function pointer, so when PHP later calls it, it jumps to an invalid address and faults.
    • Kernel / glibc Bugs
      Lay Explanation: Rare OS-level bugs in memory‐management routines can surface under heavy load.
      Technical Detail & Example: A known RHEL 8 glibc regression in malloc_consolidate() under concurrency corrupts free lists, causing crashes in all PHP-FPM children.
    • Container Memory Limits or Seccomp Rules
      Lay Explanation: Aggressive cgroup limits or filter rules can cause failed memory mappings that PHP doesn’t check.
      Technical Detail & Example: Docker with too-low --memory-swap makes mmap() return MAP_FAILED; PHP then writes to a null pointer, triggering SIGSEGV.
    • Corrupted Binaries / Filesystem Errors
      Lay Explanation: If your .so modules on disk get damaged, loading them executes invalid instructions.
      Technical Detail & Example: A truncated opcache.so left by a failed RPM upgrade “loads” but immediately crashes when its initialization function runs.
    Enable PHP-FPM Debug Mode

    To troubleshoot PHP-FPM segfaults, you need to enable PHP-FPM debug mode and do gdb backtraces to get a clue as to the issue. Centmin Mod is provided as is, so interpreting the gdb backtraces and troubleshooting would be left to you to figure out. Members are free to help each other out as well.

    When the persistent config file temporarily enables PHP debug mode for gdb backtracing troubleshooting PHP :: Generating a gdb backtrace via persistent config file variables set in /etc/centminmod/custom_config.inc

    Code (Text):
    PHPDEBUGMODE='y'
    AUTODETECPHP_OVERRIDE='y' # ensure all PHP extensions are recompiled


    Then you re‑compile PHP via centmin.sh menu option 5

    Which will do the following:

    1. adds ‑g3 ‑O0 ‑fno‑omit‑frame‑pointer to **CFLAGS/CXXFLAGS**
    2. installs a systemd drop‑in file /etc/systemd/system/php-fpm.service.d/10-coredump.conf to setup LimitCORE=infinity
    3. points kernel.core_pattern to /tmp/core-%e-%p-%t
    4. sets fs.suid_dumpable = 1

    Then when PHP-FPM crashes are as segfaults, it will create a core dump in /tmp i.e. /tmp/core-php-fpm-3519929-1746468959. You can use find command to list them. The PHP-FPM core dumps are unique for each PHP-FPM binary so if you upgrade or downgrade or recompile PHP-FPM, you should use a newer PHP core dump
    Code (Text):
    find /tmp -maxdepth 1 -type f -name 'core-*'
    /tmp/core-php-fpm-3519929-1746468959
    

    Then use gdb to backtrace the PHP core dump (PHP :: Generating a gdb backtrace) for clues with onliner that saves gdb backtrace output to /tmp/gdb.log

    Code (Text):
    gdb -q  $(which php-fpm)  /tmp/core-php-fpm-3519929-1746468959 -ex 'set pagination off' -ex 'set logging file /tmp/gdb.log' -ex 'set logging enabled on' -ex 'thread apply all bt full' -ex quit


    Disable PHP-FPM Debug Mode

    Then, to disable PHP debug mode, set persistent config file variables in /etc/centminmod/custom_config.inc. Keep AUTODETECPHP_OVERRIDE='y' set for this centmin.sh menu option 5 run so that all custom PHP extensions are recompiled this one time. You can later set AUTODETECPHP_OVERRIDE='n' or remove line for future centmin.sh menu option 5 runs. This option usually defaults to AUTODETECPHP_OVERRIDE='n' so that same PHP-FPM version recompiles skip custom PHP extension recompiles as the PHP extensions are already built for same PHP version and only custom PHP extension recompiles occur when PHP version differs i.e. upgrade/downgrade PHP versions:

    Code (Text):
    PHPDEBUGMODE=n
    AUTODETECPHP_OVERRIDE='y' # ensure all PHP extensions are recompiled


    Then you re‑compile PHP via centmin.sh menu option 5

    This will do the following:

    1. remove the systemd drop‑in /etc/systemd/system/php-fpm.service.d/10-coredump.conf
    2. restore the original kernel.core_pattern & fs.suid_dumpable settings
    3. re‑compile PHP without heavy debug flags
    4. if PHP_CLEAN_COREDUMPS=y (the default) delete stale core files in /tmp
     
Thread Status:
Not open for further replies.