markdown
Nginx.md
markdown
# Nginx Nejrozšířenější reverse proxy a webserver. Upovídanější než [Caddy](Caddy), ale najdeš k němu návod na cokoliv a při vysoké zátěži je nejrychlejší. Koncepty za tím jsou v [reverse proxy](Reverse-proxy) a [TLS](TLS-a-HTTPS). ## Struktura konfigurace ```/etc/nginx/├── nginx.conf # hlavní, globální nastavení├── conf.d/*.conf # sem se dávají vlastní konfigurace├── sites-available/ # Debian a Ubuntu: dostupné weby└── sites-enabled/ # symlinky na aktivní``` Debianovský systém `sites-available` a `sites-enabled` je jen konvence. Aktivace se dělá symlinkem: ```bashln -s /etc/nginx/sites-available/mujweb /etc/nginx/sites-enabled/nginx -t # kontrola syntaxe, VŽDYCKY před reloadsystemctl reload nginx``` To `nginx -t` je návyk, který stojí za vypěstování. Reload s chybnou konfigurací nechá běžet starou, ale restart shodí celý server. ## Reverse proxy, minimální funkční verze ```nginxserver { listen 80; server_name nas.example.cz; return 301 https://$host$request_uri;} server { listen 443 ssl; http2 on; server_name nas.example.cz; ssl_certificate /etc/letsencrypt/live/nas.example.cz/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/nas.example.cz/privkey.pem; ssl_protocols TLSv1.2 TLSv1.3; location / { proxy_pass http://127.0.0.1:5000; 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; proxy_set_header X-Forwarded-Host $host; }}``` Těch pět řádků s `proxy_set_header` je povinná výbava. Bez nich aplikace nevidí skutečného klienta ani neví, že běží pod HTTPS. Proč, je vysvětlené v [reverse proxy](Reverse-proxy). Nginx je nenastavuje sám a to je nejčastější důvod, proč „aplikace za nginxem zlobí". ## Sdílený blok hlaviček Ať to nepíšeš dvacetkrát, dej si to do souboru `/etc/nginx/snippets/proxy.conf`: ```nginxproxy_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;proxy_set_header X-Forwarded-Host $host; proxy_http_version 1.1;proxy_set_header Upgrade $http_upgrade;proxy_set_header Connection $connection_upgrade; proxy_read_timeout 300s;proxy_send_timeout 300s;proxy_connect_timeout 30s;``` a v konfiguraci pak jen: ```nginxlocation / { proxy_pass http://127.0.0.1:5000; include snippets/proxy.conf;}``` ## WebSockety Ty tři řádky s `Upgrade` výše jsou pro WebSockety, ale samy nestačí. V `nginx.conf` v bloku `http` musíš přidat: ```nginxmap $http_upgrade $connection_upgrade { default upgrade; '' close;}``` Bez toho tě čeká `Connection: upgrade` i u běžných požadavků a některé aplikace se z toho zblázní. Pozor taky na `proxy_read_timeout` — ve výchozím stavu je 60 sekund a nečinný WebSocket po nich tiše spadne. Souvislosti v [HTTP, QUIC a WebSocketu](HTTP-QUIC-a-WebSocket). Tohle je řešení problému „Home Assistant se načte, ale nic se neaktualizuje". ## Lomítko v proxy_pass Nejzáludnější detail v celém nginxu. Chování se liší podle toho, jestli je za portem lomítko: ```nginxlocation /app/ { proxy_pass http://127.0.0.1:3000; # BEZ lomítka # /app/foo → /app/foo} location /app/ { proxy_pass http://127.0.0.1:3000/; # S lomítkem # /app/foo → /foo}``` Bez lomítka se cesta předá celá. S lomítkem se prefix z `location` odřízne. Když ti aplikace pod podcestou vrací 404 na všechny statické soubory, je to skoro vždycky tohle. Většina aplikací navíc pod podcestou nefunguje vůbec, ať děláš co děláš — pokud to nemají výslovně podporované, dej jim vlastní subdoménu. ## Velké soubory ```nginxclient_max_body_size 10G; # výchozí je 1 MB!proxy_request_buffering off; # neukládat celý upload na disk proxy``` Výchozí megabajt je důvod, proč ti na Nextcloud nejde nahrát nic většího než dokument. Chyba se hlásí jako `413 Request Entity Too Large`. ## Kompletní příklad se vším ```nginxmap $http_upgrade $connection_upgrade { default upgrade; '' close;} server { listen 80; listen [::]:80; server_name foto.example.cz; return 301 https://$host$request_uri;} server { listen 443 ssl; listen [::]:443 ssl; http2 on; server_name foto.example.cz; ssl_certificate /etc/letsencrypt/live/foto.example.cz/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/foto.example.cz/privkey.pem; ssl_protocols TLSv1.2 TLSv1.3; ssl_session_cache shared:SSL:10m; add_header Strict-Transport-Security "max-age=31536000" always; add_header X-Content-Type-Options nosniff always; add_header X-Frame-Options SAMEORIGIN always; client_max_body_size 50G; access_log /var/log/nginx/foto.access.log; location / { proxy_pass http://127.0.0.1:2283; include snippets/proxy.conf; }}``` Poslouchání na `[::]:443` je pro [IPv6](Jak-funguje-IPv6). Zapomíná se to a pak se na tebe přes IPv6 nikdo nedostane, i když DNS má `AAAA`. ## Omezení rychlosti ```nginx# v bloku httplimit_req_zone $binary_remote_addr zone=obecne:10m rate=10r/s; # v bloku locationlimit_req zone=obecne burst=20 nodelay;``` Ochrana proti robotům, kteří ti perou do přihlašovacího formuláře. Doplněk k [fail2ban](Fail2ban-a-CrowdSec), ne náhrada. ## Skutečné IP za další proxy Když je před nginxem ještě Cloudflare nebo jiná proxy, vidí nginx její adresu. Náprava: ```nginxset_real_ip_from 103.21.244.0/22; # rozsahy Cloudflarereal_ip_header CF-Connecting-IP;real_ip_recursive on;``` Bez toho ti [fail2ban](Fail2ban-a-CrowdSec) zablokuje Cloudflare a s ním všechny návštěvníky. ## Diagnostika ```bashnginx -t # syntaxenginx -T # kompletní výsledná konfigurace včetně includesystemctl reload nginxtail -f /var/log/nginx/error.log``` `nginx -T` je nedoceněný. Ukáže ti složeninu všech souborů, takže hned vidíš, co se doopravdy načetlo — včetně toho, že máš dvě konfigurace pro stejnou doménu a použije se ta první. | Chyba | Příčina ||---|---|| `502 Bad Gateway` | aplikace za proxy neběží nebo je na jiném portu || `504 Gateway Timeout` | aplikace odpovídá moc dlouho, zvyš `proxy_read_timeout` || `413 Request Entity Too Large` | `client_max_body_size` || `404` na statické soubory pod podcestou | lomítko v `proxy_pass` || smyčka přesměrování | chybí `X-Forwarded-Proto` |