# Geheugengrenzen instellen met systemd en cgroups

> systemd MemoryMax voor PHP-FPM: geheugengrens via cgroup instellen zoals php.net bij PHP2Shell adviseert, met MemoryHigh, OOMPolicy en controleopdrachten.

Bron: https://phpsos.de/nl/blog/speichergrenzen-systemd-cgroups/  
Stand: 25-10-2026  
Aanbieder: PHP SOS, PHP-noodhulp en serverbeveiliging. Directe hulp via WhatsApp: https://wa.me/491736494914?text=Hallo%20PHP%20SOS%2C%20wij%20hebben%20hulp%20nodig%20met%20onze%20PHP-server.%20Bedrijf%3A%20%E2%80%A6%20Website%3A%20%E2%80%A6

**Kort gezegd:** Voor de PHP2Shell-overbruggingsmaatregel `memory_limit=-1` heeft PHP-FPM een geheugengrens buiten PHP nodig. Onder systemd stelt u die in met `MemoryHigh=` als rem en `MemoryMax=` als harde bovengrens in een aanvullend bestand voor de FPM-service. `ulimit`, `LimitAS=` of `LimitDATA=` zijn daarvoor volgens php.net ongeschikt. Controleer bovendien `OOMPolicy=`, zodat één enkele worker niet de hele service beëindigt.

## Een advies dat eerst verbaast

Onder de overbruggingsmaatregelen die php.net op 21 oktober 2026 over PHP2Shell heeft gepubliceerd, staat er één waar veel beheerders van opkeken: `memory_limit=-1`, dus geen geheugengrens in PHP zelf. Jarenlang gold het tegendeel als goede praktijk.

Een verband met de beschrijving van de kwetsbaarheid ligt voor de hand. Bij CVE-2026-109618 kan een out-of-memory-toestand PHP onderbreken terwijl verzoekgegevens maar deels zijn geïnitialiseerd. De overbruggingsmaatregel verplaatst de geheugengrens uit PHP naar het besturingssysteem. php.net koppelt haar uitdrukkelijk aan twee voorwaarden: de waarde moet tegen overschrijven zijn vergrendeld en de grens moet via container of cgroup komen, niet via `RLIMIT_AS` of `RLIMIT_DATA`.

Wie alleen de eerste helft doorvoert, heeft een server zonder enige geheugengrens. Dit artikel toont de tweede helft. Ook samen blijft de maatregel een overbrugging: verholpen is de kwetsbaarheid pas met PHP 8.5.12, 8.4.27, 8.3.36, 8.2.35 of een bevestigde backport.

## cgroups in twee zinnen uitgelegd

Control groups, kortweg cgroups, zijn een functie van de Linux-kernel die processen groepeert en hun resources begrenst. systemd maakt voor elke service automatisch een eigen cgroup aan en alle processen van de service, bij de FPM-service dus master en alle workers, horen erbij.

De geheugenopties van systemd stellen waarden van de cgroup-v2-geheugencontroller in. Of uw systeem cgroup v2 gebruikt, toont een korte opdracht:

```bash
# "cgroup2fs" betekent: cgroup v2 is actief
stat -fc %T /sys/fs/cgroup/
```

Actuele versies van de gangbare distributies gebruiken standaard cgroup v2. Toont de opdracht iets anders, zoek dat dan vóór de omschakeling uit, want de systemd-documentatie beschrijft de oude v1-opties als verouderd.

## systemd MemoryMax voor PHP-FPM instellen

De grens komt in een aanvullend bestand, een zogeheten drop-in. Zo blijft het unitbestand van het pakket ongewijzigd en overschrijft een update uw instelling niet. Servicenamen verschillen per distributie; het voorbeeld gebruikt Debian en Ubuntu met PHP 8.3.

```ini
# Opent een editor voor de drop-in: sudo systemctl edit php8.3-fpm
# Resultaat: /etc/systemd/system/php8.3-fpm.service.d/override.conf
[Service]
MemoryAccounting=yes
MemoryHigh=1536M
MemoryMax=2G
MemorySwapMax=0
OOMPolicy=continue
```

De opties in één oogopslag, volgens de documentatie van systemd:

| Optie | Werking | Aanwijzing voor PHP-FPM |
|---|---|---|
| `MemoryHigh=` | Remgrens: processen worden sterk afgeremd, geheugen wordt teruggehaald | de eigenlijke stuurgrootheid, iets onder `MemoryMax` |
| `MemoryMax=` | absolute grens: is ze niet te houden, dan wordt de OOM-killer in de service actief | laatste verdedigingslinie |
| `MemorySwapMax=` | Grens voor uitwisselen naar schijf | `0` voorkomt dat de service in plaats daarvan naar swap uitwijkt |
| `OOMPolicy=` | Gedrag na een OOM-gebeurtenis: `continue`, `stop` of `kill` | `continue` laat de overige workers doorlopen |
| `LimitAS=`, `LimitDATA=` | rlimits per proces | volgens php.net voor deze maatregel ongeschikt |

`OOMPolicy=` verdient bijzondere aandacht. Bij `stop` of `kill` beëindigt systemd na een OOM-gebeurtenis de hele service en vallen alle websites van deze FPM-service uit. Welke waarde zonder eigen opgave geldt, bepaalt de systeemstandaard `DefaultOOMPolicy=`. Controleer de werkzame waarde daarom in plaats van haar aan te nemen.

Herstart daarna de service en vergrendel in de pool `memory_limit`:

```bash
sudo systemctl restart php8.3-fpm
systemctl show php8.3-fpm -p MemoryHigh -p MemoryMax -p MemorySwapMax -p OOMPolicy -p MemoryCurrent
```

```ini
; Poolbestand, bijv. /etc/php/8.3/fpm/pool.d/seite1.conf
php_admin_value[memory_limit] = -1
```

Hoe het vergrendelen werkt, beschrijft [php_admin_value: instellingen tegen overschrijven vergrendelen](https://phpsos.de/nl/blog/php-admin-value-sperren/).

## De juiste waarde vinden

Een te krappe grens veroorzaakt afbrekingen in normaal bedrijf, een te ruime beschermt nauwelijks. Uitgangspunt is het werkelijke verbruik.

1. Het actuele geheugengebruik van alle FPM-processen enkele dagen observeren, ook bij belastingspieken.
2. De typische behoefte van een worker vaststellen en vermenigvuldigen met `pm.max_children` van alle pools van de service.
3. Een toeslag inplannen voor het masterproces, OPcache en pieken.
4. `MemoryHigh=` net boven de gemeten piekwaarde instellen, `MemoryMax=` met wat marge daarboven.
5. Waarden na een week bijstellen aan de hand van de metingen en OOM-gebeurtenissen.

```bash
# Geheugen van alle PHP-FPM-processen in MB (Resident Set Size)
ps -C php-fpm8.3 -o rss= | awk '{s+=$1} END {printf "%.0f MB\n", s/1024}'
# Doorlopend overzicht van alle cgroups gesorteerd op geheugen
systemd-cgtop -m
```

De waarde van `memory_limit` vóór de omschakeling moet u noteren. Na de update kunt u terugkeren naar een vaste grens in PHP; hoe u die zinvol kiest, staat onder [memory_limit juist instellen](https://phpsos.de/nl/blog/memory-limit-richtig-setzen/).

## Bewaken: wanneer de grens ingrijpt

Een geheugengrens waarvan niemand merkt dat ze wordt geraakt, is een stille foutenbron. De kernel telt OOM-gebeurtenissen per cgroup en systemd en het kernellogboek noteren ze.

```bash
# OOM-teller van de cgroup van de service (pad bij cgroup v2)
cat /sys/fs/cgroup/system.slice/php8.3-fpm.service/memory.events
# Meldingen van de OOM-killer in het kernellogboek
journalctl -k --since "-1 day" | grep -i "out of memory"
```

Stijgt de teller `oom_kill`, dan beëindigt de kernel workers. Dat kan wijzen op een te krappe grens, op een foutieve applicatie of op ongebruikelijke verzoeken. In de huidige situatie loont het om zulke gebeurtenissen af te stemmen op de toegangslogs van hetzelfde moment.

> **Belangrijk:**
> De geheugengrens is een overbruggingsmaatregel en vervangt de PHP-update niet. Plan de update parallel en herstart daarna alle PHP-processen. Alle overbruggingsmaatregelen in één oogopslag staan onder [Noodmaatregelen als u nog niet kunt patchen](https://phpsos.de/nl/php2shell/sofortmassnahmen-ohne-patch/).

Wat er binnenin PHP bij geheugentekort gebeurt, legt [memory_limit en out-of-memory](https://phpsos.de/nl/php/out-of-memory/) uit. Bij Apache met mod_php geldt dezelfde techniek voor de Apache-service, al deelt PHP de grens dan met de webserver zelf.

## Conclusie: de tweede helft niet vergeten

`memory_limit=-1` is alleen samen met een buitenste grens een verdedigbare overbruggingsmaatregel. systemd maakt die grens met een paar regels mogelijk: `MemoryHigh` als rem, `MemoryMax` als harde bovengrens, `MemorySwapMax` tegen het uitwijken naar swap en een bewust gekozen `OOMPolicy`. Meet vooraf, observeer achteraf en houd in de gaten dat alle pools van een service de grens delen.

Vooral echter: plan het einde van de maatregel. Na de update naar een verholpen PHP-versie keert u terug naar een vaste `memory_limit`. De cgroup-grens kunt u als extra beveiliging tegen uitdijende processen houden.

## Hoe helpt PHP SOS concreet?

- **Meten:** wij leggen de geheugenbehoefte van uw PHP-services vast en leiden daaruit passende grenzen af.
- **Doorvoeren:** wij plaatsen drop-ins met `MemoryHigh`, `MemoryMax` en een passende `OOMPolicy`, vergrendelen `memory_limit` in de pool en herstarten de services gecontroleerd.
- **Observeren:** OOM-gebeurtenissen nemen wij op in de bewaking en wij bepalen de waarden bij.
- **Naar de patch leiden:** via de [PHP-patchservice](https://phpsos.de/nl/leistungen/php-patch-service/) voeren wij de update door en nemen wij de overbruggingswaarden daarna ordelijk terug.


## Veelgestelde vragen

**Waarom moet memory_limit op -1 staan? Is dat niet gevaarlijk?**  
Op zichzelf wel. php.net adviseert memory_limit=-1 als overbruggingsmaatregel uitdrukkelijk samen met een geheugengrens via container of cgroup. De begrenzing verhuist daarmee uit PHP naar het besturingssysteem. Zonder deze buitenste grens moet u de waarde niet instellen.

**Kan ik in plaats daarvan ulimit of LimitAS= gebruiken?**  
Nee. php.net raadt RLIMIT_AS en RLIMIT_DATA uitdrukkelijk af, en precies deze grenzen stellen ulimit -v, LimitAS= en LimitDATA= in. De systemd-documentatie wijst er bovendien op dat LimitAS= de adresruimte begrenst, niet het geheugengebruik.

**Wat gebeurt er als PHP-FPM de grens bereikt?**  
Bij MemoryHigh remt de kernel de processen af en haalt geheugen terug. Bij MemoryMax wordt binnen de service de OOM-killer actief en beëindigt een proces, meestal een grote worker. Of daarna de hele service stopt, regelt OOMPolicy=.

**Geldt de grens voor elke pool afzonderlijk?**  
Nee. Alle pools van één FPM-service delen één cgroup en dus één gemeenschappelijke grens. Gescheiden grenzen per website vereisen gescheiden FPM-services of containers.

**Hoe stel ik de grens in bij Docker of Kubernetes?**  
Via de geheugenbegrenzing van de container, bijvoorbeeld de optie --memory bij docker run of resources.limits.memory in Kubernetes. Beide gebruiken eveneens cgroups. Het uitgangspunt blijft gelijk: grens buiten PHP, memory_limit in PHP vergrendeld.

## Bronnen

- [systemd.resource-control (MemoryMax, MemoryHigh)](https://www.freedesktop.org/software/systemd/man/latest/systemd.resource-control.html)
- [systemd.service (OOMPolicy)](https://www.freedesktop.org/software/systemd/man/latest/systemd.service.html)
- [php.net: beveiligingsmeldingen](https://www.php.net/)
- [PHP-handleiding: memory_limit](https://www.php.net/manual/en/ini.core.php)
