Programování

Nasazení Python aplikace na VPS: systemd, Gunicorn, Uvicorn a Nginx

Kompletní postup nasazení Flask, Django nebo FastAPI aplikace na Linux server – virtuální prostředí, Gunicorn s Uvicorn workery, služba systemd, Nginx a HTTPS.

12. 10. 2026 · 5 min čtení

python app.py v otevřeném SSH sezení není nasazení. Po odhlášení aplikace spadne, po restartu serveru se nespustí a vývojový server není stavěný na produkční provoz. Tento návod ukazuje osvědčenou sestavu: aplikační server Gunicorn (nebo Uvicorn), správa procesu přes systemd a Nginx jako reverzní proxy s HTTPS. Příkazy jsou pro Debian 12 / Ubuntu 22.04+.

Architektura

Internet → Nginx (:443, TLS, statické soubory) → Gunicorn (127.0.0.1:8000) → vaše aplikace
                                                    ↑ spravuje systemd

1. Uživatel a adresáře

Aplikace nemá běžet pod rootem:

sudo apt update
sudo apt install python3-venv python3-pip nginx git
sudo adduser --system --group --home /srv/mojeapp mojeapp
sudo -u mojeapp git clone https://github.com/vy/mojeapp.git /srv/mojeapp/app

2. Virtuální prostředí a závislosti

cd /srv/mojeapp
sudo -u mojeapp python3 -m venv venv
sudo -u mojeapp venv/bin/pip install -r app/requirements.txt gunicorn

Pro FastAPI přidejte i uvicorn:

sudo -u mojeapp venv/bin/pip install "uvicorn[standard]"

3. Ruční test

Před psaním služby ověřte, že aplikace vůbec startuje:

cd /srv/mojeapp/app
# Flask (objekt app v souboru app.py):
sudo -u mojeapp ../venv/bin/gunicorn -b 127.0.0.1:8000 app:app
# Django (projekt "mysite"):
sudo -u mojeapp ../venv/bin/gunicorn -b 127.0.0.1:8000 mysite.wsgi:application
# FastAPI (objekt app v main.py):
sudo -u mojeapp ../venv/bin/gunicorn -b 127.0.0.1:8000 -k uvicorn.workers.UvicornWorker main:app

V druhém terminálu: curl -i http://127.0.0.1:8000/. Když odpoví, ukončete Ctrl+C.

Poznámka k FastAPI: novější verze Uvicornu (0.30+) mají vlastního správce procesů, takže lze použít i uvicorn main:app --workers 4. Varianta s Gunicornem je stále běžná a funguje.

4. Proměnné prostředí

Tajné hodnoty nepatří do gitu ani do unit souboru. Vytvořte /etc/mojeapp.env:

DATABASE_URL=postgresql://mojeapp:heslo@localhost/mojeapp
SECRET_KEY=dlouhy-nahodny-retezec
DJANGO_SETTINGS_MODULE=mysite.settings
sudo chown root:mojeapp /etc/mojeapp.env
sudo chmod 640 /etc/mojeapp.env

5. Služba systemd

/etc/systemd/system/mojeapp.service:

[Unit]
Description=Moje Python aplikace
After=network.target

[Service]
Type=notify
User=mojeapp
Group=mojeapp
WorkingDirectory=/srv/mojeapp/app
EnvironmentFile=/etc/mojeapp.env
ExecStart=/srv/mojeapp/venv/bin/gunicorn \
    --workers 3 \
    --bind 127.0.0.1:8000 \
    --access-logfile - \
    --timeout 60 \
    app:app
ExecReload=/bin/kill -s HUP $MAINPID
Restart=always
RestartSec=3

# Základní zabezpečení
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=full
ProtectHome=true

[Install]
WantedBy=multi-user.target
  • Type=notify – Gunicorn od verze 20 podporuje notifikaci systemd, takže systemd ví, kdy je aplikace skutečně připravená. Pokud používáte samotný Uvicorn, dejte Type=simple.
  • --workers – rozumný start je 2 × počet jader + 1. U async workerů (Uvicorn) stačí méně, typicky počet jader.
  • --access-logfile - – přístupový log jde na stdout, a tedy do journalu.
  • ExecReload s HUP – Gunicorn plynule restartuje workery bez výpadku.
  • Pro FastAPI přidejte do ExecStart volbu -k uvicorn.workers.UvicornWorker a cíl main:app.

Spuštění:

sudo systemctl daemon-reload
sudo systemctl enable --now mojeapp
systemctl status mojeapp
journalctl -u mojeapp -f

6. Nginx jako reverzní proxy

/etc/nginx/sites-available/mojeapp:

server {
    listen 80;
    server_name mojeapp.cz www.mojeapp.cz;

    client_max_body_size 20M;

    location /static/ {
        alias /srv/mojeapp/app/static/;
        expires 30d;
    }

    location / {
        proxy_pass http://127.0.0.1:8000;
        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_read_timeout 60s;
    }
}
sudo ln -s /etc/nginx/sites-available/mojeapp /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx

U Djanga nejdřív spusťte manage.py collectstatic, aby se statické soubory zkopírovaly do adresáře, na který ukazuje alias (nastavení STATIC_ROOT).

Pro websockety (např. FastAPI) přidejte do location /:

proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";

7. HTTPS přes Let’s Encrypt

sudo apt install certbot python3-certbot-nginx
sudo certbot --nginx -d mojeapp.cz -d www.mojeapp.cz

Certbot upraví konfiguraci Nginxu a nastaví automatickou obnovu. Ověření: sudo certbot renew --dry-run.

Aplikace za proxy musí vědět, že původní požadavek byl HTTPS (kvůli generování URL a bezpečným cookies):

  • Django: SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https") a nastavený ALLOWED_HOSTS.
  • Flask: from werkzeug.middleware.proxy_fix import ProxyFix; app.wsgi_app = ProxyFix(app.wsgi_app, x_for=1, x_proto=1).
  • Gunicorn/Uvicorn: hlavičkám X-Forwarded-* důvěřují ve výchozím stavu jen z 127.0.0.1, což při proxy na stejném stroji stačí.

8. Firewall

sudo ufw allow OpenSSH
sudo ufw allow "Nginx Full"
sudo ufw enable

Port 8000 se ven neotevírá – Gunicorn poslouchá jen na 127.0.0.1.

9. Nasazení nové verze

cd /srv/mojeapp/app
sudo -u mojeapp git pull
sudo -u mojeapp ../venv/bin/pip install -r requirements.txt
# Django: sudo -u mojeapp ../venv/bin/python manage.py migrate
sudo systemctl reload mojeapp

Tyto kroky se vyplatí uložit do skriptu deploy.sh.

Řešení problémů

Příznak Kde hledat
502 Bad Gateway aplikace neběží: systemctl status mojeapp, journalctl -u mojeapp -n 100
504 Gateway Timeout pomalý požadavek – zvyšte --timeout i proxy_read_timeout, nebo přesuňte práci na pozadí
ModuleNotFoundError ve službě špatný WorkingDirectory nebo ExecStart neukazuje do venv
Chybí proměnné prostředí práva k /etc/mojeapp.env, překlep v EnvironmentFile
Statické soubory 404 cesta v alias musí končit lomítkem, Nginx potřebuje právo čtení

Celý postup můžete projít i s ColdHost AI v režimu Server a DevOps: připojte VPS přes SSH, AI navrhne jednotlivé příkazy a vy každý schválíte kliknutím, takže vidíte, co se na serveru děje. Pro úpravy konfigurace se dá použít prohlížeč souborů přes SFTP.