# nginx

## Hvad det er

nginx er et open source-program, der tager imod HTTP-forbindelser og for hver
anmodning enten svarer med filer fra disken eller sender anmodningen videre til
en anden server og giver svaret tilbage til klienten. Navnet udtales
»engine x«, og projektets egne sider skriver det også NGINX. Igor Sysoev skrev
programmet, og den første offentlige version, 0.1.0, udkom den 4. oktober 2004.
Det er gratis at bruge under en BSD-licens med to klausuler, og F5, Inc.
sælger virksomhedsdistributioner, support og undervisning.

Projektet nævner seks roller: HTTP-server, omvendt proxy, indholdscache, load
balancer, TCP- og UDP-proxy samt mailproxy. På en webhost har nginx som regel
det ene eller begge af to job: at servere statiske filer fra disken og at stå
foran en applikationsserver, hvor det terminerer TLS og sender hver anmodning
videre indad.

Når nginx starter, kører det én masterproces og flere workerprocesser. Masteren
læser og kontrollerer konfigurationen og holder øje med workerne. Workerne
kører som en bruger uden særlige rettigheder og står for al behandling af
anmodninger. Hver af dem bruger en hændelsesbaseret løkke, bygget på epoll på
Linux og kqueue på FreeBSD, så en håndfuld workere kan holde tusindvis af
forbindelser åbne på én gang. Direktivet worker_processes bestemmer, hvor mange
der er, enten som et fast tal eller som auto for én pr. CPU-kerne, og
projektets liste over funktioner sætter 10.000 inaktive keep-alive-forbindelser
til omkring 2,5 MB hukommelse.

Konfigurationen er en tekstfil med direktiver. Et simpelt direktiv er et navn
og dets parametre, afsluttet med et semikolon. Et blokdirektiv omslutter andre
direktiver i krøllede parenteser, og en blok, der kan rumme direktiver, kaldes
en kontekst. Kontekstene events og http ligger på øverste niveau. Inde i http
beskriver hver server-blok én virtuel server, valgt ud fra den adresse og port,
den lytter på, og derefter ud fra det værtsnavn, klienten bad om. Inde i en
server-blok siger hver location-blok, hvad der skal ske med en familie af
anmodningsstier.

## Hvorfor det betyder noget

Webserveren er det ene program, som alle besøgende er i berøring med, så dens
opførsel under belastning og dens standardindstillinger når ud til alle. To
egenskaber taler for nginx.

Den første er, hvor billigt det bærer langsomme forbindelser. Buffering af svar
fra en server bag proxyen er slået til som standard: nginx tager imod
backendens svar så hurtigt, som backenden kan levere det, skriver det til en
midlertidig fil, når det bliver for stort til hukommelsen, og sender det så
videre til klienten i det tempo, klienten kan klare. Applikationsserveren er
fri til sin næste anmodning, mens en telefon med svagt signal stadig henter den
forrige.

Den anden er, at ændringer i konfigurationen går i luften uden at tabe
anmodninger. En redigeret konfiguration får først virkning ved en reload eller
en genstart. Ved en reload kontrollerer masteren den nye konfiguration og
forsøger at tage den i brug. Lykkes det, starter nye workere med den, mens de
gamle holder op med at tage imod forbindelser, gør de anmodninger færdige, som
de har i gang, og afslutter. Mislykkes det, ruller masteren tilbage og
fortsætter med den konfiguration, den allerede havde. Projektet nævner også
opgradering af selve programfilen uden at afbryde klienterne.

Prisen betales i konfigurationssproget, hvis regler for forrang og nedarvning
er der, hvor de fleste overraskelser bor. For en anmodningssti finder nginx
først den location med det længste matchende præfiks og husker den, prøver så
de locations, der bruger regulære udtryk, i den rækkefølge, de står i filen, og
tager det første, der matcher. Slår alle de regulære udtryk fejl, bruges den
huskede præfiks-location. En location markeret med `=` kræver, at stien passer
præcist, og afslutter søgningen med det samme, og `^~` på det længste præfiks
får nginx til at springe de regulære udtryk over. Nogle direktiver, blandt dem
add_header og proxy_set_header, arves kun fra det omsluttende niveau, hvis det
aktuelle niveau ikke selv definerer nogen.

Certifikater kom længe fra en ACME-klient, der kørte ved siden af nginx.
Projektet tilbyder nu også ngx_http_acme_module, der leveres separat fra
kernebygget.

## Sådan ser det ud i praksis

To stykker af virksomhedens tidligere hostingarbejde involverer nginx, og i
begge delte nginx serverne med Apache frem for at afløse den.

Det første var
[fyrre kundewebsites, der skulle være hurtige og altid kunne nås](/da/portfolio/administered-40-websites-on-ubuntu-linux-hosting-servers-53/),
og de lå på servere med Ubuntu Linux, hvor både Apache og nginx var i brug.
Opgaven var at skrive deres konfiguration, tune dem for hastighed og passe dem,
mens rigtige besøgende brugte dem, og alle fyrre forblev højt tilgængelige. To
webservere i én flåde betyder, at hver regel findes på to dialekter: en
VirtualHost-blok i Apache er en server-blok i nginx, og en rettelse til den ene
skal oversættes til den anden.

Det andet strakte sig fra 2015 til 2022.
[Et ACME-workflow overtog certifikaterne for hundrede Docker-applikationer](/da/portfolio/automated-ssl-tls-certificate-creation-for-100-docker-41/),
udstedte hvert certifikat, fornyede det inden udløb og installerede det på
Ubuntu-værterne uden et menneske i løkken, og også på de værter var både Apache
og nginx i brug. På nginx' side er en fornyet fil på disken kun halvdelen af
sådan en ændring. Et certifikat, der er angivet med en almindelig sti, læses,
når nginx indlæser sin konfiguration, og dokumentationen bemærker, at kun et
filnavn bygget af variabler får det til at indlæse certifikatet igen ved hvert
TLS-håndtryk. En fornyelse, der skriver nye filer, når derfor først de
besøgende efter en reload, så enhver automatiseret fornyelse til nginx skal
slutte med én.

## Hvor det går galt

**En header, der er sat for hele sitet, forsvinder på én sti.** En location med
bare én egen add_header arver ingen fra server- eller http-niveauet, så én
cacheheader tilføjet til en enkelt location fjerner stille alle
sikkerhedsheadere over den. proxy_set_header følger samme regel. add_header
gælder desuden kun for succes- og omdirigeringskoder som 200, 301 og 304,
medmindre den får `always`, så fejlsider går ud uden. Hold fælles headere i én
fil, der hentes ind med include på hvert niveau, der sætter sine egne, eller sæt
fra 1.29.3 `add_header_inherit merge;`, tilføj `always`, hvor fejlsvar skal have
dem, og kontrollér hver sti med `curl -sI`.

**Anmodninger til ét site bliver besvaret af et andet.** nginx matcher først
adresse og port og derefter Host-headeren mod server_name. Er navnet ukendt for
alle server-blokke på den port, går anmodningen til standardserveren, som er
den første på listen, medmindre en anden er markeret default_server. En
tastefejl i et nyt sites server_name serverer derfor stille en gammel nabos
sider. Erklær en eksplicit standardserver, der besvarer ukendte navne med
`return 444`, som lukker forbindelsen, så en fejl viser sig som en fejl og ikke
som det forkerte site.

**Uploads fejler med 413 Request Entity Too Large.** client_max_body_size er
som standard 1 MB, og nginx afviser en større anmodningskrop, før applikationen
ser den. Hæv grænsen i den location, der tager imod uploads, frem for i hele
serveren, og hold den i takt med applikationens egen grænse.

**Backenden bygger links til den forkerte vært eller får den forkerte sti.** Som
standard sender nginx serveren bag proxyen en Host-header bygget af adressen i
proxy_pass, for eksempel `127.0.0.1:8080`, så applikationen laver omdirigeringer
og absolutte links til den adresse. Sæt `proxy_set_header Host $host;` i den
location, der videresender. Stier ændrer sig med proxy_pass' form: skrevet med
en URI, selv et enkelt `/`, erstatter den den del af stien, der matchede
location, mens den uden en URI sender stien uændret videre, så test en indlejret
sti efter hver ændring.

**Klienterne får stadig den gamle konfiguration eller det gamle certifikat.** En
redigeret fil eller et certifikat fornyet i nattens løb ændrer intet for en
kørende nginx før en reload, og en reload af en defekt konfiguration lader den
gamle blive. Test før hver reload, læs så fejlloggen, og kontrollér, hvad
klienterne faktisk modtager:

```sh
nginx -t && nginx -s reload
openssl s_client -connect example.com:443 \
  -servername example.com </dev/null |
  openssl x509 -noout -enddate
```

## Læs mere

- [nginx documentation](https://nginx.org/en/docs/)
  — projektets oversigt over vejledninger og direktivreferencer pr. modul.
- [Beginner's Guide](https://nginx.org/en/docs/beginners_guide.html)
  — master- og workerprocesser, reload og konfigurationens opbygning.
- [How nginx processes a request](https://nginx.org/en/docs/http/request_processing.html)
  — hvordan en server-blok vælges ud fra adresse, port og Host-header.
- [Module ngx_http_core_module](https://nginx.org/en/docs/http/ngx_http_core_module.html)
  — rækkefølgen for location-match, server_name og client_max_body_size.
- [Module ngx_http_proxy_module](https://nginx.org/en/docs/http/ngx_http_proxy_module.html)
  — proxy_pass, standardheadere, timeouts og buffering af svar.
- [Module ngx_http_headers_module](https://nginx.org/en/docs/http/ngx_http_headers_module.html)
  — add_header, de svarkoder, den gælder for, og dens regel for nedarvning.

<https://engineer.company/da/glossary/nginx/>
