FastAPI за Nginx: /docs открывается, а openapi.json возвращает 404
Приложение успешно работает на localhost:8000/docs. Снаружи его разместили под example.com/api, и страница Swagger вроде бы открылась. Но вместо методов появилась ошибка загрузки схемы. Обычно дальше начинают менять CORS, хотя проблема возникает ещё до вызова API: браузер скачивает openapi.json не по тому адресу.
Здесь есть два пути. Пользователь видит внешний /api/docs. Прокси может убрать /api и передать приложению /docs. FastAPI нужно знать об этом внешнем префиксе, чтобы построить ссылки для браузера.
Одна согласованная схема маршрутов
Пример для Nginx, который работает на том же сервере и передаёт запросы локальному Uvicorn:
location /api/ {
proxy_pass http://127.0.0.1:8000/;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Proto $scheme;
}
Завершающий слеш в proxy_pass здесь важен: префикс location заменяется на /, и внешний /api/docs приходит как /docs. В FastAPI задаём root_path:
from fastapi import FastAPI
app = FastAPI(root_path="/api")
@app.get("/items")
def items():
return [{"id": 1}]
Маршрут объявлен как /items. Не добавляйте /api ещё раз в каждый декоратор только потому, что его видит внешний клиент. Установка зависимостей: python -m pip install fastapi uvicorn; локальный запуск — python -m uvicorn main:app --host 127.0.0.1.
Проверка от браузера к приложению
Откройте инструменты разработчика, вкладку Network, затем /api/docs. Посмотрите точный URL неудачного запроса схемы. В этой схеме нужен /api/openapi.json с ответом 200. После загрузки схемы проверьте вызов /api/items через Swagger и отдельным HTTP-запросом.
Если браузер просит /openapi.json, приложение не учло внешний префикс. Если просит /api/api/openapi.json, префикс, вероятно, добавили дважды. Если правильный внешний путь даёт 404, проверьте, что именно прокси передаёт upstream.
Префикс и HTTPS — разные настройки
root_path сообщает о месте приложения под внешним путём. Протокол HTTPS и исходный адрес клиента передаются через proxy-заголовки и требуют доверия к вашему прокси. Не разрешайте произвольным внешним клиентам подменять эти данные: ограничьте доступ к upstream и настройте доверенные адреса.
Если прокси находится в контейнере, 127.0.0.1 внутри него указывает на сам контейнер. Для Compose понадобится адрес сервиса приложения в общей сети. Это отдельная настройка от root_path.
Более подробно изменение URI разобрано в статье про слеш в proxy_pass.
Собрать следующий этап проекта
Хотите собрать API целиком, а не останавливаться на отдельном обработчике? На бесплатном курсе FastAPI вы сделаете сервис с базой, регистрацией, проверкой прав и тестами. Это проект, который можно развивать дальше и показывать вместе с исходниками.
Посмотреть программу: FastAPI для начинающих: API с базой данных и тестами
Проверить детали: FastAPI за прокси, Nginx proxy_pass.
Продолжить на практике
- FastAPI для начинающих: API с базой данных и тестами ↗
Соберёте свой первый полноценный backend на FastAPI: с базой данных, регистрацией, JWT-авторизацией и автотестами. 34 коротких урока и 140 заданий с проверкой — бесплатно.
- DevOps-инженер с нуля: полный курс ↗
Практический курс по DevOps для начинающих: от настройки Linux и сетей до сборки контейнеров, автоматизации в GitLab CI/CD, развёртывания в Kubernetes, мониторинга и восстановления данных на собственном компьютере.
