uvicorn settings

This commit is contained in:
John Lancaster
2026-06-17 00:28:59 -05:00
parent 78fa9235d3
commit 6e32955533
3 changed files with 235 additions and 11 deletions
+42 -10
View File
@@ -24,6 +24,7 @@ Load these references only when needed:
- FastAPI patterns and app structure: [./references/fastapi-best-practices.md](./references/fastapi-best-practices.md) - FastAPI patterns and app structure: [./references/fastapi-best-practices.md](./references/fastapi-best-practices.md)
- uv project layout and dependency management: [./references/uv-project-layout.md](./references/uv-project-layout.md) - uv project layout and dependency management: [./references/uv-project-layout.md](./references/uv-project-layout.md)
- uvicorn CLI settings reference: [./references/uvicorn-settings.md](./references/uvicorn-settings.md)
- Docker and cloud-native patterns: [./references/docker-cloud-native.md](./references/docker-cloud-native.md) - Docker and cloud-native patterns: [./references/docker-cloud-native.md](./references/docker-cloud-native.md)
--- ---
@@ -45,6 +46,7 @@ Before making changes, map the current state across six areas. Produce a short g
Load [./references/fastapi-best-practices.md](./references/fastapi-best-practices.md) for structure rules. Load [./references/fastapi-best-practices.md](./references/fastapi-best-practices.md) for structure rules.
Load [./references/uv-project-layout.md](./references/uv-project-layout.md) for uv migration rules. Load [./references/uv-project-layout.md](./references/uv-project-layout.md) for uv migration rules.
Load [./references/uvicorn-settings.md](./references/uvicorn-settings.md) for uvicorn CLI reference.
Completion check: You can name every gap before touching any file. Completion check: You can name every gap before touching any file.
@@ -209,28 +211,58 @@ Completion check: `uv run uvicorn my_app.main:app --reload` starts with no impor
### Step 4: uvicorn Production Configuration ### Step 4: uvicorn Production Configuration
**Never** configure uvicorn inside application code. Pass all settings via CLI or environment. Load [./references/uvicorn-settings.md](./references/uvicorn-settings.md) for the full settings reference.
**Never** configure uvicorn inside application code. Pass all settings via CLI or environment variables (`UVICORN_*` prefix).
```bash ```bash
# Development # Development — reload only; never in production
uv run uvicorn my_app.main:app --reload --host 127.0.0.1 --port 8000 uv run uvicorn my_app.main:app \
--reload \
--host 127.0.0.1 \
--port 8000 \
--log-level debug
# Production (single process — let orchestrator handle replication) # Production single process (orchestrator handles replication)
uv run uvicorn my_app.main:app \ uv run uvicorn my_app.main:app \
--host 0.0.0.0 \ --host 0.0.0.0 \
--port 8000 \ --port 8000 \
--workers 1 \ --workers 1 \
--loop uvloop \ --loop auto \
--http h11 \ --http auto \
--log-level info \ --log-level info \
--access-log \
--proxy-headers \ --proxy-headers \
--forwarded-allow-ips '*' --forwarded-allow-ips '*' \
--timeout-graceful-shutdown 30
``` ```
**When to use `--workers > 1`:** Only for single-server Docker Compose deployments where you cannot replicate at the orchestrator level. For Kubernetes / cloud run: always `--workers 1` and scale via replicas. **Key flags for production:**
**`--proxy-headers`** is required whenever the container sits behind a reverse proxy (nginx, traefik, cloud load balancer) — it makes FastAPI trust `X-Forwarded-For` and `X-Forwarded-Proto`. | Flag | Value | Reason |
|------|-------|--------|
| `--host 0.0.0.0` | Required in containers | Bind to all interfaces, not just loopback |
| `--workers 1` | Kubernetes/Cloud Run | Orchestrator replicates containers |
| `--loop auto` | Default | Uses `uvloop` when available (install `uvicorn[standard]`) |
| `--http auto` | Default | Uses `httptools` when available |
| `--proxy-headers` | Behind any proxy | Trusts `X-Forwarded-For`, `X-Forwarded-Proto` |
| `--forwarded-allow-ips '*'` | Container/K8s | Trusts proxy headers from all IPs (safe when inside a trusted network) |
| `--timeout-graceful-shutdown 30` | Prod | Seconds to wait before force-closing requests on shutdown |
| `--no-access-log` | High-traffic prod | Disable per-request logs if using structured app-level logging |
**Environment variable equivalents** (useful in `docker-compose.yml` / K8s manifests):
```bash
UVICORN_HOST=0.0.0.0
UVICORN_PORT=8000
UVICORN_WORKERS=1
UVICORN_LOG_LEVEL=info
UVICORN_PROXY_HEADERS=true
UVICORN_FORWARDED_ALLOW_IPS=*
```
**`--reload` and `--workers` are mutually exclusive** — never combine them.
**When to use `--workers > 1`:** Only for Docker Compose on a single host where orchestrator-level replication is not available. For Kubernetes / Cloud Run / Fargate: always `--workers 1` and scale via replicas — this gives predictable per-container memory and cleaner crash isolation.
Completion check: `curl http://localhost:8000/healthz` returns `{"status":"ok"}`. Completion check: `curl http://localhost:8000/healthz` returns `{"status":"ok"}`.
@@ -1,6 +1,6 @@
# Docker and Cloud-Native Patterns # Docker and Cloud-Native Patterns
Source: https://docs.docker.com/build/building/best-practices/ | https://docs.astral.sh/uv/guides/integration/docker/ | https://fastapi.tiangolo.com/deployment/docker/ Source: https://docs.docker.com/build/building/best-practices/ | https://docs.astral.sh/uv/guides/integration/docker/ | https://fastapi.tiangolo.com/deployment/docker/ | https://uvicorn.dev/deployment/
--- ---
@@ -0,0 +1,192 @@
# uvicorn Settings Reference
Source: https://uvicorn.dev/settings/ | https://uvicorn.dev/deployment/
---
## Configuration Methods
Three equivalent approaches (CLI takes precedence over env vars):
```bash
# 1. CLI flags
uvicorn main:app --host 0.0.0.0 --port 8000
# 2. UVICORN_* environment variables
export UVICORN_HOST=0.0.0.0
export UVICORN_PORT=8000
uvicorn main:app
# 3. Programmatic (dev/test only)
uvicorn.run("main:app", host="0.0.0.0", port=8000)
```
**Note:** `UVICORN_*` env vars cannot be used from within an `--env-file`. The `--env-file` flag is for the ASGI *application's* config, not uvicorn's own config.
---
## All Settings by Category
### Socket Binding
| Flag | Default | Notes |
|------|---------|-------|
| `--host <str>` | `127.0.0.1` | Use `0.0.0.0` in containers to bind all interfaces |
| `--port <int>` | `8000` | Use `0` to auto-pick an available port |
| `--uds <path>` | — | UNIX domain socket path (use behind Nginx) |
| `--fd <int>` | — | Inherit socket from file descriptor (use with Supervisor) |
### Production
| Flag | Default | Notes |
|------|---------|-------|
| `--workers <int>` | `1` (or `$WEB_CONCURRENCY`) | **Mutually exclusive with `--reload`** |
| `--env-file <path>` | — | Env file for the *application* (not uvicorn itself) |
| `--timeout-worker-healthcheck <int>` | `5` | Seconds before killing a stuck worker |
### Logging
| Flag | Default | Notes |
|------|---------|-------|
| `--log-level <str>` | `info` | `critical`, `error`, `warning`, `info`, `debug`, `trace` |
| `--log-config <path>` | — | `.json` or `.yaml` for `dictConfig()`; other formats use `fileConfig()` |
| `--no-access-log` | — | Disable access log without changing log level |
| `--use-colors / --no-use-colors` | auto | Force color on/off in log output |
### Implementation
| Flag | Default | Notes |
|------|---------|-------|
| `--loop <str>` | `auto` | `auto`, `asyncio`, `uvloop`. `uvloop` requires `uvicorn[standard]` |
| `--http <str>` | `auto` | `auto`, `h11`, `httptools`. `httptools` requires `uvicorn[standard]` |
| `--ws <str>` | `auto` | `auto`, `none`, `websockets`, `websockets-sansio`, `wsproto` |
| `--lifespan <str>` | `auto` | `auto`, `on`, `off` |
| `--ws-max-size <int>` | `16777216` | WebSocket max message size in bytes (16 MB) |
| `--ws-ping-interval <float>` | `20.0` | WebSocket ping interval in seconds |
| `--ws-ping-timeout <float>` | `20.0` | WebSocket ping timeout in seconds |
### HTTP / Proxy Headers
| Flag | Default | Notes |
|------|---------|-------|
| `--proxy-headers` | enabled | Trust `X-Forwarded-For`, `X-Forwarded-Proto` from trusted IPs |
| `--no-proxy-headers` | — | Disable proxy header trust entirely |
| `--forwarded-allow-ips <list>` | `127.0.0.1` | Comma-separated IPs/networks/literals to trust. Use `'*'` to trust all (safe in containers behind a trusted LB). **Security risk if exposed directly to internet.** |
| `--root-path <str>` | `""` | ASGI `root_path` for apps mounted below a URL prefix |
| `--server-header / --no-server-header` | enabled | Include/suppress `Server` response header |
| `--date-header / --no-date-header` | enabled | Include/suppress `Date` response header |
| `--header <name:value>` | — | Add custom default response headers (repeatable) |
### Resource Limits
| Flag | Default | Notes |
|------|---------|-------|
| `--limit-concurrency <int>` | — | Max concurrent connections/tasks; returns HTTP 503 above this |
| `--limit-max-requests <int>` | — | Restart worker after N requests (limits memory leak accumulation) |
| `--limit-max-requests-jitter <int>` | `0` | Random jitter added to `--limit-max-requests` to stagger worker restarts |
| `--backlog <int>` | `2048` | Max queued connections under high load |
### Timeouts
| Flag | Default | Notes |
|------|---------|-------|
| `--timeout-keep-alive <int>` | `5` | Close keep-alive connections after N seconds of inactivity |
| `--timeout-graceful-shutdown <int>` | — | Seconds to wait for in-flight requests to complete on SIGTERM before force-closing |
### Development
| Flag | Default | Notes |
|------|---------|-------|
| `--reload` | `False` | Auto-reload on file changes. **Never use in production.** Mutually exclusive with `--workers`. |
| `--reload-dir <path>` | `.` | Directory to watch for changes (repeatable) |
| `--reload-delay <float>` | `0.25` | Seconds between reload checks |
| `--reload-include <glob>` | `*.py` | Patterns to include in watch (requires `watchfiles`) |
| `--reload-exclude <glob>` | `.*, .py[cod], ...` | Patterns to exclude from watch (requires `watchfiles`) |
### Application
| Flag | Default | Notes |
|------|---------|-------|
| `--factory` | — | Treat `APP` as a `() -> ASGI app` callable (app factory pattern) |
| `--app-dir <path>` | `.` | Add to `PYTHONPATH` when resolving `APP` |
| `--reset-contextvars` | `False` | Run each request in a fresh `contextvars.Context` (asyncio only; workaround for a CPython context-leak bug) |
---
## Recommended Production CMD
```bash
uvicorn my_app.main:app \
--host 0.0.0.0 \
--port 8000 \
--workers 1 \
--loop auto \
--http auto \
--log-level info \
--proxy-headers \
--forwarded-allow-ips '*' \
--timeout-graceful-shutdown 30
```
In a Dockerfile (exec form):
```dockerfile
CMD ["uvicorn", "my_app.main:app",
"--host", "0.0.0.0",
"--port", "8000",
"--workers", "1",
"--proxy-headers",
"--forwarded-allow-ips", "*",
"--timeout-graceful-shutdown", "30"]
```
---
## Process Manager Options
### Built-in multi-worker (Docker Compose / single host)
```bash
uvicorn my_app.main:app --workers 4
```
The built-in manager spawns workers, monitors their health, and auto-restarts crashed workers. Signal support:
- `SIGHUP` — rolling graceful restart (deploy new code without dropping requests)
- `SIGTTIN` — add one worker
- `SIGTTOU` — remove one worker
### Behind Nginx (UNIX socket)
```bash
uvicorn my_app.main:app --uds /tmp/uvicorn.sock --proxy-headers
```
Nginx config headers to set:
```nginx
proxy_set_header Host $http_host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
```
---
## `uvicorn[standard]` vs bare `uvicorn`
| Package | Extras included |
|---------|----------------|
| `uvicorn` | Pure Python h11 HTTP, asyncio event loop |
| `uvicorn[standard]` | `uvloop` (faster event loop), `httptools` (faster HTTP parser), `watchfiles` (better reload), `websockets`, `PyYAML` (for `--log-config`) |
Use `uvicorn[standard]` in all environments. The `[standard]` extras are also included when you install `fastapi[standard]`.
---
## Anti-patterns
| Anti-pattern | Fix |
|---|---|
| `--reload` in Dockerfile CMD | Remove it — `--reload` is dev-only |
| `--loop uvloop` explicitly | Use `--loop auto` — it selects uvloop automatically when available |
| `--http h11` explicitly in prod | Use `--http auto` — it selects httptools when available |
| `uvicorn.run()` at module level (no `if __name__ == '__main__':`) | Breaks multiprocessing workers; always guard it |
| Shell form `CMD uvicorn ...` | Exec form `CMD ["uvicorn", ...]` — required for SIGTERM to reach uvicorn |