Uvicorn: ASGI-сервер для FastAPI
Что такое Uvicorn и ASGI, как запустить FastAPI командой uvicorn main:app --reload, параметры host, port и workers, uvicorn.run() и Uvicorn против Gunicorn.
Содержание · 10 разделов
- Что такое ASGI и зачем нужен Uvicorn
- Установка: uvicorn и uvicorn[standard]
- Запуск: uvicorn main:app —reload
- Параметры командной строки
- Запуск из кода: uvicorn.run()
- Uvicorn и Django
- Uvicorn vs Gunicorn
- Gunicorn с Uvicorn worker
- Uvicorn в Docker и Kubernetes
- Частые ошибки
- «uvicorn не является внутренней или внешней командой»
- Error loading ASGI app. Could not import module “main”
- Attribute “app” not found in module “main”
- Порт уже занят
- Изменения в коде не подхватываются
- Частые вопросы
- Как включить HTTPS в Uvicorn?
- Как найти и остановить процесс, который занял порт?
- Как отключить или настроить логи запросов?
- Чем можно заменить Uvicorn?
- Итог
Uvicorn — это ASGI-сервер для Python: он принимает HTTP- и WebSocket-соединения и передаёт запросы асинхронному приложению — FastAPI, Starlette или Django в режиме ASGI. Сам FastAPI сетевых соединений не слушает, поэтому без сервера вроде Uvicorn приложение не запустить. Быстрый ответ, как запустить FastAPI через Uvicorn:
pip install "uvicorn[standard]"
uvicorn main:app --reload
Ниже разберём, что такое ASGI, как устроена команда uvicorn main:app, какие параметры нужны в разработке и в продакшне, как запускать сервер из кода через uvicorn.run(), чем Uvicorn отличается от Gunicorn и как исправить частые ошибки запуска. Примеры проверены на Uvicorn 0.54, FastAPI 0.143 и Python 3.12.
Что такое ASGI и зачем нужен Uvicorn
Веб-приложение на Python не работает с сокетами напрямую. Между сетью и вашим кодом стоит сервер, а договорённость о том, как сервер вызывает приложение, называется интерфейсом:
- WSGI — синхронный стандарт: один запрос занимает поток или процесс до конца обработки. Серверы: Gunicorn, uWSGI. Фреймворки: Flask, классический Django.
- ASGI — асинхронный преемник WSGI: приложение — это корутина, и один процесс может обслуживать тысячи одновременных соединений, пока запросы ждут базу или внешний API. ASGI поддерживает WebSocket и долгие соединения. Серверы: Uvicorn, Hypercorn, Daphne. Фреймворки: FastAPI, Starlette, Django (через
asgi.py).
ASGI-приложение — это асинхронная функция с тремя аргументами. Так выглядит приложение вообще без фреймворка:
# raw.py
async def app(scope, receive, send):
assert scope["type"] == "http"
await send({
"type": "http.response.start",
"status": 200,
"headers": [(b"content-type", b"text/plain; charset=utf-8")],
})
await send({"type": "http.response.body", "body": "Привет от ASGI".encode()})
uvicorn raw:app
curl http://127.0.0.1:8000/
# Привет от ASGI
Uvicorn разбирает HTTP, формирует scope (метод, путь, заголовки) и вызывает app. FastAPI делает то же самое, только скрывает эту механику за декораторами @app.get() и Pydantic-моделями.
Установка: uvicorn и uvicorn[standard]
Устанавливайте сервер в виртуальное окружение проекта. Есть два варианта:
pip install uvicorn # минимальный: чистый Python
pip install "uvicorn[standard]" # с ускорителями и автоперезагрузкой
Набор standard добавляет uvloop (быстрый цикл событий; не устанавливается на Windows), httptools (быстрый HTTP-парсер), websockets, watchfiles (отслеживание изменений для --reload), python-dotenv (для --env-file) и pyyaml (для конфигурации логов в YAML). Кавычки вокруг "uvicorn[standard]" нужны в zsh и не мешают в других оболочках.
Если вы ставили FastAPI командой pip install "fastapi[standard]", Uvicorn со всеми ускорителями уже установлен. Пошаговая установка для Windows, macOS и Linux — в статье как установить и запустить FastAPI.
Запуск: uvicorn main:app —reload
Минимальное приложение:
# main.py
from fastapi import FastAPI
app = FastAPI()
@app.get("/")
def root():
return {"message": "Hello, Uvicorn"}
uvicorn main:app --reload
INFO: Will watch for changes in these directories: ['C:\\projects\\demo']
INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
INFO: Started reloader process [36836] using WatchFiles
INFO: Started server process [30672]
INFO: Waiting for application startup.
INFO: Application startup complete.
INFO: 127.0.0.1:62035 - "GET / HTTP/1.1" 200 OK
Запись main:app читается как «модуль main, переменная app». Если приложение лежит в пакете, путь пишется через точку: uvicorn app.main:app. Если переменная называется иначе, укажите её имя: uvicorn main:application.
Флаг --reload перезапускает сервер при изменении .py-файлов. Это режим разработки: в продакшне он не нужен, потому что тратит ресурсы на слежение за файлами.
Параметры командной строки
| Параметр | По умолчанию | Назначение |
|---|---|---|
--host | 127.0.0.1 | адрес; 0.0.0.0 — принимать соединения со всех интерфейсов |
--port | 8000 | порт |
--reload | выкл. | автоперезагрузка при изменении кода |
--reload-dir | текущая папка | какие каталоги отслеживать |
--workers | 1 | число процессов; несовместим с --reload |
--log-level | info | critical, error, warning, info, debug, trace |
--env-file | — | загрузить переменные окружения из файла |
--proxy-headers | вкл. | доверять X-Forwarded-For и X-Forwarded-Proto от прокси |
--forwarded-allow-ips | 127.0.0.1,::1 | IP прокси, заголовкам которых можно доверять |
--root-path | — | префикс пути, если приложение опубликовано не в корне |
--factory | выкл. | APP — функция, которая возвращает приложение |
Полный список выводит uvicorn --help. Типичные команды:
# Разработка
uvicorn main:app --reload
# Открыть доступ из локальной сети (например, для телефона) на порту 8080
uvicorn main:app --host 0.0.0.0 --port 8080
# Продакшн на Linux-сервере: 4 процесса
uvicorn main:app --host 0.0.0.0 --port 8000 --workers 4
С --workers Uvicorn запускает родительский процесс-менеджер и указанное число процессов-воркеров; упавший воркер менеджер перезапускает. Если одновременно указать --reload и --workers, Uvicorn предупредит "workers" flag is ignored when reloading is enabled. и запустит один процесс.
Совет: в FastAPI есть собственная команда
fastapi dev main.py(то же, чтоuvicorn main:app --reload) иfastapi run main.py(без перезагрузки, на0.0.0.0). Внутри работает тот же Uvicorn — выбирайте то, что удобнее. Подробнее — в руководстве по FastAPI.
Запуск из кода: uvicorn.run()
Сервер можно запустить из Python-скрипта — удобно для отладки в IDE через кнопку Run:
# run.py
import uvicorn
from main import app
if __name__ == "__main__":
uvicorn.run(app, host="127.0.0.1", port=8000)
python run.py
Для reload=True или workers приложение нужно передать строкой импорта, иначе Uvicorn не сможет загрузить его заново в новом процессе:
import uvicorn
if __name__ == "__main__":
uvicorn.run("main:app", host="127.0.0.1", port=8000, reload=True)
Если передать объект app вместе с reload=True, сервер не запустится:
WARNING: You must pass the application as an import string to enable 'reload' or 'workers'.
Проверка if __name__ == "__main__" обязательна: с reload или workers Uvicorn создаёт дочерние процессы, и на Windows они заново импортируют ваш скрипт — без проверки каждый из них попытается запустить сервер ещё раз.
Uvicorn и Django
Django с версии 3.0 умеет работать как ASGI-приложение: в проекте уже есть файл asgi.py. Запуск через Uvicorn:
uvicorn config.asgi:application
Здесь config — пакет проекта (тот, где лежит settings.py), application — переменная из asgi.py. Это имеет смысл, если вы используете асинхронные view или WebSocket через Django Channels; для обычного синхронного Django привычнее WSGI и Gunicorn — схема описана в статье про деплой Django на Gunicorn и Nginx.
Uvicorn vs Gunicorn
Gunicorn — WSGI-сервер и менеджер процессов, Uvicorn — ASGI-сервер, и в продакшне их часто используют вместе. Запустить FastAPI «голым» Gunicorn нельзя: стандартные воркеры Gunicorn говорят на WSGI. Зато Gunicorn умеет использовать Uvicorn как класс воркера.
| Критерий | Uvicorn | Gunicorn + Uvicorn worker |
|---|---|---|
| Протокол приложения | ASGI | ASGI через воркер Uvicorn |
| Несколько процессов | --workers N | -w N |
| Перезапуск упавших воркеров | есть | есть |
| Настройка менеджера процессов | базовая: параметры командной строки | --timeout, хуки, gunicorn.conf.py |
| Работа на Windows | да | нет, Gunicorn работает только на Unix |
| Установка | uvicorn[standard] | gunicorn + uvicorn-worker |
Раньше документация FastAPI рекомендовала связку Gunicorn + Uvicorn, потому что Uvicorn не умел управлять процессами. Теперь у uvicorn --workers есть свой менеджер процессов, и документация FastAPI для запуска нескольких воркеров показывает fastapi run --workers 4 или uvicorn --workers 4. Gunicorn остаётся разумным выбором, если команда уже привыкла к его настройкам или нужны его хуки и таймауты.
Gunicorn с Uvicorn worker
Класс воркера uvicorn.workers.UvicornWorker объявлен устаревшим: при импорте он выдаёт DeprecationWarning с советом перейти на пакет uvicorn-worker. Актуальный вариант:
pip install gunicorn uvicorn-worker
gunicorn main:app --workers 4 --worker-class uvicorn_worker.UvicornWorker --bind 0.0.0.0:8000
Сокращённо — -w 4 -k uvicorn_worker.UvicornWorker -b 0.0.0.0:8000. Количество воркеров обычно подбирают от числа ядер процессора; для асинхронного приложения часто хватает одного воркера на ядро.
Uvicorn в Docker и Kubernetes
Если оркестратор сам запускает несколько копий контейнера (Kubernetes, Docker Swarm), внутри контейнера обычно достаточно одного процесса Uvicorn без --workers: масштабированием занимается кластер. В одиночном контейнере или на обычном сервере используйте --workers. Перед приложением в продакшне ставят обратный прокси (Nginx, Traefik), который отвечает за HTTPS; чтобы Uvicorn видел реальный IP клиента, укажите адрес прокси в --forwarded-allow-ips.
Частые ошибки
«uvicorn не является внутренней или внешней командой»
В Windows это выглядит так: 'uvicorn' не является внутренней или внешней командой, исполняемой программой или пакетным файлом; в PowerShell — Имя "uvicorn" не распознано как имя командлета; в Linux с bash — uvicorn: command not found, в macOS с zsh — zsh: command not found: uvicorn. Причина одна: исполняемый файл uvicorn не найден в PATH. Обычно не активировано виртуальное окружение или Uvicorn установлен в другой интерпретатор.
Самый надёжный способ — запускать через интерпретатор:
python -m uvicorn main:app --reload # Windows
python3 -m uvicorn main:app --reload # macOS / Linux
Если и это даёт No module named uvicorn, пакет не установлен в текущее окружение: выполните python -m pip install "uvicorn[standard]".
Error loading ASGI app. Could not import module “main”
ERROR: Error loading ASGI app. Could not import module "mian".
Опечатка в имени модуля или команда запущена не из той папки. Перейдите в каталог, где лежит main.py, или укажите его через --app-dir.
Attribute “app” not found in module “main”
ERROR: Error loading ASGI app. Attribute "application" not found in module "main".
После двоеточия указано имя переменной, которой нет в модуле. Проверьте, как называется объект FastAPI() в коде.
Порт уже занят
ERROR: [Errno 10048] error while attempting to bind on address ('127.0.0.1', 8000): [winerror 10048] only one usage of each socket address (protocol/network address/port) is normally permitted
Так ошибка выглядит в Windows. В Linux вместо 10048 будет [Errno 98] и текст address already in use, в macOS — [Errno 48] с тем же текстом. На этом порту уже работает другой процесс — часто предыдущий запуск Uvicorn. Остановите его или запустите сервер на другом порту: --port 8001.
Изменения в коде не подхватываются
Сервер запущен без --reload или с --workers. В разработке используйте uvicorn main:app --reload или fastapi dev.
Частые вопросы
Как включить HTTPS в Uvicorn?
Передайте ключ и сертификат:
uvicorn main:app --host 0.0.0.0 --port 8443 --ssl-keyfile key.pem --ssl-certfile cert.pem
Так удобно проверить HTTPS локально, например с сертификатом от mkcert. В продакшне сертификаты обычно обслуживает обратный прокси (Nginx, Traefik, Caddy): он сам продлевает сертификаты Let’s Encrypt, а Uvicorn за ним работает по обычному HTTP.
Как найти и остановить процесс, который занял порт?
Сначала узнайте PID процесса, затем завершите его:
# Windows
netstat -ano | findstr :8000
taskkill /PID 12345 /F
# Linux / macOS
lsof -i :8000
kill 12345
Вместо 12345 подставьте PID из вывода первой команды. Сервер, запущенный в своём терминале, останавливают сочетанием Ctrl+C.
Как отключить или настроить логи запросов?
Строки вида "GET / HTTP/1.1" 200 OK — это access log. Отключить его можно флагом --no-access-log, а уровень подробности остальных сообщений меняет --log-level warning. Для своего формата и вывода в файл передайте конфигурацию модуля logging в файле JSON, YAML или INI: --log-config logging.yaml (для YAML нужен pyyaml, он входит в uvicorn[standard]).
Чем можно заменить Uvicorn?
Самые известные ASGI-серверы помимо Uvicorn: Hypercorn — поддерживает HTTP/2 и HTTP/3, Granian — сервер на Rust, который запускает ASGI- и WSGI-приложения, и Daphne — сервер проекта Django Channels. FastAPI работает с любым из них, но команды fastapi dev и fastapi run используют Uvicorn. Если у вас нет конкретной причины (например, нужен HTTP/2 без прокси), оставайтесь на Uvicorn.
Итог
Uvicorn — ASGI-сервер, который запускает FastAPI и другие асинхронные приложения. В разработке хватает команды uvicorn main:app --reload, в продакшне — --host 0.0.0.0, --workers и обратного прокси перед сервером. Gunicorn с воркером uvicorn_worker.UvicornWorker пригодится, если нужны его настройки, но работает он только на Unix.
Дальше — основы фреймворка в руководстве по FastAPI, подключение базы данных в статье FastAPI и SQLAlchemy и защита эндпоинтов в материале про авторизацию через JWT. Полный список настроек — в документации Uvicorn.
- #Uvicorn
- #FastAPI
- #ASGI
- #Gunicorn
- #Деплой