Module 7 · 7.2
Een webserver met nginx
Module 7: Domein, webserver en https · Leestijd: 12 minuten
Leerdoel: Na deze les kun je nginx installeren, een website en een reverse proxy inrichten met een server block, een configuratie veilig testen en herladen, en de rechten van je webroot goed zetten.
Kernbegrippen: nginx, server block, sites-available en sites-enabled, conf.d, listen, server_name, root, index, try_files, default server, nginx -t, reload, reverse proxy, proxy_pass, Host, X-Forwarded-For, X-Forwarded-Proto, webroot, PHP-FPM
Wat een webserver doet
Een webserver luistert op poort 80 (http) en 443 (https), neemt verzoeken van browsers aan en stuurt iets terug: een bestand van schijf (een statische site), of het antwoord van een programma dat erachter draait (PHP, een Node.js-app, een container). In dat tweede geval heet de webserver een reverse proxy: hij staat vooraan, regelt https, en geeft het verzoek door aan de applicatie die alleen op 127.0.0.1 luistert.
Op Linux zijn nginx en Apache de bekendste webservers, en Caddy (les 7.4) is een modern alternatief dat certificaten zelf regelt. Deze les gebruikt nginx: hij zit in elke distributie, is zuinig met geheugen en is de standaard in veel handleidingen.
Installeren en de eerste blik
anna@web1:~$ sudo apt install nginx
anna@web1:~$ systemctl status nginx
anna@web1:~$ curl -I http://localhost
HTTP/1.1 200 OK
Server: nginx/1.26.3
Content-Type: text/html(Het versienummer is een voorbeeld.) Vergeet de firewall niet: poort 80 en 443 moeten open (les 5.2). Ga je nu naar http://192.0.2.10, dan zie je de welkomstpagina van nginx.
De configuratie staat in /etc/nginx/:
| Pad | Wat |
|---|---|
nginx.conf | hoofdbestand; laat je meestal met rust |
sites-available/ | één bestand per site (Debian en Ubuntu) |
sites-enabled/ | koppelingen (symlinks) naar de sites die aan staan |
conf.d/*.conf | losse instellingen die altijd geladen worden |
snippets/ | stukjes die je in meer sites hergebruikt |
sites-available en sites-enabled zijn een gewoonte van Debian en Ubuntu: zo zet je een site aan of uit door een koppeling te maken of weg te halen, zonder het bestand te verwijderen.
Een eerste site
Maak een map voor de site en een testpagina:
anna@web1:~$ sudo mkdir -p /var/www/example.com
anna@web1:~$ echo '<h1>Het werkt</h1>' | sudo tee /var/www/example.com/index.htmlMaak dan een server block: de beschrijving van één site.
# /etc/nginx/sites-available/example.com
server {
listen 80;
listen [::]:80;
server_name example.com www.example.com;
root /var/www/example.com;
index index.html;
location / {
try_files $uri $uri/ =404;
}
access_log /var/log/nginx/example.com.access.log;
error_log /var/log/nginx/example.com.error.log;
}Lees het zo:
listen 80;enlisten [::]:80;laten nginx luisteren op IPv4 én IPv6. Vergeet je de tweede regel, dan werkt je AAAA-record niet (les 7.1).server_namezegt voor welke namen dit blok geldt. nginx kijkt bij elk verzoek naar de naam die de browser vraagt (de Host-kop) en kiest het blok dat past.rootis de map met bestanden,indexhet bestand dat getoond wordt bij een map.try_filesprobeert het gevraagde bestand, dan een map, en geeft anders een 404. Zonder zo'n regel kan een verkeerde configuratie meer tonen dan je wilt.- Eigen logbestanden per site maken zoeken veel makkelijker (les 6.2).
Zet de site aan, haal de standaardsite weg, test en herlaad:
anna@web1:~$ sudo ln -s /etc/nginx/sites-available/example.com /etc/nginx/sites-enabled/
anna@web1:~$ sudo rm /etc/nginx/sites-enabled/default
anna@web1:~$ sudo nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
anna@web1:~$ sudo systemctl reload nginx
anna@web1:~$ curl -I http://example.com
HTTP/1.1 200 OKMaak van nginx -t vóór elke reload een vaste gewoonte. Bij een fout vertelt het je welk bestand en welke regel, en je draaiende site blijft ongemoeid. Herstart je zonder te testen, dan start nginx met een fout niet meer en liggen al je sites plat (les 6.1).
De default server: wat krijgt een onbekende naam?
Wat gebeurt er als iemand je server opvraagt met een naam die in geen enkel server_name staat, of gewoon met het IP-adres? Dan kiest nginx de default server: het blok met default_server achter listen, of anders het eerste blok dat het tegenkwam. Zonder nadenken is dat dus een van je echte sites.
Netter is een apart blok dat zulke verzoeken afwijst:
# /etc/nginx/sites-available/000-default
server {
listen 80 default_server;
listen [::]:80 default_server;
server_name _;
return 444;
}444 is een bijzondere code van nginx: de verbinding wordt gesloten zonder antwoord. Scanners die IP-adressen aflopen, krijgen zo niets te zien. Voor https (poort 443) werkt een default server iets anders, omdat er een certificaat bij hoort; daar kom je in les 7.3 op terug.
nginx als reverse proxy
Draait er een applicatie op 127.0.0.1:3000 (les 6.3) of een container op 127.0.0.1:3001 (les 9.3), dan zet nginx die naar buiten:
server {
listen 80;
listen [::]:80;
server_name app.example.com;
location / {
proxy_pass http://127.0.0.1:3000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}De vier proxy_set_header-regels zijn belangrijk. Zonder Host weet de applicatie niet onder welke naam hij bezocht wordt. Zonder X-Forwarded-For ziet de applicatie elk bezoek komen van 127.0.0.1 (de proxy) in plaats van het echte adres van de bezoeker. Zonder X-Forwarded-Proto denkt de applicatie dat alles via http gaat, en maakt hij soms links of cookies voor http, terwijl je site via https draait. Veel applicaties hebben een instelling om deze kopregels te vertrouwen ("trusted proxy"); zet daar alleen 127.0.0.1 in, anders kan elke bezoeker een vals adres meesturen.
Applicaties die websockets gebruiken (live-updates, zoals Uptime Kuma) hebben nog twee regels nodig: proxy_http_version 1.1; en het doorgeven van Upgrade en Connection. De documentatie van de applicatie zegt meestal precies welke.
Rechten van de webroot
nginx draait zijn werkprocessen op Debian en Ubuntu als de gebruiker www-data. Die moet je bestanden kunnen lezen, maar hoort ze niet te kunnen schrijven. Een goede indeling (les 3.1):
anna@web1:~$ sudo chown -R anna:www-data /var/www/example.com
anna@web1:~$ sudo find /var/www/example.com -type d -exec chmod 750 {} \;
anna@web1:~$ sudo find /var/www/example.com -type f -exec chmod 640 {} \;Jij (anna) beheert de bestanden, de groep www-data mag lezen, de rest niets. Moet de site ergens schrijven, zoals een map voor uploads, geef dan alleen die map schrijfrechten voor www-data. Nooit chmod 777 (les 10.2). Krijg je een 403 Forbidden, kijk dan in het foutlogboek van de site: daar staat permission denied met het pad.
Een paar andere gewoonten:
- Geen geheimen in de webroot. Back-ups (
site.zip),.env-bestanden en.git-mappen horen er niet in; worden ze toch per ongeluk neergezet, dan zijn ze op te vragen. Een extra vangnet:location ~ /\. { deny all; }blokkeert alle bestanden die met een punt beginnen (behalve wat je expliciet toestaat, zoals/.well-known/, zie les 7.3 en 7.4). - Versie verbergen.
server_tokens off;innginx.confhaalt het versienummer uit deServer-kop en foutpagina's. Dat is geen echte beveiliging, maar het geeft scanners minder informatie.
PHP, kort
Voor PHP-sites (zoals WordPress) praat nginx met PHP-FPM, een aparte dienst. Op Debian installeer je php-fpm en zet je in het server block een location ~ \.php$-blok met include snippets/fastcgi-php.conf; en fastcgi_pass unix:/run/php/php8.4-fpm.sock; (het versienummer verschilt per release). De WordPress-cursus gaat daar verder op in.
Op AlmaLinux en Rocky Linux
Daar is er geen sites-available: je zet elke site als eigen bestand in /etc/nginx/conf.d/<naam>.conf. nginx draait als de gebruiker nginx in plaats van www-data, en de standaard webroot is /usr/share/nginx/html. SELinux laat nginx standaard geen verbinding maken met een applicatie achter proxy_pass; zet dat aan met setsebool -P httpd_can_network_connect 1. Bestanden buiten de gebruikelijke mappen hebben een SELinux-label nodig (semanage fcontext en restorecon).
Samenvatting
- nginx serveert bestanden of geeft verzoeken als reverse proxy door aan een applicatie op
127.0.0.1. - Een server block per site in
sites-available, aanzetten met een koppeling insites-enabled; luister op80én[::]:80. - Altijd
nginx -tvóórsystemctl reload nginx. - Een eigen default server met
return 444voorkomt dat een onbekende naam of het kale IP-adres een van je sites toont. - Als reverse proxy geef je
Host,X-Forwarded-ForenX-Forwarded-Protodoor; de webroot is leesbaar voorwww-data, niet schrijfbaar, en zonder geheimen.
Quiz
Opdracht
Opdracht O7.2: Je eerste site. Installeer nginx (of gebruik Caddy uit les 7.4), maak een server block voor een (sub)domein dat naar je server wijst, met listen voor IPv4 en IPv6, eigen logbestanden en een eigen default server. Test met nginx -t, herlaad, en controleer met curl -I via IPv4 en IPv6. Zet de rechten van de webroot zoals in de les. Vul de checklist in en plak je server block.
Opdracht O7.2: Je eerste site
Deze opdracht doe je zelf; niemand kijkt hem na. Vink af wat je gedaan hebt en markeer de opdracht als gedaan.
Op het kale IP niets (verbinding gesloten) of een neutrale pagina, nooit een klantsite. Alleen een uploadmap schrijfbaar voor www-data, de rest alleen-lezen. Achter een proxy: Host, X-Real-IP, X-Forwarded-For en X-Forwarded-Proto.
Je vinkjes en aantekeningen blijven alleen in deze browser; we sturen ze nergens heen. Ben je aangemeld, dan bewaren we in Mijn cursussen alleen dat je de opdracht gedaan hebt.
Verder lezen
- Forbidden (403): You don't have permission to access / on this server
- nginx-documentatie, How nginx processes a request (server_name en default server): https://nginx.org/en/docs/http/request_processing.html
- nginx-documentatie, Beginner's Guide: https://nginx.org/en/docs/beginners_guide.html
- nginx-documentatie,
ngx_http_proxy_module: https://nginx.org/en/docs/http/ngx_http_proxy_module.html
