Skip to content

Commit 3abf160

Browse files
committed
docs: expand PHP-FPM tuning section in server_tuning
Replace the two-sentence stub with real content covering: - pm modes (dynamic/static/ondemand) with trade-offs and Nextcloud guidance (ondemand not recommended; sync clients cause repeated cold starts) - Key parameters: pm.max_children, start/min/max spare servers, pm.max_requests, pm.process_idle_timeout — with the RAM-based sizing formula and how to measure actual worker RSS - Example dynamic config for 2 GB PHP RAM - Slow log setup (slowlog + request_slowlog_timeout) - Troubleshooting section: 502, 504, memory growth, cold-start lag - Cross-reference to source_installation.rst for pool/env-var detail Fixes #11591 Signed-off-by: skjnldsv <skjnldsv@protonmail.com>
1 parent 48828f5 commit 3abf160

1 file changed

Lines changed: 132 additions & 5 deletions

File tree

admin_manual/installation/server_tuning.rst

Lines changed: 132 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -139,12 +139,139 @@ HTTP/2 has `huge speed improvements <https://www.troyhunt.com/i-wanna-go-fast-ht
139139
Tune PHP-FPM
140140
------------
141141

142-
The default configuration of PHP-FPM is extremely conservative. You might notice
143-
excessive load times on the web interface or even sync issues. Each simultaneous
144-
request is handled by a separate PHP-FPM process, so even on a small installation you
145-
should allow more processes to run in parallel to handle requests.
142+
PHP-FPM is required for Nginx setups and is widely used with Apache as well. Its default
143+
configuration is extremely conservative: the default pool has ``pm.max_children = 5``, which
144+
limits Nextcloud to five simultaneous PHP requests and is a common cause of gateway timeouts,
145+
slow page loads, and sync client errors under any real load.
146146

147-
`This link <https://spot13.com/pmcalculator/>`_ can help you calculate the optimal values for your system.
147+
Process manager modes
148+
^^^^^^^^^^^^^^^^^^^^^
149+
150+
The ``pm`` directive controls how PHP-FPM manages its worker processes:
151+
152+
.. list-table::
153+
:header-rows: 1
154+
:widths: 15 85
155+
156+
* - Mode
157+
- Behaviour
158+
* - ``dynamic``
159+
- Keeps between ``pm.min_spare_servers`` and ``pm.max_spare_servers`` idle workers alive,
160+
up to a ceiling of ``pm.max_children``. Good default for most Nextcloud installations:
161+
balances RAM efficiency with burst capacity. Set ``pm.min_spare_servers`` high enough
162+
that sync-client poll bursts do not stall waiting for new processes to spawn.
163+
* - ``static``
164+
- Always keeps exactly ``pm.max_children`` processes running. Highest memory use,
165+
lowest latency. Use on dedicated servers with predictable load. Always set
166+
``pm.max_requests`` to recycle workers and prevent memory leaks.
167+
* - ``ondemand``
168+
- Spawns a worker only when a request arrives; kills idle workers after
169+
``pm.process_idle_timeout`` (default ``10s``). Lowest memory use but adds
170+
cold-start latency on every burst. Not recommended for Nextcloud: desktop and
171+
mobile clients poll every 30 seconds, repeatedly triggering cold starts.
172+
173+
Key parameters
174+
^^^^^^^^^^^^^^
175+
176+
``pm.max_children``
177+
Maximum (or fixed, under ``static``) number of simultaneous worker processes.
178+
This is the most important value to tune. If all workers are busy, new requests
179+
queue up; a full queue produces 502/504 errors.
180+
181+
Estimate it from available RAM::
182+
183+
pm.max_children = floor(available_RAM_for_PHP / average_worker_RSS)
184+
185+
Measure the average RSS of a running pool::
186+
187+
ps --no-headers -o rss -C php-fpm8.3 | awk '{sum+=$1} END {print sum/NR/1024 " MB"}'
188+
189+
A typical Nextcloud worker uses **50–100 MB** (more if Imagick or LDAP is loaded).
190+
Leave headroom for the OS, web server, database, and cache. Setting ``pm.max_children``
191+
too high causes swapping, which is worse than queuing.
192+
193+
``pm.start_servers`` *(dynamic only)*
194+
Workers started at FPM boot. Defaults to
195+
``(pm.min_spare_servers + pm.max_spare_servers) / 2`` if not set.
196+
197+
``pm.min_spare_servers`` / ``pm.max_spare_servers`` *(dynamic only)*
198+
Range of idle workers kept warm. For Nextcloud, keep ``pm.min_spare_servers``
199+
high enough to absorb a sync-client burst without spawning new processes::
200+
201+
pm.min_spare_servers = 4 # adjust upward for many connected clients
202+
pm.max_spare_servers = 16
203+
204+
``pm.max_requests``
205+
Recycle a worker after this many requests. ``0`` means never recycle.
206+
Setting a value of ``500``–``1000`` guards against slow memory growth from
207+
leaky extensions (Imagick, LDAP, SAML XML parsers). Essential under ``static``
208+
mode.
209+
210+
``pm.process_idle_timeout`` *(ondemand only)*
211+
How long an idle worker lives before being killed. Default: ``10s``.
212+
213+
Example configuration
214+
^^^^^^^^^^^^^^^^^^^^^
215+
216+
A starting point for ``dynamic`` mode on a server with 2 GB of RAM dedicated to PHP
217+
(adjust ``pm.max_children`` based on your measured worker RSS):
218+
219+
.. code-block:: ini
220+
221+
pm = dynamic
222+
pm.max_children = 30
223+
pm.start_servers = 8
224+
pm.min_spare_servers = 4
225+
pm.max_spare_servers = 16
226+
pm.max_requests = 500
227+
228+
Use the `PHP-FPM process calculator <https://spot13.com/pmcalculator/>`_ as a
229+
cross-check for your values.
230+
231+
Slow log
232+
^^^^^^^^
233+
234+
Enable the slow log to identify PHP scripts that are taking too long:
235+
236+
.. code-block:: ini
237+
238+
slowlog = /var/log/php-fpm-slow.log
239+
request_slowlog_timeout = 5s
240+
241+
Each entry records the full PHP backtrace of the slow request. This is the
242+
fastest way to find the root cause of gateway timeouts and sluggish pages.
243+
244+
Troubleshooting
245+
^^^^^^^^^^^^^^^
246+
247+
**502 Bad Gateway**
248+
All ``pm.max_children`` workers are busy. Increase ``pm.max_children`` if RAM
249+
allows. Enable the slow log to check whether a slow query is tying up workers.
250+
Also check that a ``request_terminate_timeout`` is not killing workers mid-request.
251+
252+
**504 Gateway Timeout**
253+
A worker is running but not responding within the web server's upstream timeout
254+
(nginx ``fastcgi_read_timeout``, Apache ``ProxyTimeout``). Common Nextcloud causes:
255+
large file operations, slow database queries during sync, or PROPFIND over large
256+
directory trees. Use the slow log to identify the bottleneck.
257+
258+
**Memory grows over time**
259+
Workers are leaking memory (Imagick and XML parsers are common sources).
260+
Set ``pm.max_requests = 500`` to recycle them before they grow too large.
261+
262+
**Slow first request after idle**
263+
``pm = ondemand`` or ``pm.min_spare_servers`` too low. Switch to ``pm = dynamic``
264+
and raise ``pm.min_spare_servers``.
265+
266+
After any configuration change, reload PHP-FPM — changes do not take effect until you do:
267+
268+
.. code-block:: bash
269+
270+
sudo systemctl reload php8.3-fpm # Debian/Ubuntu — adjust version as needed
271+
sudo systemctl reload php-fpm # RHEL/Fedora
272+
273+
For pool configuration details (environment variables, upload sizes, Unix socket vs TCP),
274+
see :ref:`php_fpm_tips_label` in the installation guide.
148275

149276
Enable PHP OPcache
150277
------------------

0 commit comments

Comments
 (0)