Deployment & self-hosting
QueryPilot is designed to be self-hosted. The supported deployment today is the repository’s Docker Compose file, which runs four services plus optional profiles.
Services
Section titled “Services”| Service | Image source | Host port | Internal port | Health checks |
|---|---|---|---|---|
postgres |
postgres:16-alpine |
POSTGRES_PORT (5432) |
5432 | pg_isready |
api |
infrastructure/docker/api.Dockerfile |
API_PORT (8080) |
8080 | /health/live, /health/ready |
worker |
infrastructure/docker/worker.Dockerfile |
None | 8081 | /health/live, /health/ready |
web |
infrastructure/docker/web.Dockerfile |
WEB_PORT (3000) |
3000 | None |
agent (profile agent) |
infrastructure/docker/agent.Dockerfile |
None | 8082 | /health/live, /health/ready |
prometheus (profile observability) |
prom/prometheus |
PROMETHEUS_PORT (9090) |
9090 | None |
grafana (profile observability) |
grafana/grafana |
GRAFANA_PORT (3001) |
3000 | None |
ollama (profile ai) |
ollama/ollama |
OLLAMA_PORT (11434) |
11434 | None |
api and worker wait for PostgreSQL to be healthy; agent waits for the API to be healthy.
Environment
Section titled “Environment”Compose reads a .env file next to docker-compose.yml. The variables the Compose file uses:
| Variable | Default | Notes |
|---|---|---|
QUERYPILOT_ENCRYPTION_KEY |
None | Required. 32 bytes, base64 or hex. openssl rand -base64 32. |
POSTGRES_USER / POSTGRES_PASSWORD / POSTGRES_DB |
querypilot |
Credentials of the bundled storage database. Change the password. |
NEXT_PUBLIC_API_URL |
http://localhost:8080 |
API URL as seen from the browser, not from inside the Compose network. |
QUERYPILOT_CORS_ORIGINS |
http://localhost:3000 |
Comma-separated web origins allowed to call the API. |
LOG_LEVEL |
info |
debug, info, warn, error. |
API_PORT, WEB_PORT, POSTGRES_PORT |
8080, 3000, 5432 | Host ports. |
GRAFANA_PASSWORD |
admin |
Only with the observability profile. |
Every other API/worker setting can be passed the same way; see the configuration reference.
Production checklist
Section titled “Production checklist”- Restrict network access. QueryPilot does not have user authentication yet (Roadmap). Expose the web app and API only on a trusted network, behind a VPN, or behind an authenticating reverse proxy.
- Terminate TLS in front of the API and web app with a reverse proxy or load balancer. Agents send their bearer token on every request, so the agent → API hop should be HTTPS.
- Set
QUERYPILOT_PUBLIC_API_URLto the URL agents should use. It appears in the setup commands the UI generates; without it, the URL of the operator’s own request is used. - Set
NEXT_PUBLIC_API_URLandQUERYPILOT_CORS_ORIGINSto your public API URL and web origin. Next.js inlinesNEXT_PUBLIC_*variables into browser code when the web app is built, and the web client falls back tohttp://localhost:8080when the variable is unset. If the browser still callslocalhost:8080after you change it, make the variable available at image build time and rebuild thewebimage. - Protect the encryption key. Store it in your secret manager and back it up. Without it, the stored database credentials cannot be decrypted and must be re-entered.
- Change
POSTGRES_PASSWORDand consider not publishing port 5432 on the host at all. - Back up the storage database (
querypilot-postgres-datavolume) like any other PostgreSQL. - Run agents close to the observed databases, not on the QueryPilot host, and give them the least-privilege role from PostgreSQL prerequisites.
Migrations
Section titled “Migrations”The API applies pending migrations at startup, using an advisory lock so several API instances starting together do not race. To manage schema changes out of band instead:
QUERYPILOT_AUTO_MIGRATE=falseand run pnpm db:migrate with DATABASE_URL pointing at the storage database.
Configuration file
Section titled “Configuration file”Settings can also come from a YAML file. Mount it into the api and worker containers and point
QUERYPILOT_CONFIG_FILE at it. Precedence is: built-in defaults → configuration file → environment
variables. Secrets are only ever read from the environment.
deployment: instanceName: productionprivacy: storeQueryText: trueagent: intervals: queryStatsMs: 30000 planCapture: intervalMinutes: 30Monitoring QueryPilot
Section titled “Monitoring QueryPilot”Every service exposes Prometheus metrics at /metrics (API on 8080, worker on 8081, agent on 8082).
The observability profile starts Prometheus pre-configured to scrape the API and worker, and
Grafana:
docker compose --profile observability up -dHealth endpoints:
GET /health/live: the process is running. Never touches PostgreSQL, so a database outage does not get a healthy container killed.GET /health/ready: required dependencies are available (non-200 otherwise).GET /api/v1/health: the API’s detailed report, including optional subsystems.
Upgrading
Section titled “Upgrading”git pulldocker compose up -d --buildThe API migrates the storage database on startup. Agents and the API negotiate a protocol version at registration; upgrade the API before the agents.