QueryProxy
Documentation menu

Manual installation

Install QueryProxy without Docker — requirements, setup steps, and the queue worker that approved queries depend on.

Updated:

Prefer running QueryProxy directly on a server? It is a standard Laravel application.

Requirements

  • PHP ≥ 8.3 with the PDO drivers for the databases you will proxy (pdo_pgsql, pdo_mysql, pdo_sqlite; pdo_sqlsrv for SQL Server targets)
  • Composer
  • Node.js 20.19+ or 22.12+ (only to build the frontend assets; this is what the pinned Vite 8 needs)

Steps

git clone https://github.com/QueryProxy/QueryProxy.git
cd QueryProxy

composer install
cp .env.example .env
php artisan key:generate

touch database/database.sqlite
php artisan migrate            # add --seed for the demo team
php artisan queryproxy:create-admin   # the first administrator (skip it if you seeded the demo team)

npm install && npm run build

Then run the three processes:

php artisan serve                                                        # the web portal (http://localhost:7432)
php artisan queue:work --queue=queries,default --tries=1 --timeout=310   # the worker; --timeout = QUERYPROXY_EXECUTION_TIMEOUT + 10 (300 by default)
php artisan schedule:work                                                # the scheduler

The queue worker is not optional. Approved queries execute on the worker, never inside a web request. Without a running worker, requests will be approved and then sit in the queue forever. In production, keep it alive with a process supervisor (systemd, Supervisor) and set its --timeout slightly above QUERYPROXY_EXECUTION_TIMEOUT.

The retry_after warning (at or below the execution timeout) is logged when queue:work starts, and also for queue:work --once and queue:listen. If you run the worker from the repository’s Compose example, its --timeout comes from the image entrypoint (QUERYPROXY_EXECUTION_TIMEOUT + 10); on a manual install you set the number yourself.

Production notes

  • Serve the app through PHP-FPM behind a real web server (nginx, Caddy) with TLS; php artisan serve is fine for evaluation only. The official Docker image already runs nginx + php-fpm as a non-root user — mirror that for a manual install. When behind a TLS-terminating proxy, 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 then X-Forwarded-Proto is ignored (HTTPS is not detected, no HSTS header) and audit entries record the proxy’s address instead of the client’s. Never use *. Set APP_URL to the address users actually reach — the request host is pinned to it. See Configuration.
  • Keep QUERYPROXY_RESULT_DISK on a private disk. QueryProxy refuses to write results to a publicly visible disk; result paths are predictable, so such a disk would bypass the download authorization entirely.
  • Set APP_KEY explicitly and keep it stable across deploys. It encrypts your stored connection credentials and chat secrets; a regenerated key makes them unreadable. Rotate keys via APP_PREVIOUS_KEYS so existing ciphertext still decrypts.
  • Point DB_* at MySQL or PostgreSQL when SQLite no longer fits — see Configuration.
  • The scheduler powers result-retention pruning; run it via schedule:work or a cron entry calling php artisan schedule:run every minute.
  • Cache the configuration on deploy: php artisan config:cache && php artisan route:cache. TRUSTED_PROXIES and TRUSTED_HOSTS are read through the config, so .env is enough — re-run config:cache after changing them.

Arrow keys to move, Enter to open.