Skip to content

Commit 1a3914a

Browse files
authored
Merge pull request #14994 from nextcloud/backport/14923/stable34
[stable34] docs: expand PHP-FPM tuning section with real guidance
2 parents 9af73d4 + fa8cf49 commit 1a3914a

1 file changed

Lines changed: 128 additions & 5 deletions

File tree

admin_manual/installation/server_tuning.rst

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

149272
Enable PHP OPcache
150273
------------------

0 commit comments

Comments
 (0)