Nginx je webový server, ktorý je možné použiť v roly cache server, loadbalancer, alebo tiež reverzný proxy. Ja používam Nginx v roly reverzného proxy servera. HTTP znamená „Hypertextový prenosový protokol“ čo je komunikačný protokol, ktorý sa používa na prenos hypertextových dokumentov, ako sú napr. webové stránky, medzi webovým klientom (napr. webový prehliadač) a webovým serverom. Prvá ver. HTTP protokolu HTTP/0.9 bola nasadená v roku 1990 a postupne sa protokol zdokonaľoval cez ver. HTTP/1.0, HTTP/1.1, HTTP/2 a v súčasnej dobe prechádza väčšina webových serverov na HTTP-over-QUIC, resp. HTTP/3.
V minulom blogu som sa pokúšal migrovať z Nginx na Caddy, čo sa mi aj podarilo, ale problém bol v dlhom načitávaní WordPress webov. Čiže s Caddy som po krátkom čase prešiel znova na Nginx. Ak by som ostal pri Caddy, tak HTTP/3 tam funguje po vybalení z krabice a nič extra nie je potrebné nastavovať.
Nginx vydal prvé binárne balíčky s oficiálnou podporou HTTP/3 už 02.08.2023 a to pre 2 veľké distribúcie, Red Hat 9 a Ubuntu 22.04. Nginx teda oficiálne podporuje HTTP/3 s QUIC od verzie 1.25.1. Do vtedy bolo možné tiež experimentálne používať Nginx s podporou QUIC, ale bola potrebná kompilácia zo zdroja. V debiane je to teraz omnoho jednoduchšie a môžeme na to použiť jednoduchý baličkovací nástroj APT.
V dobe písania tohto článku mám Nginx nasadení v linuxovom kontajnery Debian 12. Upozorňujem, že nám nestačí použiť klasicky
1 2 3 | udo apt update sudo apt install curl gnupg2 ca-certificates lsb-release sudo apt install nginx -y |
Pretože v repozitároch Debian 12 sa nachádza
nginx version: nginx/1.22.1
Táto verzia ešte nepodporuje HTTP/3. Preto musíme systém nastaviť tak, aby neinštaloval Nginx s Debian repozitárov, ale aby použil repozitár Nginx. Postupovať by sme mali podľa návodu na nginx webe. Najprv nainštalujeme (je možné že už to máme nainštalované)
1 | sudo apt install curl gnupg2 ca-certificates lsb-release debian-archive-keyring |
Poznámka: Ja už mám Nginx nainštalovaný budem len aktualizovať na ver. 1.25.2
Importujeme oficiálny podpisový kľúč nginx, aby apt mohol overiť pravosť balíkov.
1 2 | curl https: //nginx .org /keys/nginx_signing .key | gpg --dearmor \ | sudo tee /usr/share/keyrings/nginx-archive-keyring .gpg > /dev/null |
Skontrolujeme, či stiahnutý súbor obsahuje správny kľúč:
1 | gpg --dry-run --quiet --no-keyring -- import -- import -options import -show /usr/share/keyrings/nginx-archive-keyring .gpg |
Výstup by mal obsahovať cely fingerprint 573BFD6B3D8FBC641079A6ABABF5BD827BD9BF62 takto:
pub rsa2048 2011-08-19 [SC] [expires: 2024-06-14]
573BFD6B3D8FBC641079A6ABABF5BD827BD9BF62
uid nginx signing key <signing-key@nginx.com>
Teraz môžeme nastaviť aby sa inštalovalo buď zo stabilnej, alebo z hlavnej vetvy. Kedže podpora HTTP/3 je od ver. 1.25.1 a v stabilnej vetve ešte nie je tato ver. tak musíme nastaviť hlavnú vetvu.
Toto je pre stabilnú vetvu, takže mi nepoužijeme tento príkaz, pretože pri písani tohto článku ešte v stabilnej vetve nie je nginx s podporou HTTP/3
1 2 3 | echo "deb [signed-by= /usr/share/keyrings/nginx-archive-keyring .gpg] \ http: //nginx .org /packages/debian `lsb_release -cs` nginx" \ | sudo tee /etc/apt/sources .list.d /nginx .list |
Až tento príkaz pre hlavnú vetvu obsahuje nginx s podporou HTTP/3
1 2 3 | echo "deb [signed-by= /usr/share/keyrings/nginx-archive-keyring .gpg] \ http: //nginx .org /packages/mainline/debian `lsb_release -cs` nginx" \ | sudo tee /etc/apt/sources .list.d /nginx .list |
Nastavíme aby sa uprednostnila inštalácia z nginx úložiska pred inštaláciou poskytovateľa distribúcie (čiže úložisko pre Debian 12)
1 2 | echo -e "Package: *\nPin: origin nginx.org\nPin: release o=nginx\nPin-Priority: 900\n" \ | sudo tee /etc/apt/preferences .d /99nginx |
Aktualizujeme zmeny, ktoré sme pridali a môžete inštalovať
1 2 | sudo apt update sudo apt install nginx |
Počas inštalácie uvidíme ničo také (upozorňujem, že táto hláška sa objaví, len na systéme, kde už je nainštalovaná strašia ver. Nginx).
Configuration file '/etc/nginx/nginx.conf'
==> Modified (by you or by a script) since installation.
==> Package distributor has shipped an updated version.
What would you like to do about it ? Your options are:
Y or I : install the package maintainer's version
N or O : keep your currently-installed version
D : show the differences between the versions
Z : start a shell to examine the situation
The default action is to keep your current version.
*** nginx.conf (Y/I/N/O/D/Z) [default=N] ?
Táto hláška hovorí o tom že konfiguračný súbor je iný ako pôvodný a my sa máme rozhodnúť či nainštalujeme nový, alebo ponecháme pôvodný (príp. skontrolovať rozdieli). Predvolene je vybraté „N“, takže môžeme pokračovať s pôvodným. Po nainštalovaní povolíme službu nginx v systemd a na manipuláciu budeme používať štandardne príkazy
1 2 3 4 5 6 | sudo systemctl enable nginx sudo systemctl status nginx sudo systemctl start nginx sudo systemctl stop nginx sudo systemctl reload nginx |
Či je v Nginx určite dostupný aj modul pre HTTP/3 sa môžeme presvedčiť napr. takto
1 | sudo nginx -V 2>&1 | tr ' ' '\n' | grep 'http_' |
Všimnime si posledný modul. To znamená, že binárka je skompilovaná s HTTP/3 modulom.
--with-http_addition_module
--with-http_auth_request_module
--with-http_dav_module
--with-http_flv_module
--with-http_gunzip_module
--with-http_gzip_static_module
--with-http_mp4_module
--with-http_random_index_module
--with-http_realip_module
--with-http_secure_link_module
--with-http_slice_module
--with-http_ssl_module
--with-http_stub_status_module
--with-http_sub_module
--with-http_v2_module
--with-http_v3_module
Ak sme Nginx už spustili, tak všetky konfiguračné súbory by mali byť Nginxom načítane a malo by to všetko fungovať. Môžeme sa však stretnúť minimálne z jednou zastaralou direktívou a to HTTP2. Po štarte nginx, resp. po reloade môžeme vidieť tieto hlášky a to pre každý konfiguračný súbor (čiže ich tam môže byť viac).
1 2 | Sep 07 12:37:59 debian-12-nginx-proxy nginx[815]: nginx: [warn] the "listen ... http2" directive is deprecated, use the "http2" directive instead in /etc/nginx/sites-enabled/www .example.com:5 Sep 07 12:37:59 debian-12-nginx-proxy nginx[815]: nginx: [warn] the "listen ... http2" directive is deprecated, use the "http2" directive instead in /etc/nginx/sites-enabled/www .example.com:34 |
Spôsobené je to touto smernicou
1 | listen 443 ssl http2; |
Musíme ju nahradiť týmto
1 2 | listen 443 ssl; http2 on; |
Po tejto zmene v každom konfiguračnom súbore už po reloade nedostaneme žiadne škaredé hlášky
1 2 3 | sudo nginx -t && sudo systemctl reload nginx nginx: the configuration file /etc/nginx/nginx .conf syntax is ok nginx: configuration file /etc/nginx/nginx .conf test is successful |
Ak by sme nechceli používať HTTP/3, tak jednoducho už nič nemusíme robiť a naďalej budme fungovať s HTTP/2. Avšak naším cieľom je HTTP/3.
Sem ešte vsuniem jednu drobnú ale dôležitú poznámku. Aby sme sa po konfigurácii servera zbytočne netrápili, prečo nám nefunguje HTTP/3, tak na našom routery/firewalle musíme v časti NAT okrem TCP povoliť tiež UDP protokol na porte 443.
Musím napísať, že podľa manuálu na nginx webe to mala byť jednoduchá záležitosť, ale dosť som sa s tým potrápil. Z návodu plynie, že pre základnú implementáciu HTTP/3 sú potrebné 3 smernice
1 2 3 | listen 443 quic reuseport; ssl_protocols TLSv1.3; add_header Alt-Svc 'h3=":$server_port"; ma=86400' ; |
Vzhľadom k tomu, že smernicu ssl_protocols už mám globálne v hlavnom config file, tak som dostal upozornenie na duplicitu. Zúžilo sa to na smernicu listen a add_header. V každom konfiguračnom súbore mám 2 server bloky. Najprv redirect z non www na www a potom na https. Čiže do oboch blokov som nasadil (vrátane HTTP hlavičky)
1 2 3 | listen 443 quic reuseport; # QUIC listen 443 ssl; # TCP add_header Alt-Svc 'h3=":$server_port"; ma=86400' ; |
A vždy som dostal po kontrole konfigurácie hlášku
1 2 | nginx: [emerg] duplicate listen options for 0.0.0.0:443 in /etc/nginx/sites-enabled/www .example.com:5 nginx: configuration file /etc/nginx/nginx .conf test failed |
OK, odstránením smernice z prvého server blocku
1 | listen 443 quic reuseport; # QUIC |
to už fungovalo bez problémov s HTTP/3. Konfiguráciu som si uložil a na editáciu ma čakali ďalšie konfiguráky pre ďalšie domény. Najprv som skúsil upraviť druhý konfigurák a znova som dostal podobnú hlášku
1 2 | nginx: [emerg] duplicate listen options for 0.0.0.0:443 in /etc/nginx/sites-enabled/www .example.com:5 nginx: configuration file /etc/nginx/nginx .conf test failed |
Začal som teda pátrať, prečo sa to tak správa. Musím napísať, že fakt som sa s tým pár hodín trápil až som našiel na stackoverflow, že problém sa dá veľmi jednoducho vyriešiť. Smernicu s reuseport je možné použiť v celej konfigurácii len raz. To znamená, že v jednom konfiguráku to nastavíme s
1 2 3 4 5 6 7 | # HTTP/3 support listen 443 quic reuseport; http2 on; http3 on; http3_hq on; quic_retry on; listen 443 ssl; |
V ďalších server blockoch už pridáme len
1 2 3 4 5 6 7 8 | #HTTP/3 support listen 443 ssl; listen 443 quic; # HTTP/3 Header add_header Alt-Svc 'h3=":$server_port"; ma=86400' ; add_header x-quic 'h3' ; add_header Alt-Svc 'h3-29=":$server_port"' ; |
Vidíme, že reuseport tam už nie je. Čiže každý ďalší konfigurák by mohol vyzerať nejak takto. Je to klasická konfigurácia pre reverzný proxy server obohatená o bezpečnostné HTTP hlavičky a pridaná podpora pre HTTP/3.
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 | server { server_name example.com; return 301 http: //www .example.com$request_uri; #HTTP/3 support listen 443 ssl; listen 443 quic; ssl_certificate /etc/letsencrypt/live/example .com /fullchain .pem; # managed by Certbot ssl_certificate_key /etc/letsencrypt/live/example .com /privkey .pem; # managed by Certbot include /etc/letsencrypt/options-ssl-nginx .conf; # managed by Certbot ssl_dhparam /etc/letsencrypt/ssl-dhparams .pem; # managed by Certbot # HTTP Header add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; add_header Referrer-Policy "no-referrer" always; add_header X-Content-Type-Options "nosniff" always; add_header X-Download-Options "noopen" always; add_header X-Frame-Options "SAMEORIGIN" always; add_header X-Permitted-Cross-Domain-Policies "none" always; add_header X-Robots-Tag "none" always; add_header X-XSS-Protection "1; mode=block" always; add_header Content-Security-Policy "default-src 'self' https: data: 'unsafe-inline' 'unsafe-eval';" always; add_header Permissions-Policy "geolocation=(),midi=(),sync-xhr=(),microphone=(),camera=(),magnetometer=(),gyroscope=(),fullscreen=(self),payment=()" ; # HTTP/3 Header add_header Alt-Svc 'h3=":$server_port"; ma=86400' ; add_header x-quic 'h3' ; add_header Alt-Svc 'h3-29=":$server_port"' ; } server { server_name www.example.com; location / { proxy_pass http: //192 .168.20.11; 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; } #HTTP/3 support listen 443 ssl; listen 443 quic; ssl_certificate /etc/letsencrypt/live/example .com /fullchain .pem; # managed by Certbot ssl_certificate_key /etc/letsencrypt/live/example .com /privkey .pem; # managed by Certbot include /etc/letsencrypt/options-ssl-nginx .conf; # managed by Certbot ssl_dhparam /etc/letsencrypt/ssl-dhparams .pem; # managed by Certbot # HTTP Header add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; add_header Referrer-Policy "no-referrer" always; add_header X-Content-Type-Options "nosniff" always; add_header X-Download-Options "noopen" always; add_header X-Frame-Options "SAMEORIGIN" always; add_header X-Permitted-Cross-Domain-Policies "none" always; add_header X-Robots-Tag "none" always; add_header X-XSS-Protection "1; mode=block" always; add_header Content-Security-Policy "default-src 'self' https: data: 'unsafe-inline' 'unsafe-eval';" always; add_header Permissions-Policy "geolocation=(),midi=(),sync-xhr=(),microphone=(),camera=(),magnetometer=(),gyroscope=(),fullscreen=(self),payment=()" ; # HTTP/3 Header add_header Alt-Svc 'h3=":$server_port"; ma=86400' ; add_header x-quic 'h3' ; add_header Alt-Svc 'h3-29=":$server_port"' ; } server { if ($host = example.com) { return 301 https: // $host$request_uri; } # managed by Certbot listen 80; server_name example.com; return 404; # managed by Certbot } server { if ($host = www.example.com) { return 301 https: // $host$request_uri; } # managed by Certbot listen 80; server_name www.example.com; return 404; # managed by Certbot } |
Či skutočne používame HTTP/3 protokol sa môžeme presvedčiť vo webovom prehliadači, napr. Mozilla, F12 (vývojárska konzola), kde si necháme zobraziť odpovede zo servera (v časti Network -> Headers).
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | HTTP/3 200 OK server: nginx/1.25.2 date: Mon, 18 Sep 2023 12:42:25 GMT content-type: text/css content-length: 2872 last-modified: Sat, 12 Aug 2023 10:42:00 GMT etag: "424f-602b77aa4ebf8-gzip" accept-ranges: bytes vary: Accept-Encoding content-encoding: gzip strict-transport-security: max-age=31536000; includeSubDomains referrer-policy: no-referrer x-content-type-options: nosniff x-download-options: noopen x-frame-options: SAMEORIGIN x-permitted-cross-domain-policies: none x-robots-tag: none x-xss-protection: 1; mode=block content-security-policy: default-src 'self' https: data: 'unsafe-inline' 'unsafe-eval'; permissions-policy: geolocation=(),midi=(),sync-xhr=(),microphone=(),camera=(),magnetometer=(),gyroscope=(),fullscreen=(self),payment=() alt-svc: h3=":443"; ma=86400 x-quic: h3 alt-svc: h3-29=":443" |
Ale tiež keď pôjdme na http3check
Záver
Musím sa priznať, že prechod na HTTP/3 ma trocha potrápil, ale nakoniec to snáď dopadlo dobre. Všetky weby ktoré hostujem na mojich serveroch bežia už s protokolom HTTP/3. Už z princípu by mal byť HTTP/3 rýchlejší ako HTTP/2 (1.1), pretože funguje na UDP. Bežný užívateľ si to až tak veľmi nevšimne, pretože sa jedná o milisekundy. Netvrdím, že moja konfigurácia je ideálna, určite by sa dala ešte vylepšiť, ale v rámci možnosti mi to funguje celkom slušne. Zatiaľ to mám nasadené len niekoľko dní, takže časom to možno budem odlaďovať.