Python aplikacija: gunicorn i systemd
Pokretanje Django, Flask ili FastAPI aplikacije na VDS-u: virtuelno okruženje, gunicorn sa socket-om, systemd servis i izbor broja workera prema tvom tieru.
Ažurirano 23. avgust 2026.
Ugrađeni razvojni server (manage.py runserver, flask run) nije napravljen za produkciono opterećenje. Na VPS-u instaliraš gunicorn ili uvicorn, a veb server ih poslužuje prema spolja.
Okruženje
Nikad ne instaliraj pakete projekta u sistemski Python — sistemsko ažuriranje će pokvariti aplikaciju.
apt install -y python3 python3-venv python3-pip
useradd -r -m -d /srv/app -s /usr/sbin/nologin appuser
sudo -u appuser python3 -m venv /srv/app/venv
sudo -u appuser /srv/app/venv/bin/pip install -r /srv/app/requirements.txt
sudo -u appuser /srv/app/venv/bin/pip install gunicorn
Za FastAPI dodatno instaliraj uvicorn[standard] — gunicorn ga pokreće kao worker klasu.
Servis
/etc/systemd/system/myapp.service:
[Unit]
Description=Python app
After=network-online.target postgresql.service
[Service]
User=appuser
WorkingDirectory=/srv/app
EnvironmentFile=/srv/app/.env
ExecStart=/srv/app/venv/bin/gunicorn \
--workers 3 \
--bind unix:/run/myapp/gunicorn.sock \
--access-logfile - \
myproject.wsgi:application
RuntimeDirectory=myapp
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target
Za FastAPI zameni liniju za pokretanje sa --worker-class uvicorn.workers.UvicornWorker app.main:app.
systemctl daemon-reload
systemctl enable --now myapp
journalctl -u myapp -f
RuntimeDirectory=myapp pravi /run/myapp sa potrebnim dozvolama pri svakom pokretanju — inače nema gde da se smesti socket.
Koliko workera
Uobičajena formula je 2 × cores + 1, ali se sudara sa ograničenjem memorije: svaki Django worker koristi 80–200 MB.
| Paket | Jezgra | Workeri |
|---|---|---|
| VDS-1 | 1 | 2 |
| VDS-2 | 2 | 3 |
| VDS-3 | 4 | 5 |
| VDS-4 | 6 | 9 |
Ako aplikacija provodi mnogo vremena čekajući na mrežu i bazu, dodaj --threads 2 umesto povećanja broja procesa.
Veb server
location / {
proxy_pass http://unix:/run/myapp/gunicorn.sock;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
location /static/ { alias /srv/app/static/; }
Django statičke fajlove poslužuj direktno preko Nginx-a nakon što ih sakupiš: collectstatic. Propuštanje kroz Python dodaje nepotrebno opterećenje.
Česte greške
| Simptom | Uzrok |
|---|---|
502 i connect() to unix:... failed (13) | Nginx nema dozvole za socket — postavi --umask 007 i zajedničku grupu |
ModuleNotFoundError | Pokretanje sa sistemskim Python-om umesto iz venv |
DisallowedHost u Django-u | Domen nije dodat u ALLOWED_HOSTS |
| Workere ubija timeout | Dug zahtev — povećaj --timeout, prebaci teške poslove u red čekanja |
| Sve se zaustavilo posle izdanja | Zaboravio si systemctl restart myapp — kod u memoriji se ne ažurira sam |
Tajne drži u
EnvironmentFilesa dozvolama600, ne usettings.py. Fajl sa podešavanjima će pre ili kasnije završiti u repozitorijumu.