A server with 8 GB RAM and a 4-core CPU under 50 simultaneous users slows down to 5-second response times. top shows 95% CPU on php-fpm, swap full. The default PHP-FPM configuration works for simple sites, but not for Bitrix with its heavy ORM and object caches. Under such load, page generation time can exceed 10 seconds, catastrophically affecting user experience.
We have been configuring PHP-FPM for Bitrix for many years — over 50 projects. During this time, we have developed configurations that handle 200+ simultaneous users on a single server. This article provides specific parameters and calculations for a typical project. Typical cost savings from this optimization range from 30-50% on server resources.
Why Default PHP-FPM Doesn't Fit Bitrix
The default pool usually uses pm = dynamic with pm.max_children = 5. For a Bitrix store with 50 users, this is insufficient — 5 workers get blocked by slow requests, others wait in the queue. Result: Timeout 504. An optimized configuration delivers a 2-3x speed increase over the standard one. With JIT, PHP execution is 10-30% faster compared to no JIT.
How to Calculate the Number of Workers
Formula: max_children = (Available RAM for PHP) / (Average process size). With 8 GB RAM, 2 GB for OS, 1 GB for MySQL: 5 GB / 120 MB ≈ 41. Take a safety margin: 30-35.
| RAM server |
OS + MySQL |
Available for PHP |
Process size |
max_children |
| 8 GB |
3 GB |
5 GB |
120 MB |
30-35 |
| 16 GB |
4 GB |
12 GB |
120 MB |
80-100 |
| 32 GB |
8 GB |
24 GB |
120 MB |
160-200 |
Diagnostics of Current State
Before tuning, take a snapshot of the actual 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 status page
curl -s http://127.0.0.1/php-fpm-status?full
Typical picture: 20-30 PHP-FPM workers consuming 80-150 MB each. 30 * 120 MB = 3.6 GB just for PHP on an 8 GB 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
Process management modes: dynamic works for variable load — saves memory during idle but spends resources on fork. static minimizes request delay under stable load but does not adapt to drops. ondemand saves maximum during rare spikes but causes delays on startup. For most Bitrix projects, we choose dynamic. Using static reduces request latency by up to 20% compared to dynamic under consistent load.
pm.max_requests = 1000 — restart worker after 1000 requests prevents memory leaks. Typical for projects with many third-party PHP modules.
How We Configure PHP-FPM Step by Step
- Audit current server state using
ps, curl pool status.
- Calculate
pm.max_children based on free memory.
- Create separate pools for the site, agents, and 1C import.
- Tune
php.ini with JIT, Memcached for sessions, OPcache.
- Configure slowlog and monitoring.
- Test under load.
PHP Configuration for Bitrix
/etc/php/8.1/fpm/php.ini (critical parameters for Bitrix):
; Memory
memory_limit = 256M
; Execution time
max_execution_time = 90
max_input_time = 60
; File uploads (for uploading 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 in memory instead of filesystem. Critical for multi-server clusters and speeds up session access by 50x compared to files.
opcache.jit = tracing — JIT compiler for PHP 8.0+. For Bitrix's procedural code, gives 10-30% CPU boost. OPcache stores compiled scripts in shared memory, reducing file I/O.
Comparison of default and optimized PHP parameters:
| Parameter |
Default value |
Optimized |
Impact |
memory_limit |
128M |
256M |
Increase for heavy pages |
upload_max_filesize |
2M |
256M |
Upload large price lists |
session.save_handler |
files |
memcached |
50x faster session access compared to files |
opcache.memory_consumption |
128 |
256 |
Cache more code |
Why Separate Pools for Agents and 1C Import?
It is recommended to separate 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 import should 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 is consistently equal to max_children — the pool is overloaded, requests are queued. You need either increase max_children or optimize code.
Typical PHP-FPM Configuration Mistakes
- Too small pm.max_children. If max_children is less than the number of concurrent requests, requests queue up. Solution — calculate using the formula above.
- Missing slowlog. Without slowlog, you won't know which requests are slow. Enable request_slowlog_timeout = 5s.
- Single pool for all tasks. 1C import and agents should have separate pools, otherwise user requests get blocked.
What's Included in Turnkey Configuration
We offer a comprehensive PHP-FPM optimization service for 1C-Bitrix:
- Audit of current server and PHP configuration
- Calculation of optimal worker count and pool sizes
- Configuration of separate pools for agents and import
- Optimization of OPcache and JIT
- Migration of sessions to Memcached or Redis
- Setup of slowlog and monitoring
- Configuration documentation
- Guarantee of stable operation under load
Contact us for a free audit of your PHP-FPM configuration. Order turnkey setup and achieve significant savings on server resources. Savings depend on your server configuration. Our one-time setup fee depends on scope and is typically recouped quickly.
Timeline and Process
Typical timeline: 2–5 business days depending on server complexity.
-
Day 1: Data collection and audit (server specs, current configs, load pattern).
-
Day 2: Analysis and design (calculate workers, plan pool separation, choose caching).
-
Day 3–4: Implementation (configure pools, php.ini, sessions, slowlog, monitoring).
-
Day 5: Load testing, final tuning, and documentation.
Checklist for Self-Check (Optional)
- Calculate
pm.max_children based on free RAM.
- Set
pm.max_requests to 1000 to prevent memory leaks.
- Enable
request_slowlog_timeout and check slowlog daily.
- Use separate pools for agents and 1C import.
- Store sessions in Memcached or Redis.
- Enable OPcache with JIT (PHP 8.0+).
- Monitor
active processes to avoid queue buildup.
Read also read more on Wikipedia and official documentation for in-depth study.
Problems We Solve
rsync -avz to production on Friday evening, restart php-fpm, and the site returns 502 — local database settings remain in .settings.php. Classic “deployment the old way” turns into a lottery. Another scenario: a module update from the admin panel breaks a custom component template — changes aren’t tracked in version control, recovery takes hours. Without a DevOps culture, every release is a gamble.
We design a predictable DevOps cycle for 1C-Bitrix: from Docker environment to Telegram alerts. Each deployment becomes routine, each incident triggers a context‑rich alert. Below is how we solve real Bitrix team problems — with numbers, tools, and proven configurations.
Why DevOps Is Critical for Bitrix Projects?
Bitrix projects carry specific infrastructure requirements: heavy e‑commerce catalogs, 1C exchange via CommerceML, dozens of agents and events. Without CI/CD and monitoring, every change introduces risk. A single stuck agent can silently break a 1C sync for hours; a manual deployment mistake can cost a client lost orders. We’ve seen teams spend 12 hours per month just on manual deployments and crash recovery — after our CI/CD pipeline, that drops to zero.
CI/CD Pipeline: From Commit to Production Without Hands
Git migration – we move the project from FTP to Git (GitLab, GitHub, Bitbucket). Branch structure: main (production), staging, develop, feature branches. A proper .gitignore for Bitrix is non‑trivial:
/bitrix/cache/
/bitrix/managed_cache/
/bitrix/stack_cache/
/upload/
/bitrix/php_interface/dbconn.php
/bitrix/.settings.php
/bitrix/license_key.php
Miss managed_cache/ → the repository bloats to gigabytes. Forget license_key.php → the key leaks.
CI pipeline – automatically runs PHPStan level 5+, PHP_CodeSniffer with Bitrix standard, PHPUnit for business logic, composer audit, frontend build.
CD pipeline – deploys without human intervention. Merge to staging → deploy to staging. Merge to main → deploy to production (with optional manual confirmation). Zero‑downtime via symlink strategy: new version in a separate folder, current → symlink switches in milliseconds. upload/ lives outside release directories. Healthcheck fails → symlink rolls back automatically. Tools: GitLab CI/CD, GitHub Actions, Deployer (PHP). Deployer’s built‑in recipes for Bitrix handle shared directories and symlink deployment out‑of‑the‑box.
Docker Environment: How We Eliminate “It Works on My Machine”
The Docker environment fixes versions of all components: nginx, PHP, MySQL, Redis. Configuration mirrors production — same PHP modules, same php.ini.
Local development – docker-compose.yml includes nginx + php‑fpm 8.1/8.2 + MySQL 8.0 (or MariaDB 10.6) + Redis + Memcached. New developer: git clone + docker-compose up -d → writes code within 5 minutes. Parallel work on different PHP versions via separate compose files.
Bitrix specifics in Docker:
-
/upload/ mounted as a named volume (not bind mount — permission and speed issues on Windows/Mac).
- Cron jobs (
/bitrix/modules/main/tools/cron_events.php) run via a separate container with supervisord.
- “Proactive Protection” module (
security) blocks requests through reverse proxy — need set_real_ip_from and realip_module.
- Database config (
dbconn.php, .settings.php) set via environment variables, never through a volume with production configs.
Production – multi‑stage Dockerfile (build stage for assets, production stage with lightweight image), Docker Registry for tagged images, orchestration via Docker Swarm or Kubernetes for large projects.
Nginx and PHP‑FPM Configuration for Bitrix Performance
The difference between “site is slow” and 200 ms TTFB lies in configuration. nginx:
-
location blocks for Bitrix handle urlrewrite.php for friendly URLs.
-
/bitrix/admin/ IP‑restricted via allow/deny.
-
expires 30d for static files — CSS, JS, images cached by the browser.
- Brotli compression (15‑20% better than gzip):
brotli on; brotli_comp_level 6;.
- Rate limiting on
/bitrix/tools/ protects against brute force.
- HTTP/2 push for critical resources.
php‑fpm: pm = dynamic. Calculate pm.max_children: (RAM - RAM_other_services) / avg_memory_per_process. For Bitrix, avg is 40–80 MB. OPcache: opcache.memory_consumption=256 (default 128 is insufficient — Bitrix loads thousands of files), opcache.max_accelerated_files=20000, opcache.validate_timestamps=0 in production (reset via cachetool opcache:reset on deployment). php.ini: memory_limit=256M (up to 512M for heavy imports), max_execution_time=60, upload_max_filesize=100M. Slowlog with request_slowlog_timeout=5s catches bottlenecks before users complain.
Monitoring and Logging: What We Track
Infrastructure – Prometheus + Grafana: metrics for CPU, RAM, disk, network, service status. Alerts: CPU > 80% for 5 minutes, free RAM < 500 MB, disk > 85%, php‑fpm queue > 0 (worker shortage). Node Exporter, MySQL Exporter, PHP‑FPM Exporter collect data.
Application – Uptime check every 60 seconds → Telegram alert within a minute of downtime. Response time of key URLs: /, /catalog/, /personal/order/make/. Sentry for PHP errors — structured errors with context. Bitrix agents (b_agent): we check NEXT_EXEC < NOW() - INTERVAL 1 HOUR — a stuck agent silently breaks 1C exchange.
Logging – ELK Stack or Loki + Grafana: nginx access/error, php‑fpm slow log, MySQL slow query log, Bitrix errors. Rotation via logrotate — without it, access.log takes 50 GB after six months.
Backup Strategy and Disaster Recovery
| Component |
Frequency |
Retention |
Method |
| MySQL DB |
Every 6 hours |
30 days |
mysqldump --single-transaction + gzip |
| Files (upload/) |
Daily |
14 days |
rsync incremental |
| Full backup |
Weekly |
60 days |
tar + gpg encryption |
| Server configs |
On change |
In Git |
Ansible playbooks |
Geographic distribution — S3‑compatible storage + separate server in another datacenter. Test restoration monthly — a backup never restored is just an illusion of security. Cron with notifications: if backup fails, alert immediately.
What’s Included in the Service
Our team brings 5+ years of Bitrix DevOps experience (over 50 successful projects) and certified engineers. The service provides:
- DevOps process documentation (deployment scheme, branch policy, infrastructure description)
- Configured CI/CD pipelines (GitLab CI / GitHub Actions) with working triggers
- Docker environment (
docker-compose.yml, Dockerfile, configs)
- Ansible playbooks for server reproduction
- Monitoring (Grafana dashboards, alerts in Telegram / Slack)
- Secured access with role‑based model
- Team training: two sessions on CI/CD, Docker, and deployment
- Support during implementation (two weeks after launch)
Infrastructure‑as‑code with Ansible is 5× faster than manual server configuration and eliminates human errors.
Implementation Process and Timelines
-
Audit of current state – assess infrastructure, software, processes (2–3 days).
-
Architecture design – choose stack (Docker / K8s / Ansible), agree on CI/CD policies, set up repository.
-
Environment setup – Docker for local development, staging, production servers.
-
CI/CD implementation – write pipelines, test deployment, integrate with monitoring.
-
Monitoring and alerting – install Prometheus + Grafana, configure dashboards and notifications.
-
Team training – two sessions on tool usage.
| Task |
Duration |
| Docker environment for local development |
2–3 days |
| CI/CD pipeline (GitLab CI / GitHub Actions) |
1–2 weeks |
| Staging environment |
3–5 days |
| Monitoring + alerting (Prometheus + Grafana) |
1–2 weeks |
| Centralized logging (ELK / Loki) |
1–2 weeks |
| Ansible server automation |
2–3 weeks |
| Comprehensive DevOps implementation |
4–8 weeks |
DevOps is not a project with an end date — it’s a transition from “upload via FTP and pray” to predictable processes. Each deployment is routine, each incident carries context, each new developer does docker-compose up instead of a three‑day environment setup.
Get a consultation – we’ll prepare a tailored implementation plan within 2–3 days. Order a turnkey DevOps implementation – gain stability and full control over your infrastructure.