Как развернуть FastAPI-приложение на VPS с PostgreSQL и Nginx

Валерий Волков

Время прочтения 8 минут

FastAPI-приложение можно развернуть на VPS как полноценный production-сервис: установить Python и зависимости, подключить PostgreSQL, настроить миграции, запустить приложение через Gunicorn/Uvicorn и оформить его как службу systemd. Nginx будет работать как reverse proxy и принимать внешние HTTP/HTTPS-запросы, а SSL-сертификат можно выпустить через Let’s Encrypt.

В этом руководстве развернем небольшой FastAPI API, добавим health endpoint и Swagger UI, настроим хранение секретов, работу с PostgreSQL, просмотр логов и перезапуск приложения после обновления кода. Использовать Docker и подобные средства контейнеризации мы не будем, пойдём по старинке - это поможет лучше понять, как работает приложение, reverse proxy, БД и вообще система.

Подготовка VPS

Для развертывания FastAPI понадобится VPS под управлением Linux с доступом по SSH. В примере используется Ubuntu, а приложение будет работать вместе с PostgreSQL и Nginx.

Подключение к серверу по SSH

Подключитесь к VPS по SSH. В Windows для этого можно использовать PowerShell или Windows Terminal: ssh root@203.0.113.10

При первом подключении подтвердите добавление ключа сервера в доверенные, введя yes, а затем укажите пароль пользователя root.

После успешной авторизации появится командная строка удаленного сервера.

Обновление системы и установка Python, PostgreSQL, Nginx

Сначала обновите индекс пакетов и установленные компоненты: sudo apt update && sudo apt upgrade -y

Затем установите Python, инструменты для создания виртуального окружения, PostgreSQL, Nginx и дополнительные пакеты, которые понадобятся приложению:

sudo apt install -y python3 python3-pip python3-venv python3-dev postgresql postgresql-contrib nginx libpq-dev

PostgreSQL доступен непосредственно из репозиториев Ubuntu и после установки может работать как системная служба.

Создание FastAPI-приложения

Приложение разместим в отдельном каталоге и изолируем его Python-зависимости от системных пакетов с помощью виртуального окружения venv. Такой подход позволяет устанавливать необходимые версии библиотек непосредственно для проекта, без влияния на всю систему.

Создание проекта и виртуального окружения

Создайте каталог приложения и перейдите в него:

sudo mkdir -p /var/www/fastapi-app

sudo chown -R $USER:$USER /var/www/fastapi-app

cd /var/www/fastapi-app

Создайте виртуальное окружение: python3 -m venv venv

Активируйте его: source venv/bin/activate

После активации в начале строки терминала появится (venv).

Установка FastAPI, Uvicorn, Gunicorn и зависимостей

Обновите pip: pip install --upgrade pip

Установите FastAPI, ASGI-сервер Uvicorn, Gunicorn, драйвер PostgreSQL, SQLAlchemy и Alembic: pip install fastapi uvicorn gunicorn sqlalchemy psycopg2-binary alembic python-dotenv

Сохраним список установленных зависимостей: pip freeze > requirements.txt

Файл requirements.txt позволит впоследствии установить те же зависимости после переноса или повторного развертывания приложения.

Создание API и health endpoint

Создайте основной файл приложения: nano main.py

Добавьте следующий код:

from fastapi import FastAPI

app = FastAPI(

    title="FastAPI VPS Example",

    version="1.0.0"

)

@app.get("/")

def root():

    return {"message": "FastAPI is running"}

@app.get("/health")

def health():

    return {"status": "ok"}

Сохраните файл сочетанием Ctrl+O, нажмите Enter, затем закройте редактор через Ctrl+X.

Для первой проверки запустите приложение через Uvicorn: uvicorn main:app --host 0.0.0.0 --port 8000

Uvicorn запустит ASGI-приложение на порту 8000. Для production-развертывания FastAPI поддерживает запуск нескольких рабочих процессов, а далее в руководстве управление процессом будет передано systemd.

В другом терминале или непосредственно на сервере можно проверить health endpoint: curl http://127.0.0.1:8000/health

В ответ API должен вернуть: {"status":"ok"}

Настройка PostgreSQL

FastAPI-приложению потребуется отдельная база данных и пользователь PostgreSQL. Параметры подключения вынесем из исходного кода в файл .env.

Создание базы данных и пользователя

Переключитесь на системного пользователя PostgreSQL и откройте консоль psql: sudo -u postgres psql

Создайте пользователя приложения с паролем: CREATE USER fastapi_user WITH PASSWORD 'StrongPassword123!';

Создайте базу данных и назначьте нового пользователя ее владельцем: CREATE DATABASE fastapi_db OWNER fastapi_user;

Команды CREATE ROLE/CREATE USER и CREATE DATABASE используются PostgreSQL для создания ролей и отдельных баз данных.

Выйдите из консоли PostgreSQL: \q

Проверить подключение можно командой: psql -h 127.0.0.1 -U fastapi_user -d fastapi_db

Введите созданный ранее пароль. После успешного подключения выйдите через: \q

Подключение FastAPI к PostgreSQL

Перейдите в каталог приложения: cd /var/www/fastapi-app

Создайте файл database.py: nano database.py

Добавьте конфигурацию SQLAlchemy:

import os

from dotenv import load_dotenv

from sqlalchemy import create_engine

from sqlalchemy.orm import declarative_base, sessionmaker

load_dotenv()

DATABASE_URL = os.getenv("DATABASE_URL")

engine = create_engine(DATABASE_URL)

SessionLocal = sessionmaker(

    autocommit=False,

    autoflush=False,

    bind=engine

)

Base = declarative_base()

SQLAlchemy создает подключение через URL базы данных; для PostgreSQL с драйвером psycopg2 используется формат postgresql+psycopg2://....

Хранение секретов в .env

Создайте файл .env: nano .env

Добавьте строку подключения: DATABASE_URL=postgresql+psycopg2://fastapi_user:StrongPassword123!@127.0.0.1:5432/fastapi_db

Ограничьте доступ к файлу: chmod 600 .env

Проверим подключение к базе из виртуального окружения:

source venv/bin/activate

python -c "from database import engine; conn = engine.connect(); print('PostgreSQL connection OK'); conn.close()"

При успешном подключении появится сообщение: PostgreSQL connection OK

Настройка миграций

Для управления структурой базы данных воспользуемся Alembic. Он позволяет хранить изменения схемы в виде последовательных миграций и применять их при развертывании или обновлении приложения.

Установка и настройка Alembic

Alembic уже был установлен вместе с зависимостями приложения. Находясь в каталоге проекта с активированным виртуальным окружением, создайте его конфигурацию: alembic init migrations

Команда создаст каталог migrations и файл alembic.ini.

Создадим простую модель, для которой затем сформируем миграцию: nano models.py

Добавьте:

from sqlalchemy import Column, Integer, String

from database import Base

class Item(Base):

    __tablename__ = "items"

    id = Column(Integer, primary_key=True)

    name = Column(String(255), nullable=False)

Теперь откройте файл: nano migrations/env.py

Найдите строку: target_metadata = None

И замените ее на:

from database import Base

import models

target_metadata = Base.metadata

Также добавьте в начало файла:

import os

from dotenv import load_dotenv

load_dotenv()

После строки config = context.config добавьте config.set_main_option("sqlalchemy.url", os.environ["DATABASE_URL"])

Таким образом Alembic будет использовать ту же строку подключения из .env, что и приложение.

Создание и применение миграции

Создайте первую миграцию: alembic revision --autogenerate -m "create items table"

Параметр --autogenerate позволяет Alembic сравнить метаданные SQLAlchemy с текущей схемой базы данных и подготовить изменения для файла миграции.

Примените миграцию: alembic upgrade head

Проверим текущее состояние: alembic current

Затем можно убедиться, что таблица появилась в PostgreSQL: psql -h 127.0.0.1 -U fastapi_user -d fastapi_db -c "\dt"

В списке должны присутствовать таблицы items и alembic_version.

Проверка FastAPI

Перед настройкой постоянного запуска приложения убедимся, что FastAPI корректно работает через Uvicorn и созданные endpoints доступны локально.

Запуск приложения через Uvicorn

Перейдите в каталог проекта и активируйте виртуальное окружение:

cd /var/www/fastapi-app

source venv/bin/activate

Запустите приложение: uvicorn main:app --host 127.0.0.1 --port 8000

Здесь main — имя файла main.py, а app — созданный в нем объект FastAPI. Для ASGI-приложений FastAPI может работать через Uvicorn как отдельный серверный процесс.

После запуска в терминале появится сообщение о том, что Uvicorn принимает подключения на 127.0.0.1:8000.

Проверка health endpoint и Swagger UI

Не останавливая Uvicorn, откройте второй SSH-сеанс и выполните: curl http://127.0.0.1:8000/health

В ответ должно вернуться: {"status":"ok"}

Также проверим корневой endpoint: curl http://127.0.0.1:8000/

Ответ: {"message":"FastAPI is running"}

FastAPI автоматически формирует интерактивную документацию Swagger UI. Пока приложение доступно только локально, проверить ее с самого сервера можно запросом: curl -I http://127.0.0.1:8000/docs

Полноценный интерфейс Swagger UI откроем в браузере после настройки Nginx и доступа по домену.

После проверки остановите Uvicorn сочетанием Ctrl+C.

Запуск FastAPI через Gunicorn и systemd

Для постоянной работы приложение запустим через Gunicorn с отдельным Uvicorn Worker, а управление процессом передадим systemd. Это позволит автоматически запускать API вместе с сервером и перезапускать его после сбоев.

Настройка Gunicorn с Uvicorn Worker

Установите пакет uvicorn-worker:

source /var/www/fastapi-app/venv/bin/activate

pip install uvicorn-worker

pip freeze > requirements.txt

Отдельный пакет uvicorn-worker предоставляет ASGI-воркер для запуска приложений через Gunicorn. Его использование позволяет оставить управление процессами Gunicorn, а обработку ASGI-приложения передать Uvicorn.

Проверьте запуск приложения:

gunicorn main:app \

  --workers 2 \

  --worker-class uvicorn_worker.UvicornWorker \

  --bind 127.0.0.1:8000

Параметр --workers 2 запускает два рабочих процесса. Несколько воркеров позволяют использовать несколько процессов приложения одновременно.

В другом SSH-сеансе выполните: curl http://127.0.0.1:8000/health

После успешной проверки остановите Gunicorn сочетанием Ctrl+C.

Создание systemd-сервиса

Создайте unit-файл: sudo nano /etc/systemd/system/fastapi.service

Добавьте:

[Unit]

Description=FastAPI application

After=network.target postgresql.service

[Service]

User=root

Group=www-data

WorkingDirectory=/var/www/fastapi-app

EnvironmentFile=/var/www/fastapi-app/.env

ExecStart=/var/www/fastapi-app/venv/bin/gunicorn main:app \

    --workers 2 \

    --worker-class uvicorn_worker.UvicornWorker \

    --bind 127.0.0.1:8000

Restart=always

RestartSec=5

[Install]

WantedBy=multi-user.target

Приложение будет принимать запросы только на локальном адресе 127.0.0.1:8000. Внешний доступ позднее будет организован через Nginx.

Запуск и проверка статуса сервиса

Перечитайте конфигурацию systemd: sudo systemctl daemon-reload

Добавьте сервис в автозагрузку: sudo systemctl enable fastapi

Запустите его: sudo systemctl start fastapi

Проверьте состояние: sudo systemctl status fastapi --no-pager

При нормальном запуске сервис должен находиться в состоянии: Active: active (running)

Дополнительно проверим API: curl http://127.0.0.1:8000/health

Ответ: {"status":"ok"}

Настройка Nginx

FastAPI уже работает как локальный сервис на 127.0.0.1:8000, но напрямую этот порт открывать в интернет не стоит и не требуется. Перед приложением настроим Nginx, который будет принимать внешние запросы и передавать их FastAPI как reverse proxy. Такой вариант соответствует типичной схеме размещения FastAPI за прокси-сервером.

Создание reverse proxy для FastAPI

Создайте отдельный конфигурационный файл сайта: sudo nano /etc/nginx/sites-available/fastapi

Добавьте конфигурацию:

server {

    listen 80;

    listen [::]:80;

    server_name api.example.com;

    location / {

        proxy_pass http://127.0.0.1:8000;

        proxy_http_version 1.1;

        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_pass передает запросы от Nginx локальному серверу FastAPI.

Активируйте конфигурацию: sudo ln -s /etc/nginx/sites-available/fastapi /etc/nginx/sites-enabled/fastapi

Если стандартный сайт Nginx больше не используется, отключите его: sudo rm -f /etc/nginx/sites-enabled/default

Проверьте конфигурацию: sudo nginx -t

При отсутствии ошибок примените изменения: sudo systemctl reload nginx

Проверка API через домен

До этого момента DNS-запись домена должна указывать на публичный IP VPS. Например, для api.example.com создается A-запись на адрес сервера.

После обновления DNS проверьте API: curl http://api.example.com/health

Ожидаемый ответ: {"status":"ok"}

В браузере также можно открыть: http://api.example.com/docs

Если проксирование настроено корректно, загрузится Swagger UI FastAPI.

Настройка HTTPS

Следующий этап — включение HTTPS. TLS-соединение будет терминироваться на Nginx, а FastAPI продолжит работать локально за reverse proxy. Такая схема позволяет не настраивать сертификаты непосредственно внутри приложения.

Установка Certbot

Установите Certbot и плагин для Nginx:

sudo apt update

sudo apt install -y certbot python3-certbot-nginx

Убедитесь, что Certbot доступен: certbot --version

Получение SSL-сертификата Let’s Encrypt

Запустите Certbot для домена приложения: sudo certbot --nginx -d api.example.com

Укажите адрес электронной почты, примите условия использования и выберите перенаправление HTTP-трафика на HTTPS, если Certbot предложит соответствующий вариант.

Плагин Nginx позволяет Certbot получить сертификат и автоматически изменить конфигурацию веб-сервера для работы через HTTPS.

После выпуска сертификата проверьте конфигурацию: sudo nginx -t

Затем проверьте механизм автоматического продления: sudo certbot renew --dry-run

Проверка API по HTTPS

Проверьте health endpoint: curl https://api.example.com/health

Ожидаемый ответ: {"status":"ok"}

Теперь Swagger UI доступен по защищенному адресу: https://api.example.com/docs

Логи и обслуживание приложения

При эксплуатации API важно иметь возможность быстро проверить состояние приложения и определить причину ошибки. Для этого можно использовать журнал systemd и стандартные журналы Nginx.

Просмотр логов FastAPI через journalctl

Поскольку приложение работает как systemd-сервис, его вывод можно просматривать через journalctl. Эта команда используется для чтения записей системного журнала systemd.

Для просмотра последних записей FastAPI выполните: sudo journalctl -u fastapi -n 50 --no-pager

Для просмотра журнала в реальном времени: sudo journalctl -u fastapi -f

Здесь будут отображаться сообщения Gunicorn, Uvicorn, ошибки запуска приложения и другая информация, записываемая сервисом.

Выйти из режима просмотра в реальном времени можно сочетанием Ctrl+C.

Просмотр логов Nginx

Журнал входящих запросов Nginx можно посмотреть командой: sudo tail -n 50 /var/log/nginx/access.log

Ошибки Nginx записываются отдельно: sudo tail -n 50 /var/log/nginx/error.log

Для наблюдения за ошибками в реальном времени: sudo tail -f /var/log/nginx/error.log

Обновление FastAPI-приложения

После изменения исходного кода приложение необходимо перезапустить, чтобы рабочие процессы Gunicorn загрузили новую версию. Если обновление затрагивает структуру базы данных, перед перезапуском также следует применить новые миграции.

Обновление кода и применение миграций

Перейдите в каталог проекта: cd /var/www/fastapi-app

Активируйте виртуальное окружение: source venv/bin/activate

После замены или получения новой версии исходного кода установите зависимости из requirements.txt, если они изменились: pip install -r requirements.txt

Если новая версия приложения содержит миграции Alembic, примените их: alembic upgrade head

Текущую примененную миграцию можно проверить командой: alembic current

Перезапуск systemd-сервиса

Чтобы Gunicorn загрузил обновленную версию приложения, перезапустите сервис: sudo systemctl restart fastapi

Проверьте его состояние: sudo systemctl status fastapi --no-pager

Сервис должен снова находиться в состоянии: Active: active (running)

Проверка приложения после обновления

Проверьте health endpoint через публичный HTTPS-адрес: curl https://api.example.com/health

Ожидаемый ответ: {"status":"ok"}

При необходимости сразу после перезапуска можно проверить журнал приложения: sudo journalctl -u fastapi -n 30 --no-pager

Это позволяет убедиться, что новая версия FastAPI успешно запустилась и не завершилась с ошибкой после обновления.

Заключение

FastAPI-приложение развернуто на VPS и подключено к PostgreSQL. Для управления схемой базы данных используется Alembic, приложение запускается через Gunicorn с Uvicorn Worker и работает как systemd-сервис с автоматическим запуском после перезагрузки сервера.

Nginx принимает внешние запросы и передает их FastAPI через reverse proxy, а Certbot обеспечивает работу API по HTTPS. Такая конфигурация также позволяет централизованно хранить секреты в .env, просматривать логи через journalctl и быстро перезапускать приложение после обновления кода.

FAQ

Зачем FastAPI нужен Nginx?

FastAPI можно запустить напрямую через ASGI-сервер, однако при публичном развертывании Nginx удобно использовать как reverse proxy. Он принимает внешние HTTP- и HTTPS-запросы, работает с TLS-сертификатом и передает запросы локальному приложению. Официальная документация FastAPI также рассматривает развертывание приложения за прокси-сервером.

Где хранить пароль от PostgreSQL и другие секреты?

Пароли, токены и строки подключения не следует размещать непосредственно в исходном коде. В рассмотренной конфигурации они хранятся в .env, доступ к которому ограничен средствами файловой системы Linux. При использовании системы контроля версий такой файл также следует добавить в .gitignore.

Для чего нужны миграции Alembic?

Миграции позволяют последовательно изменять структуру базы данных вместе с развитием приложения. Например, после добавления нового столбца в SQLAlchemy-модель можно создать новую миграцию и применить ее к PostgreSQL вместо ручного изменения таблиц.

Где находится Swagger UI FastAPI?

FastAPI автоматически предоставляет интерактивную документацию Swagger UI. При стандартных настройках после развертывания она доступна по адресу: https://api.example.com/docs

Через Swagger UI можно просматривать доступные endpoints, параметры запросов и отправлять тестовые запросы к API.

Как проверить, работает ли FastAPI после перезапуска сервера?

Проверьте состояние systemd-сервиса: sudo systemctl status fastapi

Затем отправьте запрос к health endpoint: curl https://api.example.com/health

При нормальной работе API вернет: {"status":"ok"}

Как перезапустить FastAPI после изменения кода?

После обновления файлов приложения выполните: sudo systemctl restart fastapi

Если вместе с кодом изменилась структура базы данных, перед перезапуском следует применить подготовленные миграции: alembic upgrade head

Список источников

  1. FastAPI Documentation — Deployment
  2. PostgreSQL Documentation — CREATE DATABASE, CREATE ROLE
  3. Nginx Documentation — ngx_http_proxy_module
  4. Certbot — Nginx Instructions

Подпишитесь на нашу рассылку и получайте статьи и новости

    Ознакомьтесь с другими нашими материалами