# Production URL: /docs/deployment/production/ Section: deployment Tags: production, deployment, hardening, scaling -------------------------------------------------------------------------------- Recommended Configuration pounce myapp:app \ --host 0.0.0.0 \ --port 8000 \ --workers 0 \ --log-level warning \ --log-format json \ --compression \ --request-timeout 30 \ --header-timeout 10 \ --health-check-path /health \ --shutdown-timeout 15 Behind a Reverse Proxy In most production setups, Pounce runs behind a reverse proxy (nginx, Caddy, etc.) that handles TLS termination, static files, and load balancing. Nginx (TCP) upstream pounce { server 127.0.0.1:8000; } server { listen 443 ssl http2; server_name example.com; ssl_certificate /etc/ssl/cert.pem; ssl_certificate_key /etc/ssl/key.pem; location / { proxy_pass http://pounce; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Request-ID $request_id; # WebSocket support proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; } # Health check — bypass logging for probe traffic location = /health { proxy_pass http://pounce; access_log off; } } Nginx (Unix Domain Socket) Using a Unix socket eliminates TCP overhead and is the recommended approach when nginx and Pounce run on the same host. pounce myapp:app --uds /run/pounce.sock --workers 0 upstream pounce { server unix:/run/pounce.sock; } server { listen 443 ssl http2; server_name example.com; ssl_certificate /etc/ssl/cert.pem; ssl_certificate_key /etc/ssl/key.pem; location / { proxy_pass http://pounce; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Request-ID $request_id; } } Caddy example.com { reverse_proxy 127.0.0.1:8000 } Caddy handles TLS automatically via Let's Encrypt. Proxy Header Trust When behind a reverse proxy, configure trusted_hosts so Pounce honours X-Forwarded-For, X-Forwarded-Proto, and X-Forwarded-Host from trusted peers. Without this, proxy headers are stripped for security. import pounce pounce.run( "myapp:app", trusted_hosts=("10.0.0.1",), # Your proxy's IP ) Or via CLI: # Trust is configured via ServerConfig (no CLI flag — intentionally # requires programmatic configuration for safety) Warning Warning Never set trusted_hosts=("*",) in internet-facing deployments. A wildcard trusts every peer, allowing any client to spoof their IP via X-Forwarded-For. Health Checks Pounce has a built-in health check endpoint that responds before the ASGI app is invoked — fast, lightweight, and independent of your application. pounce myapp:app --health-check-path /health The endpoint returns a JSON payload: { "status": "ok", "uptime_seconds": 3600.1, "worker_id": 0, "active_connections": 42 } Health check requests are excluded from access logs to reduce noise from Kubernetes probes, load balancer checks, and monitoring agents. Kubernetes Probes livenessProbe: httpGet: path: /health port: 8000 initialDelaySeconds: 5 periodSeconds: 10 readinessProbe: httpGet: path: /health port: 8000 initialDelaySeconds: 2 periodSeconds: 5 Request Tracing Every request is assigned a unique X-Request-ID (UUID4 hex). The ID appears in: Response headers — X-Request-ID header on every response ASGI scope — scope["extensions"]["request_id"] for app-level access Access logs — Both text and JSON formats include the request ID If a trusted proxy sends X-Request-ID, Pounce uses that value instead of generating a new one. This enables end-to-end tracing across services. Systemd Service [Unit] Description=Pounce ASGI Server After=network.target [Service] Type=simple User=www-data WorkingDirectory=/opt/myapp ExecStart=/opt/myapp/.venv/bin/pounce myapp:app \ --host 0.0.0.0 \ --workers 0 \ --health-check-path /health \ --log-format json Restart=always RestartSec=5 [Install] WantedBy=multi-user.target Unix Socket with Systemd [Unit] Description=Pounce ASGI Server After=network.target [Service] Type=simple User=www-data WorkingDirectory=/opt/myapp ExecStart=/opt/myapp/.venv/bin/pounce myapp:app \ --uds /run/pounce.sock \ --workers 0 \ --health-check-path /health \ --log-format json Restart=always RestartSec=5 RuntimeDirectory=pounce [Install] WantedBy=multi-user.target Docker FROM python:3.14t-slim WORKDIR /app COPY . . RUN pip install bengal-pounce[full] . EXPOSE 8000 HEALTHCHECK CMD curl -f http://localhost:8000/health || exit 1 CMD ["pounce", "myapp:app", "--host", "0.0.0.0", "--workers", "0", "--health-check-path", "/health", "--log-format", "json"] Graceful Shutdown Pounce handles SIGINT and SIGTERM: Stop accepting new connections Wait for in-flight requests to complete (up to shutdown_timeout) Send ASGI lifespan shutdown event Clean up Unix socket file (if using UDS) Exit cleanly Connection Backpressure When the connection limit is reached (max_connections), Pounce returns an HTTP 503 Service Unavailable response with a Retry-After: 5 header instead of silently dropping the connection. This gives clients actionable feedback. Security Checklist Run behind a reverse proxy for TLS termination Set trusted_hosts to your proxy's IP address Set appropriate max_request_size for your application Use --header-timeout to protect against slowloris attacks (default: 10s) Use --log-format json for structured logging (parseable by log aggregators) Set server_header to a generic value (or empty) to avoid version fingerprinting Use --workers 0 for auto-scaled parallelism Enable --health-check-path /health for load balancer integration See Also Security — Proxy headers, CRLF protection, request smuggling Observability — Health checks, request IDs, Prometheus metrics TLS — Direct TLS termination Workers — Worker count tuning ServerConfig — All configuration options -------------------------------------------------------------------------------- Metadata: - Word Count: 708 - Reading Time: 4 minutes