# Nginx veilig configureren voor PHP

> Nginx veilig configureren voor PHP: alleen echte scripts aan PHP-FPM doorgeven, front controller vrijgeven, dotfiles blokkeren en groottegrenzen passend instellen.

Bron: https://phpsos.de/nl/blog/nginx-fuer-php-absichern/  
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:** Om Nginx veilig voor PHP te configureren, geeft u alleen scripts aan PHP-FPM door die werkelijk bestaan, bij front-controllerapplicaties zelfs alleen de `index.php`. Daarbij komen geblokkeerde dotfiles zoals `.git` en `.env`, een standaardserver voor onbekende hostnamen, passende groottegrenzen en `security.limit_extensions = .php` in de pool. Dat beschermt niet tegen kwetsbaarheden in PHP zelf, maar beperkt wat na een fout uitvoerbaar is.

## De gevaarlijkste regels staan in de PHP-location

Sinds PHP2Shell controleren veel teams hun PHP-FPM-versies en pools, zoals de pagina [Nginx met PHP-FPM beveiligen](https://phpsos.de/nl/server/nginx-php-fpm/) beschrijft, en herstarten na de update [alle workers](https://phpsos.de/nl/php2shell/php-fpm-neustart/). Een tweede blik gaat naar de Nginx-configuratie zelf. Daar wordt bepaald welke bestanden als PHP worden uitgevoerd.

In veel configuraties staat een blok dat elk verzoek naar `.php` aan PHP-FPM doorgeeft, waar het bestand ook staat. Belandt een ingebracht PHP-bestand in een uploadmap, dan voert de server het uit. Van een bestandsfout wordt zo een achterdeur.

Dit artikel richt zich op de Nginx-kant: welke directieven tellen, hoe de volgorde van de location-blokken werkt en hoe u het resultaat test.

## Hoe Nginx beslist welk blok geldt

Wie Nginx veilig voor PHP wil configureren, moet de selectie van location-blokken kennen. Volgens de Nginx-documentatie verloopt die zo:

1. Een exacte treffer met `location =` beëindigt de zoektocht meteen.
2. Onder de prefix-locations wordt de langste passende onthouden. Draagt ze `^~`, dan worden geen reguliere expressies meer gecontroleerd.
3. Anders worden reguliere expressies (`~`, `~*`) gecontroleerd in de volgorde van het configuratiebestand; de eerste treffer wint.
4. Geeft geen reguliere expressie een treffer, dan geldt de onthouden prefix-location.

Daaruit volgen twee praktische regels. Een blokkade voor PHP in uploadmappen moet ofwel als `^~`-prefix worden aangelegd, ofwel als reguliere expressie vóór het algemene PHP-blok staan. En een gewone prefix-location als `location /uploads/` beschermt niet, omdat de reguliere expressie voor `.php` haar overrulet.

## Een veilige basisconfiguratie

Het volgende voorbeeld toont een serverblok voor een applicatie met front controller, zoals gebruikelijk bij Laravel, Symfony, Shopware 6 of veel eigen ontwikkelingen. Paden, socket en certificaten past u aan.

```nginx
server {
    listen 443 ssl;
    server_name www.example.de;
    root /var/www/seite1/public;
    index index.php;

    ssl_certificate     /etc/ssl/seite1/fullchain.pem;
    ssl_certificate_key /etc/ssl/seite1/privkey.pem;

    server_tokens off;
    client_max_body_size 32m;

    # Let's Encrypt en andere bekende paden toestaan
    location ^~ /.well-known/ {
        try_files $uri =404;
    }

    # Verborgen bestanden en mappen blokkeren (.git, .env, .htaccess)
    location ~ /\. {
        deny all;
    }

    location / {
        try_files $uri $uri/ /index.php$is_args$args;
    }

    # Alleen de front controller wordt aan PHP-FPM doorgegeven
    location = /index.php {
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
        fastcgi_param DOCUMENT_ROOT $realpath_root;
        fastcgi_hide_header X-Powered-By;
        fastcgi_pass unix:/run/php/seite1.sock;
    }

    # Elk ander PHP-bestand wordt niet uitgevoerd
    location ~ \.php$ {
        return 404;
    }
}
```

`$realpath_root` lost symbolische links op. Dat is bij deployments met een wisselende symlink naar de actuele release belangrijk, zodat PHP-FPM en OPcache het juiste pad zien. Let bovendien op: volgens de Nginx-documentatie worden `fastcgi_param`-directieven alleen van hogere niveaus geërfd als er op het huidige niveau geen eigen staan. Daarom hoort `include fastcgi_params;` in hetzelfde blok.

Klassieke CMS'en als WordPress, TYPO3 of Contao hebben meerdere ingangspunten. Daar vervangt u het front-controllerblok door een algemene PHP-location die alleen bestaande bestanden doorgeeft (`try_files $uri =404;`) en blokkeert u de uitvoering in alle beschrijfbare mappen. Hoe dat lukt, staat onder [PHP-uitvoering in uploadmappen verbieden](https://phpsos.de/nl/blog/php-in-uploads-verbieten/).

## De tweede beveiliging in PHP-FPM

Nginx beslist wat wordt doorgegeven, PHP-FPM beslist wat het uitvoert. Volgens de PHP-handleiding voert PHP-FPM standaard bestanden met `.php` en `.phar` uit en adviseert het zelf dat te beperken tot `.php`. Dat vangt configuratiefouten in de webserver op.

```ini
; in de pool, bijv. /etc/php/8.3/fpm/pool.d/seite1.conf
security.limit_extensions = .php
listen = /run/php/seite1.sock
listen.owner = www-data
listen.group = www-data
listen.mode = 0660
```

De socket mag alleen voor Nginx bereikbaar zijn. FPM-poorten op het netwerk, zoals `9000`, horen niet naar buiten te worden geopend. Hoe de server in totaal alleen de noodzakelijke poorten toont, beschrijft [Firewall voor webservers: alleen noodzakelijke poorten openen](https://phpsos.de/nl/blog/firewall-fuer-webserver/).

## Onbekende hostnamen en verdere stelschroeven

Zonder eigen standaardserver beantwoordt Nginx verzoeken naar onbekende hostnamen met het eerste passende serverblok. Geautomatiseerde scans die alleen het IP-adres aanspreken, belanden dan rechtstreeks in uw applicatie. Een eigen standaardserver beëindigt zulke verzoeken zonder antwoord.

```nginx
server {
    listen 80 default_server;
    listen 443 ssl default_server;
    server_name _;
    ssl_reject_handshake on;
    return 444;
}
```

Verdere punten die zich hebben bewezen:

| Stelschroef | Aanbeveling | Doel |
|---|---|---|
| `server_tokens` | `off` | geen versienummer in headers en foutpagina's |
| `client_max_body_size` | passend bij `post_max_size` | grote verzoeken vroeg weigeren |
| `autoindex` | uit (standaard) | geen maplijsten |
| `fastcgi_hide_header` | `X-Powered-By` | geen PHP-versie naar buiten |
| Statuspagina's | `pm.status_path` alleen intern | geen bedrijfsgegevens openbaar |
| Back-upbestanden | `.sql`, `.zip`, `.bak` in de webroot blokkeren of verwijderen | geen download van databases |

Meer over versiegegevens staat in het artikel [expose_php en Server-header](https://phpsos.de/nl/blog/expose-php-versionsangaben/).

Een andere stelschroef betreft de toegestane HTTP-methoden. De meeste websites hebben alleen GET, HEAD en POST nodig. Met `limit_except` kunnen andere methoden in een location worden geweigerd; volgens de Nginx-documentatie staat de vrijgave van GET automatisch ook HEAD toe. Controleer vooraf of interfaces van uw applicatie bijvoorbeeld PUT of DELETE gebruiken, want REST-API's doen dat vaak.

## Testen voordat u opnieuw laadt

Elke wijziging controleert u eerst met `nginx -t` en pas daarna laadt u Nginx opnieuw. Vervolgens test u het gedrag van buitenaf met normale verzoeken naar uw eigen domein:

```bash
sudo nginx -t && sudo systemctl reload nginx
# Verwacht: 403 of 404
curl -s -o /dev/null -w "%{http_code}\n" https://www.example.de/.git/HEAD
curl -s -o /dev/null -w "%{http_code}\n" https://www.example.de/.env
# Verwacht: 404, omdat alleen de front controller wordt uitgevoerd
curl -s -o /dev/null -w "%{http_code}\n" https://www.example.de/info.php
# Welke blokken geven door aan PHP-FPM?
sudo nginx -T 2>/dev/null | grep -nE "location|fastcgi_pass"
```

Bewaar vóór elke grotere wijziging de volledige uitvoer van `nginx -T` met datum. Ze bevat de gehele werkzame configuratie inclusief alle ingevoegde bestanden. Gaat er na een wijziging iets mis, dan toont de vergelijking meteen wat er verschilt. Bij de volgende kritieke kwetsbaarheid hebt u daarmee bovendien een betrouwbare basis voor de inventarisatie, zonder eerst bestanden bijeen te hoeven zoeken.

> **Tip:**
> Wijzig de configuratie eerst in een testomgeving of op een kopie van het serverblok. Een vergeten ingangspunt, bijvoorbeeld een betaalcallback, valt anders pas op als bestellingen uitblijven.

## Hoe helpt PHP SOS concreet?

- **Configuratie lezen:** wij analyseren de volledige Nginx-configuratie met `nginx -T` en koppelen elke PHP-overdracht aan haar website en pool.
- **Ingangspunten vastleggen:** samen met uw ontwikkelaars bepalen wij welke scripts moeten worden uitgevoerd en blokkeren de rest.
- **Doorvoeren en testen:** wij passen serverblokken en pools aan, controleren met `nginx -t` en testen formulieren, betaalroutes en uploads.
- **Blijvend beveiligen:** de configuratie wordt onderdeel van onze [serverhardening](https://phpsos.de/nl/leistungen/server-haertung/) en van de documentatie van uw server.


## Veelgestelde vragen

**Moet Nginx na een PHP-update worden herstart?**  
Voor de PHP-patch niet, want Nginx bevat geen PHP. Herstarten moeten alle PHP-FPM-services. Wijzigt u daarbij ook de Nginx-configuratie, controleer haar dan eerst met nginx -t en laad Nginx daarna opnieuw.

**Waarom alleen index.php aan PHP doorgeven?**  
Veel moderne applicaties hebben één enkel ingangspunt, de front controller. Wordt alleen dit bestand aan PHP-FPM doorgegeven, dan kan een ingebracht PHP-bestand elders niet via de browser worden uitgevoerd. Bij systemen met veel ingangspunten is dit patroon niet mogelijk.

**Wat levert security.limit_extensions in PHP-FPM op?**  
De instelling bepaalt welke bestandsextensies PHP-FPM als script uitvoert. Volgens de PHP-handleiding is de standaard .php .phar; aanbevolen wordt te beperken tot .php. Dat vangt fouten in de webserverconfiguratie op, maar vervangt haar niet.

**Zijn Nginx-regels een bescherming tegen PHP2Shell?**  
Nee. PHP2Shell zit in de PHP-interpreter en wordt alleen gesloten door de update naar een verholpen versie en de herstart van alle workers. Een veilige Nginx-configuratie verkleint het aanvalsoppervlak en beperkt de schade na een inbraak.

## Bronnen

- [Nginx: ngx_http_core_module](https://nginx.org/en/docs/http/ngx_http_core_module.html)
- [Nginx: ngx_http_fastcgi_module](https://nginx.org/en/docs/http/ngx_http_fastcgi_module.html)
- [PHP-handleiding: FPM-configuratie](https://www.php.net/manual/en/install.fpm.configuration.php)
- [OWASP Cheat Sheets](https://cheatsheetseries.owasp.org/)
