Skip to content

Configuration

This guide covers the essential configuration steps to get your FastAPI application running.

Quick Setup

Copy the example environment file and edit a few values:

cd backend
cp .env.example .env

The full set of variables lives in backend/.env.example. The sections below cover the ones you'll most likely want to change.

Essential Configuration

Open backend/.env and set these required values.

Application Settings

APP_NAME=Your app name here
APP_DESCRIPTION=Your app description here
VERSION=0.1.0
API_CONTACT_NAME=Your name
API_CONTACT_EMAIL=your@email.com
API_LICENSE_NAME=The license you picked

Environment Type

# Options: development, staging, production, local
ENVIRONMENT=development
  • development: API docs at /docs, /redoc, verbose logging
  • staging: Structured logs, file output enabled
  • production: JSON logs, security validation, docs gated by ENABLE_DOCS_IN_PRODUCTION
  • local: Same defaults as development; useful for tests

Database

POSTGRES_USER=postgres
POSTGRES_PASSWORD=changeme
POSTGRES_DB=postgres
POSTGRES_SERVER=postgres    # use "localhost" without Docker
POSTGRES_PORT=5432
CREATE_TABLES_ON_STARTUP=true   # the default in local and development

Security

Generate a strong SECRET_KEY:

python -c "import secrets; print(secrets.token_urlsafe(64))"
SECRET_KEY=your-generated-secret-key-here

# Production security validation (enabled by default in production)
PRODUCTION_SECURITY_VALIDATION_ENABLED=true

Sessions

SESSION_TIMEOUT_MINUTES=30
# SESSION_ABSOLUTE_TIMEOUT_HOURS=12  # unset: the idle timeout is the only one
# FRESH_SIGN_IN_SECONDS=600          # unset: closing an account asks nothing; crudauth's own routes keep their 10-minute default
SESSION_CLEANUP_INTERVAL_MINUTES=15
MAX_SESSIONS_PER_USER=5
SESSION_SECURE_COOKIES=true
SESSION_BACKEND=redis            # redis | memory
SESSION_REDIS_DB=2               # on the cache Redis, apart from the cache DB so a flush won't log users out
# SESSION_REDIS_URL=             # optional dedicated session Redis, e.g. rediss://user:password@host:6380/0

# CSRF protection (set false to disable in dev/test)
CSRF_ENABLED=true

# Trusted reverse proxies in front of the app (used to resolve the real client
# IP for login lockout). 0 = none; set 1 behind a single nginx/Caddy.
TRUSTED_PROXY_HOPS=0

# Password policy (enforced by crudauth on registration and password changes)
PASSWORD_MIN_LENGTH=8
PASSWORD_REQUIRE_UPPERCASE=true
PASSWORD_REQUIRE_LOWERCASE=true
PASSWORD_REQUIRE_DIGIT=true
PASSWORD_REQUIRE_SPECIAL=true

Login lockout is applied by crudauth, per client IP and per submitted identifier at once, and answers 429 Too Many Requests with a Retry-After header. Four settings tune it, passed to crudauth's LockoutConfig in infrastructure/auth/setup.py:

LOGIN_MAX_ATTEMPTS=5              # failures allowed inside the window
LOGIN_ATTEMPT_WINDOW_SECONDS=900  # how long failures keep counting
LOGIN_LOCKOUT_BASE_SECONDS=300    # first lockout, doubling each round
LOGIN_LOCKOUT_MAX_SECONDS=3600    # cap on the escalation

Because both dimensions are counted, an attacker rotating identifiers from one address runs out of attempts on the address, and one spread across addresses runs out on the identifier.

First Admin User

The setup_initial_data script reads these on first run:

ADMIN_NAME=Admin User
ADMIN_EMAIL=admin@example.com
ADMIN_USERNAME=admin
ADMIN_PASSWORD=Change-Me-Now-1!

Then run:

uv run --no-sync python -m scripts.setup_initial_data

Cache (Redis or Memcached)

CACHE_ENABLED=true
CACHE_BACKEND=redis             # or "memcached"

# Client-side cache (Cache-Control headers)
CLIENT_CACHE_ENABLED=true
CLIENT_CACHE_MAX_AGE=60

# Redis settings
CACHE_REDIS_HOST=redis          # use "localhost" without Docker
CACHE_REDIS_PORT=6379
CACHE_REDIS_DB=0
CACHE_REDIS_PASSWORD=

Rate Limiting

RATE_LIMITER_ENABLED=true
RATE_LIMITER_BACKEND=redis        # or memory (per process, single worker only)
DEFAULT_RATE_LIMIT_LIMIT=100
DEFAULT_RATE_LIMIT_PERIOD=60

# Redis (uses DB 1 by default to separate from cache)
RATE_LIMITER_REDIS_HOST=redis   # use "localhost" without Docker
RATE_LIMITER_REDIS_PORT=6379
RATE_LIMITER_REDIS_DB=1
RATE_LIMITER_REDIS_PASSWORD=

API limits are resolved by crudauth per request from the user's tier and path. Authenticated requests are keyed by user ID; anonymous requests are keyed by the client IP, honoring TRUSTED_PROXY_HOPS.

Background Tasks (Taskiq)

TASKIQ_BROKER_TYPE=redis        # or "rabbitmq"

# Redis broker (uses DB 3 by default)
TASKIQ_REDIS_HOST=redis         # use "localhost" without Docker
TASKIQ_REDIS_PORT=6379
TASKIQ_REDIS_DB=3
TASKIQ_REDIS_PASSWORD=

CORS

CORS_ENABLED=true
CORS_ORIGINS=http://localhost:3000,http://localhost:5173  # comma-separated origins
CORS_ALLOW_CREDENTIALS=true
CORS_ALLOW_METHODS=*
CORS_ALLOW_HEADERS=*

CORS in Production

Never use * for CORS_ORIGINS in production. Specify exact domains and explicit methods/headers:

CORS_ORIGINS=https://yourapp.com,https://www.yourapp.com
CORS_ALLOW_METHODS=GET,POST,PUT,DELETE,PATCH
CORS_ALLOW_HEADERS=Authorization,Content-Type

OAuth (Optional)

For Google / GitHub sign-in:

OAUTH_REDIRECT_BASE_URL=http://localhost:8000

# Google OAuth
OAUTH_GOOGLE_CLIENT_ID=
OAUTH_GOOGLE_CLIENT_SECRET=

# GitHub OAuth
OAUTH_GITHUB_CLIENT_ID=
OAUTH_GITHUB_CLIENT_SECRET=

A provider is wired when both of its settings are set, so you can run Google, GitHub, both or neither; leave a pair empty to disable that provider. See Authentication for the OAuth setup walkthrough.

The built-in crudauth OAuth router keeps the existing paths (/api/v1/auth/oauth/{provider} and /api/v1/auth/oauth/callback/{provider}), returns JSON, sets session cookies, binds state to the browser, and validates post-login redirects as same-origin relative paths.

Admin Interface

ADMIN_ENABLED=true              # enables SQLAdmin at /admin

Docker Compose Settings

When running with Docker Compose, services reach each other by service name. Use these hosts in .env:

POSTGRES_SERVER=postgres
CACHE_REDIS_HOST=redis
RATE_LIMITER_REDIS_HOST=redis
TASKIQ_REDIS_HOST=redis

That's It

With these settings, start the app:

uv run --no-sync fastapi dev src/interfaces/main.py
docker compose up

For the full reference and advanced settings, see User Guide → Configuration.