Как выложить FastAPI-приложение в интернет

FastAPI-приложение выкладывается в интернет без аренды сервера: загружаете папку с кодом, платформа распознаёт Python по requirements.txt, ставит зависимости и отдаёт публичную HTTPS-ссылку. Решающих деталей три: приложение должно читать порт из переменной PORT, слушать 0.0.0.0 и запускаться через uvicorn, а не через python main.py. Зато FastAPI сам отдаёт интерактивную документацию на /docs — по ней проще всего убедиться, что API действительно живой. Ниже — путь от папки с кодом до рабочей ссылки на Dockbox.

Почему FastAPI-проект по умолчанию тащат на VPS

Привычный сценарий начинается с аренды сервера: поставить Python, собрать виртуальное окружение с зависимостями, придумать, как поднимать uvicorn после падения и перезагрузки, поставить перед ним nginx и выпустить сертификат. Сам FastAPI пишется за вечер — сложно всё, что вокруг него.

Обратный прокси и сертификат. Uvicorn отдаёт обычный HTTP, а наружу нужен HTTPS. Значит, nginx, конфиг с proxy_pass и сертификат, который надо продлевать каждые три месяца.

Автозапуск и перезапуск. Чтобы процесс вернулся в строй после сбоя и перезагрузки, нужен systemd-юнит, а его отладка — отдельный навык, не связанный с вашим кодом.

Оплата независимо от нагрузки. Сервер стоит денег все 30 дней, даже если эндпоинты дёргают раз в сутки.

Платформа деплоя снимает эту часть: вы загружаете код, она находит requirements.txt, ставит пакеты и отдаёт публичную HTTPS-ссылку. Ни сервера, ни nginx, ни ручного сертификата.

Шаг 1. Положите requirements.txt в корень проекта

Файл зависимостей в корне — это и есть признак Python-проекта. Перечислите в нём то, что реально импортирует код, фиксируя версии: минимально это fastapi и uvicorn — сервер, который принимает запросы и передаёт их вашему приложению.

fastapi==0.115.6
uvicorn[standard]==0.34.0

Если приложение ходит в базу или во внешние API, добавьте httpx, sqlalchemy, pydantic-settings — по факту импортов. Папку venv с библиотеками в архив класть не нужно: пакеты ставятся во время сборки. Если рядом лежит ещё и pyproject.toml, оставьте один манифест — с двумя платформа может определить окружение неверно.

Шаг 2. Читайте порт из переменной PORT и слушайте 0.0.0.0

Порт задаёт платформа, а не вы. Значение приходит в переменных окружения, поэтому берите его оттуда, а не пишите число руками. Слушать нужно 0.0.0.0: адрес localhost виден только самому приложению изнутри, и публичная ссылка останется пустой. Жёстко зашитый порт — причина номер один, по которой сборка проходит, а страница потом не открывается.

Так делать не стоит:

uvicorn main:app --host 0.0.0.0 --port 8000

Так — правильно, порт подставляется из окружения:

import os
import uvicorn
if __name__ == "__main__":
    port = int(os.environ["PORT"])
    uvicorn.run("main:app", host="0.0.0.0", port=port)

main:app здесь означает «файл main.py, объект приложения app». Если у вас app/main.py с app = FastAPI(), импорт-строка будет app.main:app.

Шаг 3. Решите, сколько нужно воркеров uvicorn

FastAPI асинхронный, и один воркер обычно держит сотни одновременных запросов — этого хватает большинству API. Флаг --workers поднимает несколько процессов, и каждый из них импортирует приложение целиком, то есть умножает потребление памяти. На тарифе с 2 ГБ RAM четыре воркера с тяжёлыми зависимостями легко упираются в лимит, и контейнер перезапускается по памяти, а не по нагрузке.

uvicorn main:app --host 0.0.0.0 --port $PORT --workers 1

Практическое правило: начинайте с одного воркера и добавляйте следующий только под реальную нагрузку. И не оставляйте в продакшене --reload — он следит за файлами и лишний раз перезапускает процесс.

Шаг 4. Вынесите секреты в переменные окружения

Ключи сторонних сервисов, токены и строку подключения к базе читайте из окружения, а не держите константами в коде:

import os
DATABASE_URL = os.environ["DATABASE_URL"]
API_TOKEN = os.environ["API_TOKEN"]

Код вы почти наверняка зальёте в Git или кому-то покажете, а вместе с ним уедут и секреты. В настройках проекта Dockbox запрашивает такие значения и передаёт их в контейнер, поэтому в архиве и в репозитории они не появляются.

Шаг 5. Загрузите код и получите ссылку

Проект попадает на платформу двумя способами: архивом с исходниками или импортом репозитория GitHub, в том числе приватного. Указывать язык, писать Dockerfile и готовить сборку заранее не нужно — платформа сама видит requirements.txt, ставит Python и пакеты. Статус сборки и логи видны в панели в реальном времени. Когда сборка закончится, вы получите публичную HTTPS-ссылку — она остаётся той же при обновлении кода.

Шаг 6. Проверьте API и автодокументацию

FastAPI генерирует документацию по вашему коду сам, без единой строчки настроек. Откройте <ваша-ссылка>/docs — это Swagger UI со списком всех эндпоинтов, схемами запросов и кнопкой Try it out, которой можно отправить тестовый запрос прямо из браузера. Рядом — /redoc и /openapi.json с машинной схемой для фронтенда и клиентов.

Если /docs открылся и эндпоинты отвечают — API работает в интернете. Полезно добавить лёгкий эндпоинт /health с ответом {"status": "ok"}: по нему видно, что живо всё приложение, а не один эндпоинт.

Сколько это стоит и как работают контейнеры

Ни администрировать сервер, ни следить за процессом не нужно: контейнеры работают постоянно, без ограничения по часам и без «засыпания». Упавший контейнер платформа перезапускает сама, и API возвращается в строй без вашего участия.

Starter — 990 ₽/мес. 1 vCPU, 2 ГБ RAM, один проект. Первый месяц бесплатный. Для одного FastAPI-сервиса этого достаточно, и лимита по времени работы у тарифа нет.

Pro — 2 490 ₽/мес. Больше ресурсов и до пяти проектов — вариант, если у вас несколько API или бэкенд плюс фронтенд.

Team — 4 990 ₽/мес — для команд, которым нужен запас ресурсов и SLA.

Свой Dockerfile поддерживается, но не обязателен. Если он нужен, берите официальный образ Python и не забывайте про порт из окружения:

FROM python:3.12-slim
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
CMD ["sh", "-c", "uvicorn main:app --host 0.0.0.0 --port $PORT"]

Файлы, которые пишет приложение, сохраняются между деплоями только в постоянной папке /data — туда же стоит положить SQLite-базу, если она у вас есть. Всё, что создано рядом с кодом, пересоздаётся при следующей публикации.

Частые вопросы

Приложение собралось, а ссылка возвращает 502 — почему?

Три причины покрывают почти все случаи: приложение слушает localhost вместо 0.0.0.0, порт вписан числом вместо значения из переменной PORT, либо uvicorn запущен не на том объекте приложения (неверная строка вида main:app). Откройте логи запуска в панели — там будет либо строка о старте сервера с портом, либо traceback с причиной.

Сколько воркеров uvicorn ставить для FastAPI?

Для большинства API достаточно одного: FastAPI асинхронный, и один процесс держит сотни одновременных запросов. Каждый дополнительный воркер — отдельный процесс со своей копией приложения и зависимостей, то есть рост потребления RAM. Ориентируйтесь на доступную память.

Обязателен ли Dockerfile для FastAPI-проекта?

Нет. Достаточно requirements.txt в корне — платформа определит Python и соберёт окружение сама. Dockerfile нужен, если вы хотите зафиксировать системные пакеты, нестандартную версию Python или шаги сборки. Если Dockerfile есть, он главнее автоопределения.

Ошибка «KeyError: 'PORT'» при старте — что делать?

Приложение читает переменную PORT, которой нет в окружении. На платформе она подставляется автоматически, поэтому чаще всего проблема в коде, который выполняется до инициализации сервера. Используйте os.environ.get("PORT", 8000) для локальной отладки, но в продакшене полагайтесь на значение платформы.

Сохранится ли SQLite-база между деплоями?

Только если файл лежит в постоянной папке /data. Файл, созданный рядом с кодом, исчезнет при следующей публикации, потому что образ контейнера собирается заново. Для серьёзных данных лучше внешняя база, а /data подойдёт для небольших проектов и загруженных пользователями файлов.