Deployment
Deploy ProxyWhirl locally, on Kubernetes, AWS, or Linux systemd with Docker Compose and Helm.
ProxyWhirl deployments combine a Python runtime (CLI, API, or MCP), optional SQLite storage, and periodically refreshed proxy-list artifacts.
Pre-Deploy Validation
uv run proxywhirl sources --validate --fail-on-unhealthy --timeout 5 --concurrency 5
just quality-gates
pnpm --dir web run docs:generate && pnpm --dir web run buildDocker Compose (API Only)
Root docker-compose.yml runs the REST API with persistent storage:
docker compose up -d
curl http://localhost:8000/api/healthDocker Compose (Full Stack)
deploy/docker-compose.yml adds Redis, PostgreSQL, Prometheus, and Grafana:
docker compose -f deploy/docker-compose.yml up -d| Service | URL |
|---|---|
| API | http://localhost:8000 |
| Prometheus | http://localhost:9091 |
| Grafana | http://localhost:3000 (admin/admin) |
Build context resolves to the repo-root Dockerfile (context: .. from deploy/).
Kubernetes
Raw manifests
kubectl apply -f deploy/kubernetes/
kubectl get pods -n proxywhirl
kubectl logs -n proxywhirl -l app=proxywhirlHelm (recommended)
helm install proxywhirl deploy/helm/ -n proxywhirl --create-namespace
helm upgrade proxywhirl deploy/helm/ --set replicaCount=5 --set persistence.size=50GiCreate proxywhirl-secrets first or set secrets.create=true with local, uncommitted secret values.
Customize via deploy/helm/values.yaml or a local values file for image tag, persistence, metrics
exposure, and secret references.
AWS (Terraform)
cd deploy/terraform
terraform init
terraform plan -var-file=prod.tfvars
terraform apply -var-file=prod.tfvars
terraform output alb_dns_nameConfigure AWS credentials before apply.
Linux systemd
uv sync
sudo cp deploy/systemd/*.service /etc/systemd/system/
sudo useradd -r -s /bin/false proxywhirl
sudo mkdir -p /opt/proxywhirl /var/lib/proxywhirl /var/log/proxywhirl
sudo chown proxywhirl:proxywhirl /var/lib/proxywhirl /var/log/proxywhirl
sudo systemctl daemon-reload
sudo systemctl enable --now proxywhirlEnvironment file example (/etc/default/proxywhirl):
PROXYWHIRL_LOG_LEVEL=INFO
PROXYWHIRL_STORAGE_PATH=/var/lib/proxywhirl/proxywhirl.db
PROXYWHIRL_REQUIRE_AUTH=true
PROXYWHIRL_ENCRYPTION_KEY=<key>
PROXYWHIRL_API_KEY=<key>
# Optional only for internal Prometheus scraping:
# PROXYWHIRL_PUBLIC_METRICS=trueAPI Service (Direct)
PROXYWHIRL_REQUIRE_AUTH=true \
PROXYWHIRL_STORAGE_PATH=/data/proxywhirl.db \
PROXYWHIRL_API_KEY=<key> \
uv run uvicorn proxywhirl.api:app --host 0.0.0.0 --port 8000Point load balancers at /api/ready. See REST API Deployment.
MCP Service
PROXYWHIRL_MCP_API_KEY=<key> \
PROXYWHIRL_MCP_DB=/data/proxywhirl.db \
proxywhirl-mcp --transport httpSee MCP Server.
Production Hardening (Authentication)
[!IMPORTANT] Both
PROXYWHIRL_REQUIRE_AUTH(REST API) andPROXYWHIRL_MCP_API_KEY(MCP server) default to disabled/unset for local-dev ergonomics. Neither flips automatically for production — you must opt in explicitly. When either is off at startup, ProxyWhirl now logs aWARNINGdescribing the exposure; treat that log line as an actionable signal in any environment reachable outside localhost.
- Set
PROXYWHIRL_REQUIRE_AUTH=trueandPROXYWHIRL_API_KEY=$(openssl rand -base64 32)for the REST API; setPROXYWHIRL_MCP_API_KEY(or--api-key) for the MCP server. Rotate keys on a schedule and store them in a secrets manager, not in compose/env files committed to git. - Terminate TLS in front of the API/MCP service (Nginx/Caddy/ALB) — neither service terminates TLS itself.
- Restrict
PROXYWHIRL_CORS_ORIGINSto known origins; never combine*with credentials (enforced at import time inproxywhirl/api/core.py, which also logs a warning if*is configured). /api/statsand/api/metricsrequire the REST API key whenPROXYWHIRL_REQUIRE_AUTH=true./api/metricscan be exposed without a key only by explicitly settingPROXYWHIRL_PUBLIC_METRICS=true; use that only on an internal listener or behind network policy.- The MCP server allows unauthenticated read actions by default; write actions (
add,remove,fetch,validate,reset_cb,set_strategy) are rejected without a key unlessPROXYWHIRL_MCP_ALLOW_UNAUTHENTICATED_WRITESis explicitly set — keep that variable unset in production. - Monitor the "authentication DISABLED" startup warnings (API and MCP) in log aggregation/alerting so a misconfigured deployment is caught before it reaches production traffic.
Backup and Zero-Downtime
./deploy/scripts/backup-restore.sh backup
./deploy/scripts/backup-restore.sh list
./deploy/scripts/backup-restore.sh restore /path/to/backup.db.gz
./deploy/scripts/blue-green-deploy.sh
./deploy/scripts/health-check.shMonitoring
curl 'http://localhost:9091/api/v1/query?query=proxywhirl_available_proxies'
kubectl port-forward -n proxywhirl svc/grafana 3000:3000Check Grafana for error rate, latency, available proxies, and cache hit rate.
Proxy List Publication
The public bundle at /proxy-lists/ is mirrored from docs/proxy-lists/ during pnpm --dir web run docs:generate. See Proxy Lists.