Застосунок на Python: gunicorn і systemd
Запуск Django, Flask або FastAPI на VPS: віртуальне середовище, gunicorn із сокетом, служба systemd і вибір кількості воркерів для вашого тарифу.
Оновлено 23 серпня 2026 р.
Вбудований сервер розробки (manage.py runserver, flask run) не призначений для продакшен-навантаження. На VPS ви встановлюєте gunicorn або uvicorn, а вебсервер обслуговує їх ззовні.
Середовище
Ніколи не встановлюйте пакети проєкту в системний Python — оновлення системи зламає застосунок.
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
Для FastAPI додатково встановіть uvicorn[standard] — gunicorn запускає його як клас воркера.
Служба
/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
Для FastAPI замініть рядок запуску на --worker-class uvicorn.workers.UvicornWorker app.main:app.
systemctl daemon-reload
systemctl enable --now myapp
journalctl -u myapp -f
RuntimeDirectory=myapp створює /run/myapp з потрібними правами під час кожного запуску — інакше сокету нікуди подітися.
Скільки воркерів
Звична формула — 2 × cores + 1, але вона впирається в обмеження пам'яті: кожен воркер Django використовує 80–200 МБ.
| Тариф | Ядра | Воркери |
|---|---|---|
| VDS-1 | 1 | 2 |
| VDS-2 | 2 | 3 |
| VDS-3 | 4 | 5 |
| VDS-4 | 6 | 9 |
Якщо застосунок багато часу чекає на мережу та базу даних, додайте --threads 2 замість збільшення кількості процесів.
Вебсервер
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 віддавайте напряму через Nginx після їх збору: collectstatic. Передача їх через Python додає зайве навантаження.
Типові помилки
| Симптом | Причина |
|---|---|
502 і connect() to unix:... failed (13) | Nginx не має прав на сокет — задайте --umask 007 і спільну групу |
ModuleNotFoundError | Запуск із системним Python замість venv |
DisallowedHost у Django | Домен не додано до ALLOWED_HOSTS |
| Воркери вбиває таймаут | Довгий запит — збільште --timeout, перенесіть важку роботу в чергу |
| Усе зупинилося після релізу | Ви забули systemctl restart myapp — код у пам'яті сам не оновлюється |
Тримайте секрети в
EnvironmentFileз правами600, а не вsettings.py. Файл налаштувань рано чи пізно потрапить до репозиторію.