Self-host TraceIQ
Run a private local instance with one command, or deploy the API, PostgreSQL, Redis, and dashboard on infrastructure you control. Local authentication needs no hosted identity provider; Supabase remains available for shared installations that need accounts, teams, invitations, and 2FA.
One-command private installation
Install Docker with Docker Compose, clone the repository, and start the complete local stack:
docker compose -f compose.local.yml up -d --build
Open http://localhost:3000. Compose starts PostgreSQL 18, runs every pending migration, starts Redis and the API, then starts the dashboard. No TraceIQ account or Supabase project is required.
docker compose -f compose.local.yml ps curl http://localhost:4000/health
Stop the containers without deleting PostgreSQL data:
docker compose -f compose.local.yml down
Choose an authentication mode
Supabase is not required. Choose the path that matches who can reach the dashboard:
Private local mode
No login, Supabase project, or external identity service. Intended for one operator on localhost, a private machine, or a trusted private network.
AUTH_MODE=local
NEXT_PUBLIC_AUTH_MODE=localSupabase mode
Use when multiple people need accounts, organizations, invitations, team permissions, and two-factor authentication.
AUTH_MODE=supabase
NEXT_PUBLIC_AUTH_MODE=supabaseThe API and dashboard modes must match. Supabase variables are read only in Supabase mode. Local mode contains no login boundary, so never expose its dashboard directly to the public internet; keep it loopback-bound, behind a VPN, or protected by a trusted access proxy.
Production topology
The verified production shape keeps the public dashboard and API deployment independent:
Dashboard host (Vercel or Node.js)
|
v
API domain -> Caddy -> 127.0.0.1:4000
|
Docker Compose
|- NestJS API
|- PostgreSQL 18
- Redis 7Dashboard— Deploy apps/dashboard as a Next.js application and set its NEXT_PUBLIC_* values at build time.API— Bind port 4000 to loopback and expose it only through a TLS reverse proxy such as Caddy.PostgreSQL and Redis— Keep both services on the private Compose network; do not publish their ports.CORS— Set CORS_ORIGINS to the exact dashboard and instrumented website origins that should reach the API.
Production environment
Copy .env.example to .env, replace every placeholder, and keep the file out of Git. Begin with the values common to both authentication modes:
DATABASE_URL=postgresql://traceiq:UNIQUE_PASSWORD@postgres:5432/traceiq?sslmode=disable DATABASE_SSL=false REDIS_URL=redis://redis:6379 CORS_ORIGINS=https://analytics.example.com,https://www.example.com NEXT_PUBLIC_API_URL=https://api.example.com NEXT_PUBLIC_WAITLIST_ONLY=false
Option A: private local authentication
AUTH_MODE=local NEXT_PUBLIC_AUTH_MODE=local LOCAL_PROJECT_WRITE_KEY=replace-with-a-random-write-key # Required only when the API container binds beyond loopback internally. # Keep the host port loopback-only or privately protected. LOCAL_AUTH_ALLOW_NETWORK=true
No SUPABASE_* or NEXT_PUBLIC_SUPABASE_* values are needed for this path.
Option B: Supabase authentication
AUTH_MODE=supabase NEXT_PUBLIC_AUTH_MODE=supabase SUPABASE_URL=https://YOUR_PROJECT.supabase.co SUPABASE_ANON_KEY=YOUR_ANON_KEY SUPABASE_SERVICE_ROLE_KEY=YOUR_SERVICE_ROLE_KEY NEXT_PUBLIC_SUPABASE_URL=https://YOUR_PROJECT.supabase.co NEXT_PUBLIC_SUPABASE_ANON_KEY=YOUR_ANON_KEY
Inside Compose, use postgres rather than localhost as the database hostname. Only Supabase-mode installations need to configure the production dashboard callback URL in Supabase Auth. Never expose SUPABASE_SERVICE_ROLE_KEY to the dashboard or browser.
First VPS deployment
docker compose up -d postgres redis docker compose build api docker compose run --rm api npm run migrate --workspace=@traceiq/api docker compose up -d api docker compose ps curl http://127.0.0.1:4000/health
Point the API DNS record to the VPS and proxy the public API hostname to the loopback API:
api.example.com {
reverse_proxy 127.0.0.1:4000
}Then build or deploy the dashboard with its production environment values and verify that its origin is included in CORS_ORIGINS.
Backups, migrations, and safe upgrades
Back up PostgreSQL before migrations or major upgrades. Store the dump outside the Compose volume and test restoration periodically.
docker compose exec -T postgres pg_dump -U traceiq -d traceiq --no-owner --no-acl > traceiq-backup.sql
git pull --ff-only docker compose build api docker compose run --rm api npm run migrate --workspace=@traceiq/api docker compose up -d api docker compose ps curl http://127.0.0.1:4000/health
docker compose down -v during an upgrade. The -v flag removes the PostgreSQL volume and can permanently delete analytics data.Operational checklist
Credentials— Use unique database passwords and rotate exposed Supabase, project, email, AI, and access-token secrets.Backups— Back up before migrations, keep copies outside the VPS, and test restoration.Network— Expose only the TLS proxy; keep API, PostgreSQL, and Redis ports private or loopback-bound.Monitoring— Watch API health, disk capacity, PostgreSQL growth, backup completion, and container restarts.Updates— Review dependency and container-image changes before deploying them.

