PHP-FPM Configuration for 1C-Bitrix
PHP-FPM Configuration for 1C-Bitrix
A server with 8 GB RAM and a 4-core CPU serving 50 concurrent users starts responding in 3–5 seconds. top shows 95% CPU on php-fpm processes and swap activity. The default PHP-FPM configuration is designed for minimal memory consumption, not for high load. For 1C-Bitrix — with its heavy object models and ORM — this is unacceptable.
Diagnosing the Current State
Before tuning, get a snapshot of the real picture:
# Number of php-fpm processes and their status
ps aux | grep php-fpm | grep -v grep | wc -l
# Memory consumption per process
ps aux --sort=-%mem | grep php-fpm | head -5 | awk '{print $6/1024 " MB"}'
# Pool status via the status page
curl -s http://127.0.0.1/php-fpm-status?full
A typical picture: 20–30 PHP-FPM workers using 80–150 MB each. 30 × 120 MB = 3.6 GB for PHP alone on an 8 GB RAM server.
Pool Configuration
Pool configuration file /etc/php/8.1/fpm/pool.d/bitrix.conf:
[bitrix]
user = bitrix
group = bitrix
listen = /run/php/php8.1-fpm-bitrix.sock
listen.owner = www-data
listen.group = www-data
listen.mode = 0660
; Process management
pm = dynamic
pm.max_children = 30
pm.start_servers = 8
pm.min_spare_servers = 5
pm.max_spare_servers = 15
pm.max_requests = 1000
; Timeouts
request_terminate_timeout = 120s
request_slowlog_timeout = 5s
slowlog = /var/log/php-fpm/slow.log
; Status
pm.status_path = /php-fpm-status
Calculating pm.max_children:
max_children = (Available RAM for PHP) / (Average process size)
With 8 GB RAM, 2 GB for the OS, 1 GB for MySQL: 5 GB / 120 MB = ~41. Allow headroom for growth — set to 30–35.
pm = dynamic vs pm = static: dynamic conserves memory under low load. static is preferable under consistently high load — no overhead from forking new processes.
pm.max_requests = 1000: restarting a worker after 1,000 requests prevents memory leaks. This is common for projects with many third-party PHP modules.
PHP Configuration for 1C-Bitrix
/etc/php/8.1/fpm/php.ini (parameters critical for 1C-Bitrix):
; Memory
memory_limit = 256M
; Execution time
max_execution_time = 90
max_input_time = 60
; File uploads (for images and price lists)
upload_max_filesize = 256M
post_max_size = 256M
max_file_uploads = 50
; Sessions
session.gc_maxlifetime = 3600
session.save_handler = memcached
session.save_path = "127.0.0.1:11211"
; OPcache
opcache.enable = 1
opcache.memory_consumption = 256
opcache.max_accelerated_files = 20000
opcache.validate_timestamps = 1
opcache.revalidate_freq = 60
opcache.jit = tracing
opcache.jit_buffer_size = 64M
; Disable dangerous functions
disable_functions = exec,passthru,shell_exec,system,proc_open,popen
session.save_handler = memcached — sessions stored in memory instead of the filesystem. Critical for multi-server setups (clusters) and speeds up session access by 10–20×.
opcache.jit = tracing — the PHP 8.0+ JIT compiler. For 1C-Bitrix with its procedural code, this delivers a 10–30% CPU performance gain.
Separate Pools for Different Tasks
It is recommended to split pools:
bitrix.conf — main site, 30 workers, 256M memory
agents.conf — Bitrix agents, 3–5 workers, 512M memory, longer timeout
import.conf — 1C import, 1–2 workers, 1G memory, 300s timeout
Agents and 1C imports must not compete with user requests for workers. Without separation, the import pool can occupy all 30 slots during price list processing.
Monitoring
# Watch status in real time
watch -n1 'curl -s http://127.0.0.1/php-fpm-status | grep -E "active|idle|total"'
If active processes consistently equals max_children, the pool is saturated and requests are being queued. Either increase max_children or optimize the application code.

