# Zabezpečení Nginx s PHP-FPM

> Bezpečnost Nginx a PHP-FPM po PHP2Shell: zkontrolujte pooly a verze, restartujte workery, nastavte hodnoty přes php_admin_value a zpevněte Nginx.

Zdroj: https://phpsos.de/cs/server/nginx-php-fpm/  
Stav: 25.10.2026  
Poskytovatel: PHP SOS, Nouzová pomoc pro PHP a bezpečnost serverů. Okamžitá pomoc přes WhatsApp: https://wa.me/491736494914?text=Dobr%C3%BD%20den%2C%20PHP%20SOS%2C%20pot%C5%99ebujeme%20pomoc%20s%20na%C5%A1%C3%ADm%20PHP%20serverem.%20Firma%3A%20%E2%80%A6%20Web%3A%20%E2%80%A6

**Stručně:** U Nginx s PHP-FPM sídlí zranitelnost z PHP2Shell v PHP-FPM, nikoli v Nginx. Zazáplatujte všechny verze PHP-FPM, každou službu FPM úplně restartujte a doložte to časy spuštění procesů. Pro dlouhodobou bezpečnost Nginx a PHP-FPM mají význam oddělené pooly, hodnoty, které nelze přepsat, a konfigurace Nginx, která nespouští nahrané soubory.

## Jak spolupracují Nginx a PHP-FPM

Nginx statické soubory obsluhuje sám a požadavky na skripty PHP předává přes FastCGI do PHP-FPM. PHP-FPM se skládá z hlavního procesu (master) a několika procesů workerů seskupených do poolů. Jeden worker zpracovává postupně mnoho požadavků.

Právě to je pro PHP2Shell podstatné. U CVE-2026-109619 může vnitřní stav požadavku po uvolnění paměti přetrvat a být využit pozdějším požadavkem ve stejném workeru. U CVE-2026-109618 může stav nedostatku paměti (out of memory) přerušit PHP uprostřed inicializace požadavku. Obě zranitelnosti jsou hodnoceny CVSS v4.0 9,2 a opraveny v PHP 8.5.12, 8.4.27, 8.3.36 a 8.2.35.

## Zkontrolovat stav: verze, pooly, procesy

Na mnoha serverech běží vedle sebe několik verzí PHP-FPM. Následující příkazy jen čtou; názvy balíčků a služeb jsou příklady pro Debian/Ubuntu a rodinu RHEL.

```bash
# Které služby FPM běží?
systemctl list-units --type=service | grep -i fpm

# Jaká verze za tím stojí? (příklad Debian/Ubuntu)
php-fpm8.3 -v
# Rodina RHEL
php-fpm -v

# Na které sockety nebo porty Nginx předává?
nginx -T 2>/dev/null | grep -E 'fastcgi_pass'

# Pooly a jejich uživatelé
grep -RhE '^\[|^user|^listen' /etc/php/*/fpm/pool.d/ 2>/dev/null
```

Porovnejte každý záznam `fastcgi_pass` s běžícím poolem. Tak uvidíte, která verze PHP obsluhuje který web. U balíčků distribucí záplatu dokládá changelog s čísly CVE, nikoli samotné číslo verze.

Častým zjištěním při takové inventuře jsou servery, na kterých se během let nainstalovalo několik verzí PHP, z nichž se skutečně používá jen jedna. Ostatní služby FPM přesto běží dál, často se standardními pooly, které naslouchají na lokálním socketu nebo portu. Zvenčí bývají zpravidla přímo nedosažitelné, ale zůstávají zbytečným rizikem a prodlužují každou nouzovou aktualizaci. Verze, které žádný web nepoužívá, vypněte a odstraňte poté, co ověříte přiřazení pomocí záznamů `fastcgi_pass`.

Stejně tak se vyplatí pohled na uživatele poolů. Pokud všechny pooly běží jako `www-data` nebo `nginx`, je oddělení mezi weby jen na papíře. Kdo převezme jeden web, může pak číst soubory všech ostatních, například konfigurační soubory s hesly k databázi. Vlastní systémoví uživatelé pro každý pool a vhodná oprávnění k souborům tu vytvoří skutečnou hranici. Není to náprava pro PHP2Shell, ale výrazně to omezuje možné škody úspěšného útoku.

## Nasadit záplatu a obnovit všechny workery

Po aktualizaci balíčků restartujte každou službu PHP-FPM. Reload sice workery nahradí, úplný restart ale obnoví i hlavní proces a po bezpečnostních aktualizacích je to bezpečná cesta.

```bash
# Příklad Debian/Ubuntu, pro každou nainstalovanou verzi
systemctl restart php8.3-fpm
# Rodina RHEL
systemctl restart php-fpm

# Kontrola: čas spuštění masteru a workerů
ps -eo pid,lstart,cmd | grep -E 'php-fpm' | grep -v grep
```

Každý proces musí být spuštěn po aktualizaci. Podrobně je to popsáno na stránce [Restart PHP-FPM a všech workerů](https://phpsos.de/cs/php2shell/php-fpm-neustart/).

> **Důležité:**
> Záplata neodstraní škodlivý software zavlečený dříve. Uchovejte přístupové a chybové logy Nginx od 20. 10. 2026 a zkontrolujte weby, zda nenesou stopy.

## Nastavit přechodné hodnoty v poolu

Dokud verze není zazáplatována, doporučuje php.net přechodná opatření. Neposkytují úplnou ochranu. V PHP-FPM nastavíte hodnoty pomocí `php_admin_value`, resp. `php_admin_flag` v poolu, aplikace je pak nemohou přes `ini_set()` přepsat.

```ini
; Příklad: /etc/php/8.3/fpm/pool.d/website.conf
php_admin_flag[session.upload_progress.enabled] = off
php_admin_value[post_max_size] = 32M
php_admin_value[upload_max_filesize] = 24M
```

Bez funkce nahrávání souborů uvádí php.net `post_max_size = 8M`. Na PHP 8.5 přibývá `fatal_error_backtraces=0`. Pro upozornění k `memory_limit=-1` potřebujete limit paměti na úrovni cgroup, například pomocí `MemoryMax` v doplňku systemd pro službu FPM. V Nginx přizpůsobte `client_max_body_size` nové hodnotě `post_max_size`, aby uživatelé dostávali srozumitelné chybové hlášky. Poté FPM restartujte.

## Trvale zlepšit bezpečnost Nginx a PHP-FPM

Nad rámec akutního případu pomáhá několik základních pravidel, která omezí škody při budoucích zranitelnostech:

- **Jeden pool pro každý web** s vlastním systémovým uživatelem, vlastním socketem a vlastní hranicí `open_basedir`. Více na stránce [open_basedir a izolace pro každý web](https://phpsos.de/cs/ratgeber/open-basedir/).
- **Oprávnění socketu** nastavit tak, aby se mohl připojit jen Nginx, žádné porty FPM neotevírat navenek.
- **Spouštět jen existující skripty:** V location pro PHP nastavit `try_files $uri =404;`, aby Nginx nepředával PHP cesty, které neexistují.
- **Nespouštět nahrané soubory:** V adresářích pro nahrávání zakázat spouštění PHP. Pokyny najdete na stránce [Bezpečné nahrávání souborů](https://phpsos.de/cs/ratgeber/datei-upload-sicher/).
- **Chránit stavové stránky:** `pm.status_path` a `ping.path` zpřístupnit jen interně.

```nginx
# Příklad: žádné spouštění PHP v adresáři pro nahrávání
location ~* ^/uploads/.*\.php$ {
    deny all;
}
```

Každou změnu zkontrolujte pomocí `nginx -t`, než Nginx znovu načtete. Zaznamenejte si také, jaké pooly, verze a zvláštní pravidla na serveru existují. Tato krátká dokumentace při příští kritické zranitelnosti ušetří cenný čas, protože nikdo nemusí nejprve hledat, který web patří ke kterému poolu.

## Jak konkrétně pomáhá PHP SOS?

- Přiřadíme každý web jeho poolu a verzi PHP a zkontrolujeme skutečný stav balíčků.
- Zazáplatujeme, restartujeme všechny služby FPM a časy spuštění procesů zdokumentujeme jako doklad.
- Do záplaty nastavíme přechodné hodnoty pro každý pool a omezíme paměť přes cgroup.
- V rámci [zpevnění serveru](https://phpsos.de/cs/leistungen/server-haertung/) čistě oddělíme pooly, oprávnění a adresáře pro nahrávání.
- Při podezření na průnik převezmeme [reakci na incidenty](https://phpsos.de/cs/leistungen/incident-response/).


## Časté dotazy

**Stačí po aktualizaci systemctl reload pro PHP-FPM?**  
Reload obnoví workery, hlavní proces (master) ale může starý kód zachovat. Po bezpečnostní aktualizaci je bezpečnou cestou úplný restart služby. Poté zkontrolujte čas spuštění masteru i workerů.

**Musí se Nginx po aktualizaci PHP restartovat?**  
Samotný Nginx PHP neobsahuje a kvůli záplatě PHP se restartovat nemusí. Restartovat se musí všechny služby PHP-FPM. Pokud při tom měníte konfiguraci Nginx, před opětovným načtením ji zkontrolujte pomocí nginx -t.

**Proč vlastní pooly pro každý web?**  
Každý pool běží s vlastním uživatelem a vlastními hranicemi. Pokud je jeden web kompromitován, útočník se bez dalšího nedostane k souborům ostatních. Přechodné hodnoty lze navíc nastavit cíleně pro každý pool.

**Je pm.max_requests ochranou proti PHP2Shell?**  
Ne, záplatu nenahrazuje. Hodnota omezuje, kolik požadavků worker zpracuje, než je nahrazen. To může zkrátit životnost stavů v procesu, ale není to náprava uvedená php.net.

## Zdroje

- [php.net: bezpečnostní oznámení](https://www.php.net/)
- [PHP 8 ChangeLog](https://www.php.net/ChangeLog-8.php)
- [OWASP Cheat Sheets](https://cheatsheetseries.owasp.org/)
- [BSI](https://www.bsi.bund.de/)
