Kako pokretati Python aplikacije s Gunicorn i Nginx na VPS
Rasporedite Flask ili FastAPI aplikaciju na Ubuntu s virtualenv, systemd uslugom Gunicorn, obrnutim proxyjem Nginx, TLS, datotekama okruženja, zapisivanjem i kontrolnim popisom za 502 pogreške i dimenzioniranje radnika.

Ugrađeni Flask poslužitelj i uvicorn --reload su za razvoj. Na javnom VPS hoćete upravitelj procesa koji restartira radnike, veže se na localhost i sjedi iza obrnutog proxyja koji obrađuje TLS i spore klijente. Gunicorn uobičajen je WSGI izbor za Flask i Django. FastAPI može ići pod Gunicorn s klasom radnika Uvicorn. Nginx (ili Caddy) skida HTTPS i prosljeđuje na 127.0.0.1:8000.
Ovaj vodič prolazi kroz raspored koji preživi restart: projekt u /srv/app, virtualenv, .env s tajnama, jedinica gunicorn.service, Nginx poslužiteljski blok, Let's Encrypt i zapisničke datoteke koje stvarno možete grepovati. Govorit ćemo i o broju radnika, istecima vremena i zašto 502 Bad Gateway gotovo nikad ne znači „Nginx je pokvaren“ — gotovo uvijek Gunicorn ne radi, vezan je za pogrešnu utičnicu ili pada na uvozu. Primjer koristi Flask, s napomenama za FastAPI tamo gdje se naredba razlikuje.
Zašto ovaj stog
Gunicorn unaprijed pokreće procese radnika. Svaki radnik obrađuje jedan zahtjev u danom trenutku osim ako koristite drugu klasu radnika. Nginx međusprema spore klijente da radnici ne zapinju na slanju bajtova u mobilnu mrežu. systemd restartira aplikaciju ako umre. Zajedno je to dosadno — a upravo to hoćete u tri ujutro.
- Gunicorn: stabilan model procesa WSGI/ASGI
- systemd: start pri pokretanju, restart pri padu, journald zapisnici
- Nginx: TLS, statičke datoteke, limiti veličine zahtjeva, gzip
- venv: sistemski Python ostaje čist
- vezivanje na localhost: do aplikacije se stiže samo kroz Nginx
Zahtjevi
Python 3.10+ na Ubuntu 22.04/24.04 dovoljan je. Ne pokrećite pip kao root u sistemske site-packages. Za TLS treba domena. Ako kao proxy više volite Caddy, Gunicorn jedinica iz ovog članka ostaje ista — mijenja se samo prednji config (vidi članak o Caddyju).
- Ubuntu 22.04 ili 24.04 VPS
- Vaša aplikacija s requirements.txt ili ekvivalentom
- WSGI ulazna točka (za Flask: app:app) ili ASGI (za FastAPI: app:app s uvicorn radnicima)
- A zapis domene za HTTPS
Korak 1. Sistemski paketi, korisnik i direktorij projekta
Napravite sistemskog korisnika koji ne može interaktivno se prijaviti, posjeduje kod i pokreće Gunicorn. Instalacija python3-venv i alata za gradnju izbjegava padove pip na paketima koji još kompajliraju C proširenja.
ssh root@YOUR_VPS_IP
apt update && apt -y upgrade
apt -y install python3 python3-venv python3-pip python3-dev build-essential nginx curl
adduser --system --group --home /srv/app appuser
mkdir -p /srv/app
chown appuser:appuser /srv/app
# Copy your code (example):
# rsync -a --delete ./myproject/ appuser@YOUR_VPS_IP:/srv/app/Korak 2. Virtualenv i ovisnosti
Pravite venv kao appuser da vlasništvo datoteka bude točno. U produkciji pričvrstite verzije. Nakon instalacije potvrdite da možete uvesti aplikaciju jednokratnim gunicorn --check-config ili Python uvozom. Pogreške uvoza ovdje iste su pogreške koje kasnije postanu 502.
sudo -u appuser -H bash -lc '
cd /srv/app
python3 -m venv /srv/app/venv
/srv/app/venv/bin/pip install --upgrade pip
/srv/app/venv/bin/pip install -r /srv/app/requirements.txt gunicorn
'
# Flask example check:
sudo -u appuser -H /srv/app/venv/bin/python -c "from app import app; print('import ok')"Korak 3. Datoteka okruženja
Ne ušivajte SECRET_KEY ili URL baze u systemd jedinicu tako da završe u gitu čitljivom svima. Koristite EnvironmentFile. chmod 640, vlasnik root, grupa appuser (ili vlasnik appuser ako više volite).
cat >/srv/app/.env <<'EOF'
FLASK_ENV=production
SECRET_KEY=replace-with-openssl-rand-hex-32
DATABASE_URL=postgresql://app:password@127.0.0.1:5432/app
EOF
chown appuser:appuser /srv/app/.env
chmod 600 /srv/app/.envKorak 4. systemd usluga Gunicorn
Vežite se na 127.0.0.1:8000, ne na 0.0.0.0, osim ako imate razlog da zaobiđete Nginx. Broj radnika često je (2 × CPU) + 1 za sync radnike; na VPS s 2 vCPU to je 5, što može biti previše ako svaki radnik učita teški ML model — tada 2–3. Za FastAPI postavite --worker-class uvicorn.workers.UvicornWorker i instalirajte uvicorn. Isteci trebaju premašiti najsporiji pošten zahtjev, ne 30 sekundi ako imate izvoze od 2 minute.
cat >/etc/systemd/system/gunicorn.service <<'EOF'
[Unit]
Description=Gunicorn for the web app
After=network.target
[Service]
User=appuser
Group=appuser
WorkingDirectory=/srv/app
EnvironmentFile=/srv/app/.env
ExecStart=/srv/app/venv/bin/gunicorn --workers 3 --bind 127.0.0.1:8000 --timeout 60 --access-logfile - --error-logfile - app:app
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload
systemctl enable --now gunicorn
systemctl status gunicorn --no-pager
ss -tulpn | grep 8000Korak 5. Obrnuti proxy Nginx i TLS
Nginx sluša na 80/443 i proksira prema Gunicorn. client_max_body_size važan je za učitavanja. proxy_read_timeout treba odgovarati isteku Gunicorn ili ga premašiti. Kada poslužiteljski blok radi na HTTP, izdajte certifikat Certbotom (ili prebacite prednji dio na Caddy). Isečak ispod samo je HTTP da možete testirati; zatim pokrenite Certbot koji umije urediti datoteku.
cat >/etc/nginx/sites-available/app <<'EOF'
server {
listen 80;
server_name app.example.com;
client_max_body_size 20m;
location /static/ {
alias /srv/app/static/;
}
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 90s;
}
}
EOF
ln -sf /etc/nginx/sites-available/app /etc/nginx/sites-enabled/app
nginx -t && systemctl reload nginx
ufw allow OpenSSH
ufw allow 'Nginx Full'
ufw enable
apt -y install certbot python3-certbot-nginx
certbot --nginx -d app.example.comKorak 6. Statičke datoteke, dopuštenja i specifičnosti Flask/FastAPI
Nginx treba služiti statiku ako možete; brži je od Gunicorn. Django collectstatic, Flask send_from_directory za sićušne aplikacije ili kasnije CDN. appuser mora moći čitati stablo. Ako koristite FastAPI, instalirajte uvicorn[standard] u venv i promijenite ExecStart na UvicornWorker. Ako koristite UNIX utičnice umjesto TCP, usmjerite proxy_pass na utičnicu i uskladite dopuštenja da www-data može pisati na nju.
# FastAPI ExecStart example:
# ExecStart=/srv/app/venv/bin/gunicorn -k uvicorn.workers.UvicornWorker --workers 2 --bind 127.0.0.1:8000 app:app
# Unix socket variant:
# --bind unix:/run/gunicorn/app.sock
# Nginx: proxy_pass http://unix:/run/gunicorn/app.sock:
chown -R appuser:appuser /srv/appRadnici, memorija i ponovno učitavanje bez prekida
Sync Gunicorn radnici jednostavni su i dovoljni za lake API zahtjev/odgovor. Ako treba mnogo istodobnih sporih I/O čekanja, razmotrite gevent ili ASGI radnika — mjerite, ne nagađajte. Svaki radnik učitava aplikaciju; RAM ≈ broj radnika puta RSS aplikacije. VPS od 2 GB s 8 radnika aplikacije od 300 MB otići će u swap i osjećati se „nasumično sporo“. systemctl reload gunicorn (HUP) može restartirati radnike s novim kodom ako ste rasporedili datoteke na mjestu; puni restart jasniji je kada se mijenjaju ovisnosti.
# After git pull / rsync of new code:
sudo -u appuser -H /srv/app/venv/bin/pip install -r /srv/app/requirements.txt
systemctl restart gunicorn
curl -I https://app.example.com/healthRješavanje 502 i tihih padova
502 znači da Nginx nije dobio važeći odgovor od upstream. Prva naredba je journalctl -u gunicorn -e. Česti uzroci: pogrešno ime module:app, nedostaje ključ u .env, Postgres ne radi, vezan na 127.0.0.1 a Nginx na drugom hostu, SELinux (rijetko na Ubuntu) ili aplikacija sluša samo na IPv6. 504 je istekao. Petlje 301 događaju se kada aplikacija preusmjerava na HTTP dok se X-Forwarded-Proto ignorira.
- systemctl status gunicorn — je li active?
- journalctl -u gunicorn -n 100 — ImportError, nedostaje env, baza
- curl -v http://127.0.0.1:8000/ s VPS — ako ovo ne uspije, Nginx je nedužan
- nginx -t i error.log — upstream prematurely closed connection
- ss -tulpn | grep 8000 — nitko ne sluša
- Disk pun — radnici padaju na misteriozne načine
Sigurnost
Aplikacija se nikad ne veže javno. Tajne ostaju u .env. Krpite venv i OS. Ne pokrećite Gunicorn kao root. Ako obrađujete prijave, postavite kolačiće sesije Secure i SameSite i podesite okvir da vjeruje X-Forwarded-Proto samo od Nginxa. Ograničite brzinu ruta za prijavu u Nginxu ili u aplikaciji.
- vezivanje na 127.0.0.1 ili unix utičnicu
- chmod 600 .env
- User= ne-root u systemd
- TLS preko Certbot ili Caddy
- Isključite debug način i auto-ponovno učitavanje u produkciji
Savjeti
- Dodajte rutu /health koja provjerava povezanost s bazom za Compose i uravnoteživače opterećenja
- Šaljite statičke resurse s cache-control zaglavljem u Nginxu
- Koristite posebnog radnika ili red (Redis + systemd) za e-poštu i teške poslove
- Pričvrstite verzije gunicorn i uvicorn u requirements.txt
- Napravite snimku prije prvog produkcijskog prebacivanja
Python aplikacija na VPS spremna je za produkciju kada radi pod Gunicorn kao systemd usluga, veže se samo na localhost i dostupna je kroz Nginx ili Caddy s TLS. Stavite tajne u EnvironmentFile, dimenzionirajte radnike prema RAM a ne prema formuli s bloga, i 502 prvo uklanjajte iz Gunicorn dnevnika. Kada je ovaj put dokumentiran za vaš repozitorij, svako kasnije raspoređivanje rsync je ili git pull, pip install i systemctl restart gunicorn.