
# PHP-FPM by HTTP

## Overview

This template is developed to monitor the FastCGI Process Manager (PHP-FPM) by Zabbix that work without any external scripts.
Most of the metrics are collected in one go, thanks to Zabbix bulk data collection.

The template `PHP-FPM by Zabbix agent` - collects metrics by polling PHP-FPM status-page with HTTP agent remotely.

Note that this solution supports HTTPS and redirects.

## Requirements

Zabbix version: 7.0 and higher.

## Tested versions

This template has been tested on:
- PHP 7
- PHP 8

## Configuration

> Zabbix should be configured according to the instructions in the [Templates out of the box](https://www.zabbix.com/documentation/7.0/manual/config/templates_out_of_the_box) section.

## Setup

Note that depending on your OS distribution, the PHP-FPM executable/service name can vary. RHEL-like distributions usually name both process and service as `php-fpm`, while for Debian/Ubuntu based distributions it may include the version, for example: executable name - `php-fpm8.2`, systemd service name - `php8.2-fpm`. Adjust the following instructions accordingly if needed.

1. Open the PHP-FPM configuration file and enable the status page as shown.
  ```
  pm.status_path = /status
  ping.path = /ping
  ```

2. Validate the syntax to ensure it is correct before you reload the service. Replace the `<version>` in the command if needed.
  ```
  $ php-fpm -t
  ```
  or
  ```
  $ php-fpm<version> -t
  ```

3. Reload the `php-fpm` service to make the change active. Replace the `<version>` in the command if needed.
  ```
  $ systemctl reload php-fpm
  ```
  or
  ```
  $ systemctl reload php<version>-fpm
  ```

4. Next, edit the configuration of your web server.

If you use Nginx, edit the configuration file of your Nginx server block (virtual host) and add the location block below it.
  ```
  # Enable php-fpm status page
  location ~ ^/(status|ping)$ {
  ## disable access logging for request if you prefer
  access_log off;

  ## Only allow trusted IPs for security, deny everyone else
  # allow 127.0.0.1;
  # allow 1.2.3.4;    # your IP here
  # deny all;

  fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
  fastcgi_index index.php;
  include fastcgi_params;
  ## Now the port or socket of the php-fpm pool we want the status of
  fastcgi_pass 127.0.0.1:9000;
  # fastcgi_pass unix:/run/php-fpm/your_socket.sock;
  }
  ```
If you use Apache, edit the configuration file of the virtual host and add the following location blocks.
  ```
  <LocationMatch "/status">
      Require ip 127.0.0.1
      # Require ip 1.2.3.4    # Your IP here
      # Adjust the path to the socket if needed
      ProxyPass "unix:/run/php-fpm/www.sock|fcgi://localhost/status"
  </LocationMatch>

  <LocationMatch "/ping">
      Require ip 127.0.0.1
      # Require ip 1.2.3.4    # Your IP here
      # Adjust the path to the socket if needed
      ProxyPass "unix:/run/php-fpm/www.sock|fcgi://localhost/ping"
  </LocationMatch>
  ```
5. Check the web server configuration syntax. The command may vary depending on the OS distribution and web server.
  ```
  $ nginx -t
  ```
  or
  ```
  $ httpd -t
  ```
  or
  ```
  $ apachectl configtest
  ```

6. Reload the web server configuration. The command may vary depending on the OS distribution and web server.
  ```
  $ systemctl reload nginx
  ```
  or
  ```
  $ systemctl reload httpd
  ```
  or
  ```
  $ systemctl reload apache2
  ```

7. Verify that the pages are available with these commands.
  ```
  curl -L 127.0.0.1/status
  curl -L 127.0.0.1/ping
  ```

If you use another location of the status/ping pages, don't forget to change the `{$PHP_FPM.STATUS.PAGE}/{$PHP_FPM.PING.PAGE}` macro.

If you use another web server port or scheme for the location of the PHP-FPM status/ping pages, don't forget to change the macros `{$PHP_FPM.SCHEME}` and `{$PHP_FPM.PORT}`.

### Macros used

|Name|Description|Default|
|----|-----------|-------|
|{$PHP_FPM.PORT}|
The port of the PHP-FPM status host or container.
|`80`|
|{$PHP_FPM.SCHEME}|
Request scheme which may be http or https
|`http`|
|{$PHP_FPM.HOST}|
The hostname or IP address of the PHP-FPM status for a host or container.
|`localhost`|
|{$PHP_FPM.STATUS.PAGE}|
The path of the PHP-FPM status page.
|`status`|
|{$PHP_FPM.PING.PAGE}|
The path of the PHP-FPM ping page.
|`ping`|
|{$PHP_FPM.PING.REPLY}|
The expected reply to the ping.
|`pong`|
|{$PHP_FPM.QUEUE.WARN.MAX}|
The maximum percent of the PHP-FPM queue usage for a trigger expression.
|`80`|

### Items

|Name|Description|Type|Key and additional info|
|----|-----------|----|-----------------------|
|Get ping page||HTTP agent|php-fpm.get_ping|
|Get status page||HTTP agent|php-fpm.get_status|
|Ping||Dependent item|php-fpm.ping
**Preprocessing**

- 
Regular expression: `{$PHP_FPM.PING.REPLY}($|\r?\n) 1`

⛔️Custom on fail: Set value to: `0`

|
|Processes, active|
The total number of active processes.
|Dependent item|php-fpm.processes_active
**Preprocessing**

- 
JSON Path: `$.['active processes']`

|
|Version|
The current version of the PHP. You can get it from the HTTP-Header "X-Powered-By"; it may not work if you have changed the default HTTP-headers.
|Dependent item|php-fpm.version
**Preprocessing**

- 
Regular expression: `^[.\s\S]*X-Powered-By: PHP/([.\d]{1,}) \1`

⛔️Custom on fail: Discard value

- 
Discard unchanged with heartbeat: `3h`

|
|Pool name|
The name of the current pool.
|Dependent item|php-fpm.name
**Preprocessing**

- 
JSON Path: `$.pool`

- 
Discard unchanged with heartbeat: `3h`

|
|Uptime|
It indicates how long has this pool been running.
|Dependent item|php-fpm.uptime
**Preprocessing**

- 
JSON Path: `$.['start since']`

|
|Start time|
The time when this pool was started.
|Dependent item|php-fpm.start_time
**Preprocessing**

- 
JSON Path: `$.['start time']`

|
|Processes, total|
The total number of server processes currently running.
|Dependent item|php-fpm.processes_total
**Preprocessing**

- 
JSON Path: `$.['total processes']`

|
|Processes, idle|
The total number of idle processes.
|Dependent item|php-fpm.processes_idle
**Preprocessing**

- 
JSON Path: `$.['idle processes']`

|
|Process manager|
The method used by the process manager to control the number of child processes for this pool.
|Dependent item|php-fpm.process_manager
**Preprocessing**

- 
JSON Path: `$.['process manager']`

- 
Discard unchanged with heartbeat: `3h`

|
|Processes, max active|
The highest value of "active processes" since the PHP-FPM server was started.
|Dependent item|php-fpm.processes_max_active
**Preprocessing**

- 
JSON Path: `$.['max active processes']`

|
|Accepted connections per second|
The number of accepted requests per second.
|Dependent item|php-fpm.conn_accepted.rate
**Preprocessing**

- 
JSON Path: `$.['accepted conn']`

- Change per second
|
|Slow requests|
The number of requests that has exceeded your `request_slowlog_timeout` value.
|Dependent item|php-fpm.slow_requests
**Preprocessing**

- 
JSON Path: `$.['slow requests']`

- Simple change
|
|Listen queue|
The current number of connections that have been initiated but not yet accepted.
|Dependent item|php-fpm.listen_queue
**Preprocessing**

- 
JSON Path: `$.['listen queue']`

|
|Listen queue, max|
The maximum number of requests in the queue of pending connections since this FPM pool was started.
|Dependent item|php-fpm.listen_queue_max
**Preprocessing**

- 
JSON Path: `$.['max listen queue']`

|
|Listen queue, len|
The size of the socket queue of pending connections.
|Dependent item|php-fpm.listen_queue_len
**Preprocessing**

- 
JSON Path: `$.['listen queue len']`

|
|Queue usage|
The utilization of the queue.
|Calculated|php-fpm.listen_queue_usage|
|Max children reached|
The number of times that `pm.max_children` has been reached since the PHP-FPM pool was started.
|Dependent item|php-fpm.max_children
**Preprocessing**

- 
JSON Path: `$.['max children reached']`

- Simple change
|

### Triggers

|Name|Description|Expression|Severity|Dependencies and additional info|
|----|-----------|----------|--------|--------------------------------|
|PHP-FPM: Service is down||`last(/PHP-FPM by HTTP/php-fpm.ping)=0 or nodata(/PHP-FPM by HTTP/php-fpm.ping,3m)=1`|High|**Manual close**: Yes|
|PHP-FPM: Version has changed|
The PHP-FPM version has changed. Acknowledge to close the problem manually.
|`last(/PHP-FPM by HTTP/php-fpm.version,#1)<>last(/PHP-FPM by HTTP/php-fpm.version,#2) and length(last(/PHP-FPM by HTTP/php-fpm.version))>0`|Info|**Manual close**: Yes|
|PHP-FPM: Failed to fetch info data|
Zabbix has not received any data for items for the last 30 minutes.
|`nodata(/PHP-FPM by HTTP/php-fpm.uptime,30m)=1`|Info|**Manual close**: Yes
**Depends on**:

- PHP-FPM: Service is down
|
|PHP-FPM: Pool has been restarted|
Uptime is less than 10 minutes.
|`last(/PHP-FPM by HTTP/php-fpm.uptime)<10m`|Info|**Manual close**: Yes|
|PHP-FPM: Manager changed|
The PHP-FPM manager has changed. Acknowledge to close the problem manually.
|`last(/PHP-FPM by HTTP/php-fpm.process_manager,#1)<>last(/PHP-FPM by HTTP/php-fpm.process_manager,#2)`|Info|**Manual close**: Yes|
|PHP-FPM: Detected slow requests|
The PHP-FPM has detected a slow request. 
The slow request means that it took more time to execute than expected (defined in the configuration of your pool).
|`min(/PHP-FPM by HTTP/php-fpm.slow_requests,#3)>0`|Warning||
|PHP-FPM: Queue utilization is high|
The queue for this pool has reached `{$PHP_FPM.QUEUE.WARN.MAX}%` of its maximum capacity. 
Items in the queue represent the current number of connections that have been initiated on this pool but not yet accepted.
|`min(/PHP-FPM by HTTP/php-fpm.listen_queue_usage,15m) > {$PHP_FPM.QUEUE.WARN.MAX}`|Warning||

## Feedback

Please report any issues with the template at [`https://support.zabbix.com`](https://support.zabbix.com)

You can also provide feedback, discuss the template, or ask for help at [`ZABBIX forums`](https://www.zabbix.com/forum/zabbix-suggestions-and-feedback)

