Docs

Self-host InsightAssure

The same images VerticalServe runs, on one machine or your cloud, with your database, storage and model provider.

Install

Self-hosted InsightAssure is three containers: Postgres 16, the API and the console (nginx, which also proxies /api). You need Docker with Compose.

Install
cd deploy/selfhost
./install.sh            # asks for the organization name and administrator email,
                        # writes .env with generated passwords, then: docker compose up -d

The console is on http://<host>:8080. The first start runs the migrations (about a minute). .env is written with mode 600 and holds the generated Postgres and application passwords and the first administrator’s password; change that password after signing in. For anything beyond a trial, put a TLS-terminating proxy or your load balancer in front and set the two URLs below to the https address.

Services

ServiceImageNotes
postgrespostgres:16-alpineVolume pg. Health-checked before the API starts
apivserveinc/insightassure-apiPort 8136 inside the network. Volume data at /data. Runs as an unprivileged user
uivserveinc/insightassure-uiPublishes ${ASSURE_HTTP_PORT:-8080}; proxies /api to ASSURE_API_UPSTREAM (api:8136)

The database role

On first start the API uses ASSURE_DB_SUPERUSER_URL to create the application role assure_app as an ordinary role, NOSUPERUSER NOBYPASSRLS, with a 30-second statement timeout. That matters: Postgres row-level security does not bind a superuser or a role with BYPASSRLS, so the app must connect as an ordinary role for the per-organization policy to apply. The migration step warns if it is not.

Environment

VariableMeaning
ASSURE_EDITIONselfhosted here (hides the multi-workspace portfolio); saas on VerticalServe’s hosting
INSIGHT_DATABASE_URLThe app’s Postgres URL, without a password: postgresql://assure_app@postgres:5432/assure
INSIGHT_DATABASE_PASSWORD / INSIGHT_DATABASE_SECRETThe password for a local database, or a secret ref (aws-sm://, azure-kv://, gcp-sm://, file:///run/secrets/pg, env://VAR) resolved at start
INSIGHT_DATABASE_SCHEMAassure: the product’s tables, identity, connections and notifications share this schema
INSIGHT_DATABASE_SSLMODEdisable inside the compose network; require for a managed database
ASSURE_DB_SUPERUSER_URLUsed once to create assure_app; drop it when you manage the role yourself
ASSURE_ORG, ASSURE_ORG_NAMEThe organization slug and display name
ASSURE_ADMIN_EMAIL, ASSURE_ADMIN_PASSWORDThe first administrator, created only if absent; a restart never resets a password
ASSURE_PUBLIC_URL, ASSURE_CONSOLE_URLWhere the API and console are reached: used in agent install commands, Trust Center links and notifications
ASSURE_EVIDENCE_STOREEvidence files, policy PDFs and audit packages: file:///data/evidence (default), s3://bucket/prefix, az://account/container, gs://bucket, oci://namespace/bucket
ASSURE_AIfalse (the self-host default) answers every AI feature by rule; true uses the model below
INSIGHT_LLM_PROVIDERbedrock, azure_openai, vertex, oci or openai (any OpenAI-compatible endpoint, with INSIGHT_LLM_BASE_URL)
INSIGHT_CHAT_MODEL, INSIGHT_LLM_API_KEY_REFThe model id, and a secret ref to its key for key-based providers
INSIGHT_SEALED_SECRETSWhere integration credentials are sealed: auto (a configured secret store, else local AES-GCM), store or local
INSIGHT_SECRET_KEY_FILE / INSIGHT_SECRET_KEY_REFThe key that seals credentials locally; the image keeps it at /data/secret.key
INSIGHT_JWT_KEY_FILE / INSIGHT_JWT_KEY_REFThe token-signing key; generated once at /data/jwt-key.json unless you provide one
ASSURE_ALLOW_PRIVATE_INTEGRATIONStrue lets integrations call private addresses, for a Jira or GitLab inside your network. Off by default
ASSURE_BACKGROUND, ASSURE_MONITOR_INTERVAL_MINUTESThe background loop (syncs, monitors, reminders) and how often monitors run (60)
CORS_ORIGINS, LOG_FORMAT, ASSURE_METRICS_TOKENConsole origins when it is served from another host; json logs; a bearer token for /api/metrics

Keys and credentials

Integration credentials are never stored in clear and never returned by the API: they are sealed with insight_core.secrets.sealed, in your secret store when one is configured (one secret per connection) or as one AES-256-GCM token bound to the row. A field may instead hold ref:aws-sm://… to point at a secret you already keep.

Backups

Back up two things: the Postgres volume (pg_dump or your managed backups) and the data volume, which holds jwt-key.json, secret.key and, with the default store, the evidence files. Losing secret.key makes every sealed integration credential unreadable; reconnect the integrations if it happens.

Back up the database and the data volume
docker compose exec postgres pg_dump -U postgres assure > assure-$(date +%F).sql
docker run --rm -v insightassure_data:/data -v "$PWD":/backup alpine tar czf /backup/assure-data-$(date +%F).tgz -C /data .

Upgrades

Pull the new images and restart. Migrations run on every start under a Postgres advisory lock, so two API replicas starting together never race.

Upgrade
docker compose pull && docker compose up -d

Want a hand setting it up?

Tell us which frameworks, systems and cloud you run; we will map the integrations and the first audit with you.

Talk to us