This guide provides instructions for deploying QWED in various environments.
Table of Contents
- Docker Deployment
- Kubernetes Deployment
- Manual / Bare Metal Deployment
- Environment Variables Reference
- Production Checklist
- Troubleshooting
- Operations & Monitoring
Docker Deployment
The easiest way to run QWED locally or on a single server is using Docker Compose.
Dockerfile
A Dockerfile is provided in the root directory. It builds the QWED core service based on python:3.11-slim.
# Build the image manually
docker build -t qwed-core:5.0.0 .
Docker Compose
We provide a docker-compose.yml that orchestrates:
- qwed-core: The main API server.
- postgres: Primary database.
- redis: Cache and rate limiting.
- jaeger: Distributed tracing.
- prometheus: Metrics collection.
- grafana: Observability dashboards.
Before starting the stack, create a .env file in the deploy/ directory with the required environment variables:
# Required — the server will not start without these
DATABASE_URL=postgresql://qwed:your_password@postgres:5432/qwed_db
QWED_CORS_ORIGINS=https://app.yourcompany.com
API_KEY_SECRET=your-generated-secret
# Optional
REDIS_URL=redis://redis:6379/0
OTEL_EXPORTER_OTLP_ENDPOINT=http://jaeger:4317
# Postgres
POSTGRES_USER=qwed
POSTGRES_PASSWORD=your_password
POSTGRES_DB=qwed_db
# Grafana
GF_SECURITY_ADMIN_USER=admin
GF_SECURITY_ADMIN_PASSWORD=your_grafana_password
DATABASE_URL, QWED_CORS_ORIGINS, and API_KEY_SECRET are required. Docker Compose will refuse to start if any of these are missing. Generate API_KEY_SECRET with:python -c "import secrets; print(secrets.token_urlsafe(48))"
Start the stack:
Access the services:
Docker requirement for code execution
Both the Stats Engine and the Consensus Engine (in high/maximum mode) execute model-generated Python inside Docker containers. Docker is required — there are no in-process fallbacks. If Docker is unavailable, these endpoints return HTTP 503.
Kubernetes Deployment
For production environments, we provide Kubernetes manifests in deploy/kubernetes/.
Prerequisites
- A running Kubernetes cluster (v1.24+ recommended).
kubectl configured.
- A PostgreSQL database and Redis instance (managed services recommended for production).
Deployment Steps
-
Create Namespace
kubectl create namespace qwed
-
Configure Secrets & ConfigMaps
Edit
deploy/kubernetes/secret.yaml and replace all __REPLACE_WITH_*__ placeholders with your real values. The DATABASE_URL is now stored in the Secret (not the ConfigMap) because it contains credentials.
kubectl apply -f deploy/kubernetes/configmap.yaml
kubectl apply -f deploy/kubernetes/secret.yaml
-
Deploy Application
kubectl apply -f deploy/kubernetes/deployment.yaml
kubectl apply -f deploy/kubernetes/service.yaml
-
Verify Deployment
Horizontal Pod Autoscaling (HPA)
For high-traffic environments, we recommend enabling HPA (requires Metrics Server):
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: qwed-core-hpa
namespace: qwed
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: qwed-core
minReplicas: 2
maxReplicas: 10
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 70
If you prefer to run the application directly on a host or VM:
1. Prerequisites
Docker Installation (Required for Secure Code Execution)
QWED requires Docker for all model-generated code execution in the Stats Engine and Consensus Engine. Without Docker, these verification endpoints return HTTP 503.
Linux (Ubuntu/Debian)
sudo apt-get update
sudo apt-get install docker.io
sudo systemctl start docker
sudo systemctl enable docker
sudo usermod -aG docker $USER
2. Python Dependencies
# Install dependencies
pip install -e .
3. Database Setup
Ensure PostgreSQL and Redis are running. Set the DATABASE_URL and REDIS_URL environment variables.
Initialize the database:
python -c "from qwed_new.core.database import create_db_and_tables; create_db_and_tables()"
4. Running the API
# Production Mode with Gunicorn (Linux/macOS)
gunicorn qwed_new.api.main:app -w 4 -k uvicorn.workers.UvicornWorker --bind 0.0.0.0:8000
Environment Variables Reference
Infrastructure
| Variable | Description | Default | Required |
|---|
DATABASE_URL | Postgres connection string | sqlite:///./qwed.db | Yes (Prod) |
REDIS_URL | Redis connection string | redis://localhost:6379/0 | Yes (Prod) |
API_KEY_SECRET | Secret key for signing JWTs | None (must be set) | YES |
QWED_CORS_ORIGINS | Comma-separated list of allowed CORS origins | None (must be set) | YES |
QWED_SKIP_ENV_INTEGRITY_CHECK | Set to true to bypass startup environment integrity check | false | No |
API_KEY_SECRET | Secret for PBKDF2 API-key hashing | None | Yes |
QWED_CORS_ORIGINS | Comma-separated allowed CORS origins | None | Yes |
API_KEY_SECRET no longer has a default value. The server will refuse to start if it is not set. This prevents accidental deployment with a weak default secret.
Security Configuration
| Variable | Description | Default |
|---|
MAX_INPUT_LENGTH | Max query length (chars) | 2000 |
SIMILARITY_THRESHOLD | Prompt injection detection threshold | 0.6 |
DOCKER_TIMEOUT | Code execution timeout (seconds) | 10 |
DOCKER_MEMORY_LIMIT | Container memory limit | 512m |
QWED_SKIP_ENV_INTEGRITY_CHECK | Skip .pth file verification on startup | false |
AI Providers
| Variable | Description | Default |
|---|
ACTIVE_PROVIDER | Selected LLM provider | azure_openai |
AZURE_OPENAI_API_KEY | API Key for Azure OpenAI | - |
AZURE_OPENAI_ENDPOINT | Endpoint URL | - |
ANTHROPIC_API_KEY | API Key for Anthropic | - |
GOOGLE_API_KEY | API Key for Google Gemini (or GEMINI_API_KEY) | - |
GEMINI_MODEL | Gemini model name | gemini-1.5-pro |
Observability
| Variable | Description | Default |
|---|
OTEL_EXPORTER_OTLP_ENDPOINT | Jaeger/OTLP Endpoint | http://localhost:4317 |
Production Checklist
Before going to production, ensure the following:
1. Database Setup
2. Redis Configuration
3. Security
4. Observability
Troubleshooting
1. Docker Permission Denied
Error: docker: Got permission denied while trying to connect to the Docker daemon socket
Solution: Ensure the user running the app is in the docker group, or (for Docker Compose) ensure the socket is mounted correctly and the container user has permissions.
2. Stats or consensus verification returning 503
Error: Service temporarily unavailable on /verify/stats or /verify/consensus
Cause: The secure Docker sandbox is unreachable. QWED does not fall back to in-process execution.
Solution:
- Check Docker is running:
docker ps
- Verify the Docker daemon responds to pings:
docker info
- Check
python:3.10-slim image exists: docker pull python:3.10-slim (The executor uses this image).
Operations & Monitoring
View Recent Security Events
# Python script
python -c "
from qwed_new.core.database import get_session
from qwed_new.core.models import SecurityEvent
from sqlmodel import select
with get_session() as session:
events = session.exec(
select(SecurityEvent)
.where(SecurityEvent.event_type == 'BLOCKED')
.order_by(SecurityEvent.timestamp.desc())
.limit(10)
).all()
for e in events:
print(f'{e.timestamp}: {e.reason}')
"
Security Metrics Dashboard
# Block rate by hour
sqlite3 qwed_v2.db "
SELECT strftime('%Y-%m-%d %H:00', timestamp) as hour, COUNT(*) as blocks
FROM security_event
WHERE event_type = 'BLOCKED'
GROUP BY hour
ORDER BY hour DESC
LIMIT 24;
"
For detailed architecture documentation, see: