QueryProxy
Documentation menu

Production hardening

A checklist for running QueryProxy on a reachable network, from the application key and HTTPS to read-only connections and what the defaults already cover.

Updated:

QueryProxy stores the credentials to every database it fronts, so treat the instance itself as sensitive. Work through this list before exposing it to a network.

  • For teams or users who only read, register a separate connection with a database user that has SELECT privileges only. Keep write access on a different connection, since approved writes run through the connection they were submitted on.
  • Point that read-only connection at a replica where you can.
  • Restrict the network path between QueryProxy and the target database.
  • On PostgreSQL, check the transport yourself: the connection uses sslmode=prefer today, and a TLS setting arrives in v0.3.0.

The SQL guard is not a last line of defence. Until read-only execution on the database side arrives (v0.3.0), build the defence with database privileges as well.

Checklist

  • Set APP_KEY explicitly and keep it stable. It encrypts connection credentials and chat secrets; changing it makes every stored credential unreadable. Generate one with docker run --rm queryproxy/queryproxy php artisan key:generate --show and pass it as -e APP_KEY=... (every container of the same instance must share it). When rotating, move the old key into APP_PREVIOUS_KEYS so existing ciphertext still decrypts. Without an explicit APP_KEY, the container generates one on first boot and persists it to the data volume.
  • Serve over HTTPS behind a TLS-terminating reverse proxy (the container serves plain HTTP on :7432). Then set SESSION_SECURE_COOKIE=true.
  • Set TRUSTED_PROXIES to your proxy’s IP or CIDR whenever a proxy sits in front of QueryProxy. No proxy is trusted by default, so until you set it the app reads the connecting peer as the client: X-Forwarded-Proto is ignored (HTTPS is not detected, so no HSTS header) and audit entries record the proxy’s address. Never set it to *: that lets any client forge X-Forwarded-For, which both fakes the audit trail’s client IP and hands out unlimited login and 2FA attempts, since those throttles are keyed per IP. See Configuration.
  • Keep demo seeding off (QUERYPROXY_SEED_DEMO=false, the default) on any reachable instance.
  • Require 2FA for privileged roles with QUERYPROXY_REQUIRE_2FA=admins (or dba / all). Users are funneled to enrollment on next login.
  • Restrict connection targets with QUERYPROXY_CONNECTION_HOST_DENYLIST / QUERYPROXY_SQLITE_ALLOWED_DIR if DBAs should not reach arbitrary hosts.

What is on by default

No configuration is needed for these:

  • Security response headers, including a Content-Security-Policy, and a rate limit on the Livewire endpoint.
  • Encrypted connection credentials at rest and TOTP two-factor authentication (optional until you require it).
  • Comment-normalized SQL guards with an executor-enforced row ceiling.
  • Replay-protected, identity-bound chat callbacks, and self-approval prevention.
  • Immutable audit logs and login/webhook rate limiting.
  • SSRF-guarded outbound webhooks.
  • Masked-at-write, fail-closed result storage.

Next steps

Arrow keys to move, Enter to open.