ProxyWhirl Docs
Guides

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 build

Docker Compose (API Only)

Root docker-compose.yml runs the REST API with persistent storage:

docker compose up -d
curl http://localhost:8000/api/health

Docker Compose (Full Stack)

deploy/docker-compose.yml adds Redis, PostgreSQL, Prometheus, and Grafana:

docker compose -f deploy/docker-compose.yml up -d
ServiceURL
APIhttp://localhost:8000
Prometheushttp://localhost:9091
Grafanahttp://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=proxywhirl
helm install proxywhirl deploy/helm/ -n proxywhirl --create-namespace
helm upgrade proxywhirl deploy/helm/ --set replicaCount=5 --set persistence.size=50Gi

Create 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_name

Configure 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 proxywhirl

Environment 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=true

API 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 8000

Point 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 http

See MCP Server.

Production Hardening (Authentication)

[!IMPORTANT] Both PROXYWHIRL_REQUIRE_AUTH (REST API) and PROXYWHIRL_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 a WARNING describing the exposure; treat that log line as an actionable signal in any environment reachable outside localhost.

  1. Set PROXYWHIRL_REQUIRE_AUTH=true and PROXYWHIRL_API_KEY=$(openssl rand -base64 32) for the REST API; set PROXYWHIRL_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.
  2. Terminate TLS in front of the API/MCP service (Nginx/Caddy/ALB) — neither service terminates TLS itself.
  3. Restrict PROXYWHIRL_CORS_ORIGINS to known origins; never combine * with credentials (enforced at import time in proxywhirl/api/core.py, which also logs a warning if * is configured).
  4. /api/stats and /api/metrics require the REST API key when PROXYWHIRL_REQUIRE_AUTH=true. /api/metrics can be exposed without a key only by explicitly setting PROXYWHIRL_PUBLIC_METRICS=true; use that only on an internal listener or behind network policy.
  5. The MCP server allows unauthenticated read actions by default; write actions (add, remove, fetch, validate, reset_cb, set_strategy) are rejected without a key unless PROXYWHIRL_MCP_ALLOW_UNAUTHENTICATED_WRITES is explicitly set — keep that variable unset in production.
  6. 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.sh

Monitoring

curl 'http://localhost:9091/api/v1/query?query=proxywhirl_available_proxies'
kubectl port-forward -n proxywhirl svc/grafana 3000:3000

Check 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.

See Also

On this page