Перейти к содержимому

Python-приложение: gunicorn и systemd

Развернуть Django, Flask или FastAPI в виртуальном окружении, запустить через gunicorn как службу systemd и опубликовать за Nginx.

Уровень
Средний
Время чтения
3 мин чтения
Обновлено
Проверено на
Ubuntu 22.04, Ubuntu 24.04, Debian 12
Содержание
  1. Окружение
  2. Пробный запуск
  3. Служба systemd
  4. Nginx
  5. Обновление кода
  6. Частые ошибки

Схема: код в /srv/app, зависимости в виртуальном окружении, gunicorn слушает Unix-сокет, systemd следит за процессом, Nginx принимает запросы из интернета.

Окружение

bash
$ apt update$ apt install -y python3-venv python3-dev build-essential$ adduser --system --group --home /srv/app app$ cd /srv/app$ sudo -u app python3 -m venv .venv$ sudo -u app .venv/bin/pip install --upgrade pip$ sudo -u app .venv/bin/pip install -r requirements.txt gunicorn

Пробный запуск

Точка входа зависит от фреймворка: для Django — проект.wsgi:application, для Flask — модуль:app, для FastAPI — модуль:app с воркером uvicorn.

bash
$ sudo -u app .venv/bin/gunicorn --bind 127.0.0.1:8000 myproject.wsgi:application$ # FastAPI:$ # sudo -u app .venv/bin/pip install "uvicorn[standard]"$ # sudo -u app .venv/bin/gunicorn -k uvicorn.workers.UvicornWorker --bind 127.0.0.1:8000 main:app

Служба systemd

/etc/systemd/system/app.service
[Unit]Description=My Python app (gunicorn)After=network.target[Service]User=appGroup=www-dataWorkingDirectory=/srv/appEnvironmentFile=/srv/app/.envRuntimeDirectory=appExecStart=/srv/app/.venv/bin/gunicorn --workers 3 --bind unix:/run/app/gunicorn.sock myproject.wsgi:applicationExecReload=/bin/kill -s HUP $MAINPIDRestart=on-failure[Install]WantedBy=multi-user.target

RuntimeDirectory создаёт /run/app при старте службы. Группа www-data нужна, чтобы Nginx мог подключиться к сокету. Число воркеров для начала — 2 × число ядер + 1, дальше подбирайте по нагрузке и памяти.

bash
$ chmod 600 /srv/app/.env$ systemctl daemon-reload$ systemctl enable --now app$ systemctl status app --no-pager

Nginx

/etc/nginx/sites-available/example.com
server {    listen 80;    server_name example.com;    location /static/ {        alias /srv/app/static/;    }    location / {        proxy_pass http://unix:/run/app/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;    }}
bash
$ ln -s /etc/nginx/sites-available/example.com /etc/nginx/sites-enabled/$ nginx -t && systemctl reload nginx$ certbot --nginx -d example.com

Обновление кода

bash
$ cd /srv/app$ sudo -u app git pull$ sudo -u app .venv/bin/pip install -r requirements.txt$ systemctl reload app

reload отправляет gunicorn сигнал HUP: воркеры перезапускаются по очереди, соединения не обрываются.

Частые ошибки

  • 502 и «Permission denied» к сокету в журнале Nginx — у службы не та группа или сокет создаётся не там, куда смотрит proxy_pass.
  • Служба падает сразу после старта — смотрите journalctl -u app -n 50: обычно ошибка импорта или не найден .env.
  • Статика Django не отдаётся — не выполнен collectstatic или STATIC_ROOT не совпадает с alias в Nginx.

Дочитайте до конца — статья засчитается в обучении автоматически.

  • Python
  • gunicorn
  • Django
  • Flask
  • FastAPI
  • systemd

Статья помогла?