Servery a DevOps

Nginx jako reverse proxy pro Node.js a Python aplikace

Jak dát nginx před aplikaci na portu 3000 nebo 8000: server blok, hlavičky X-Forwarded, WebSockety, timeouty, velikost uploadu a ladění chyby 502.

12. 10. 2026 · 4 min čtení

Aplikace v Node.js, Pythonu (FastAPI, Flask, Django) nebo Go obvykle běží na vlastním portu, třeba 3000 nebo 8000. Vystavit ji přímo do internetu není dobrý nápad. Nginx před ní vyřeší HTTPS, kompresi, statické soubory, limity a umožní provozovat více aplikací na jednom serveru pod různými doménami.

Základní princip

Prohlížeč ──HTTPS:443──▶ nginx ──HTTP:127.0.0.1:3000──▶ aplikace

Aplikace by měla naslouchat jen na 127.0.0.1, ne na 0.0.0.0. Tím je zvenku nedostupná a jediná cesta k ní vede přes nginx.

  • Node.js/Express: app.listen(3000, '127.0.0.1')
  • Uvicorn: uvicorn main:app --host 127.0.0.1 --port 8000
  • Gunicorn: gunicorn -b 127.0.0.1:8000 app:app

Instalace nginx

sudo apt install nginx
sudo ufw allow 'Nginx Full'

Konfigurace server bloku

Vytvořte /etc/nginx/sites-available/mojeapp.cz:

upstream mojeapp {
    server 127.0.0.1:3000;
    keepalive 16;
}

server {
    listen 80;
    listen [::]:80;
    server_name mojeapp.cz www.mojeapp.cz;

    client_max_body_size 20m;

    location / {
        proxy_pass http://mojeapp;
        proxy_http_version 1.1;

        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 Connection        "";
    }
}

Aktivujte ji a otestujte:

sudo ln -s /etc/nginx/sites-available/mojeapp.cz /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx

Výchozí web nginx můžete vypnout: sudo rm /etc/nginx/sites-enabled/default.

Proč ty hlavičky

Hlavička K čemu slouží
Host aplikace ví, jaká doména byla požadována
X-Real-IP / X-Forwarded-For skutečná IP návštěvníka (jinak uvidíte jen 127.0.0.1)
X-Forwarded-Proto aplikace pozná, že požadavek přišel přes HTTPS

Aplikaci musíte říct, že má těmto hlavičkám věřit:

  • Express: app.set('trust proxy', 'loopback')
  • Uvicorn: --proxy-headers --forwarded-allow-ips 127.0.0.1
  • Django: SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')

Bez toho budou například přesměrování generovat http:// odkazy nebo rate limiting uvidí všechny návštěvníky jako jednu IP.

WebSockety

Socket.IO, live reload nebo chat potřebují upgrade spojení. Do kontextu http (např. do /etc/nginx/conf.d/websocket.conf) přidejte:

map $http_upgrade $connection_upgrade {
    default upgrade;
    ''      close;
}

A do location:

proxy_set_header Upgrade    $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_read_timeout 1h;

Řádek Connection "" ze základní konfigurace pak nahraďte tímto.

Statické soubory přímo z nginx

Nginx servíruje statické soubory mnohem efektivněji než Node nebo Python:

location /static/ {
    alias /var/www/mojeapp/static/;
    expires 30d;
    access_log off;
}

Pozor na lomítka: u alias musí cesta končit /, pokud location končí /.

Timeouty a dlouhé požadavky

Výchozí proxy_read_timeout je 60 sekund. Pokud vaše API generuje export nebo volá pomalou službu, prodlužte ho jen pro konkrétní cestu:

location /api/export {
    proxy_pass http://mojeapp;
    proxy_read_timeout 300s;
}

Pro streamované odpovědi (Server-Sent Events, postupné generování textu) vypněte buffering:

proxy_buffering off;

Více aplikací na jednom serveru

Každá doména má vlastní soubor v sites-available s jiným server_name a jiným portem v upstream. Alternativně můžete aplikace rozdělit podle cesty:

location /api/ {
    proxy_pass http://127.0.0.1:8000/;
}

Koncové lomítko v proxy_pass znamená, že se prefix /api/ odstraní – aplikace dostane /users místo /api/users. Bez lomítka se cesta předá beze změny.

Ladění 502 Bad Gateway

502 znamená, že nginx se k aplikaci nedostal. Postup:

sudo tail -n 20 /var/log/nginx/error.log
curl -I http://127.0.0.1:3000
sudo ss -tlpn | grep 3000

Typické příčiny:

  • aplikace neběží nebo spadla – zkontrolujte systemctl status / journalctl,
  • naslouchá na jiném portu nebo jen na IPv6 (::1),
  • v logu je connect() failed (111: Connection refused) = nikdo neposlouchá,
  • upstream timed out = aplikace odpovídá pomalu (504).

Další krok: HTTPS

S funkčním HTTP blokem stačí spustit sudo certbot --nginx -d mojeapp.cz -d www.mojeapp.cz a certbot doplní HTTPS konfiguraci sám. Aplikaci pak spouštějte jako systemd službu, aby se po restartu serveru rozběhla automaticky.