Skip to content
M↓ View as Markdown ↗

Install with Docker Compose (single host)

The Compose bundle runs the whole of Actian AI Analyst on one Docker host: the server, the web app, Postgres (with pgvector), Keycloak for sign-in, a Caddy reverse proxy and, optionally, the JDBC bridge. It is a supported production target for one host. There is no high availability, there is one Postgres, and your backups are snapshots of the Docker volumes.

For a Kubernetes cluster, use Install on Kubernetes with Helm instead.

Availability

  • Who can do this: the operator who runs the Docker host, with shell access to it.
  • Deployment: Self-managed deployments only. The Compose bundle always runs air-gapped.

What the Compose bundle sets for you

Some settings are fixed in the Compose file and cannot be changed through .env:

Setting Value What it means
Network posture Air-gapped The server refuses vendor-hosted integrations at boot. See Network posture.
Entitlements From the Licence A missing or invalid Licence stops the server from starting. See Licence.
Identity Bundled Keycloak Members sign in through the Keycloak that runs in the stack.
File storage Local Docker volume Uploaded files and attachments are stored on the host.
Postgres max_connections=300 Headroom for the server and Keycloak, which share the Postgres container.

What runs

Service Role
proxy Caddy. Terminates TLS and is the only container that publishes ports (HTTP_PORT, default 80, and HTTPS_PORT, default 443). It routes /api to the server, /auth/realms, /auth/resources, /auth/admin and /auth/js to Keycloak, and everything else to the web app. Its request size limit is 260 MB (decimal), which is slightly below the 250 MiB (about 262 MB) file upload cap, so an upload right at the cap may be refused by the proxy.
web The web app. Its runtime configuration is rendered from the environment when the container starts.
server The whole backend in one process.
migrate A one-shot schema migration. The server waits for it to finish.
keycloak Sign-in, members and organizations.
postgres The product database and Keycloak's database.
jdbc-bridge Only with --profile jdbc. Needed for Actian-family warehouses.

Every container except proxy sits on a Docker internal network, which has no route off the host. Out of the box, the server can reach only the stack's own containers. To reach your LLM, warehouses and SMTP relay, see Reach your own services.

Host requirements

  • An amd64 (x86-64) host. The Release bundle ships amd64 images only.
  • Docker Engine 26 or later with Docker Compose v2 (docker compose). Both must be on the PATH.
  • 4 CPU and 8 GB RAM recommended.
  • A DNS name for the host that your members can resolve. This becomes PUBLIC_HOST.

Memory limits are set per container: the server is capped at 3 GB (SERVER_MEMORY_LIMIT) and Keycloak at 1 GB (KEYCLOAK_MEMORY_LIMIT). Do not lower the server limit below 2 GB. A 250 MiB CSV upload peaks near 1 GiB in the server while it is converted.

Note

No language model or model weights ship with AI Analyst. Chat needs an OpenAI-compatible API that you run and that supports tool calling. See Configure inference.

Step 1: Run the installer

  1. Copy the Release bundle archive to the host and extract it. Check the archive before you carry it across the air gap, as described in Release bundle.
  2. From the extracted bundle directory, run the installer. Pass the directory to install into, or leave it out to use ./ai-analyst:

    ./install.sh /opt/ai-analyst
    

The installer:

  1. Runs verify.sh, which checks the bundle's signatures and checksums offline. It stops at the first mismatch.
  2. Loads every image into Docker.
  3. Copies the Compose files into the target directory. On a fresh install it creates .env from .env.example. An existing .env, ./licence and ./certs are kept.
  4. Pins every *_IMAGE value and AI_ANALYST_VERSION in .env to the images it just loaded.
  5. Prints the remaining steps.

Tip

Compare the public-key fingerprint that verify.sh prints with the one Actian publishes for the release before you trust a successful run. The key travels inside the bundle it vouches for.

Running a newer bundle's install.sh over the same directory is how you upgrade. See Upgrade and back up.

Step 2: Fill in .env

The installer creates .env from .env.example. Edit .env in the target directory and set these values. .env.example ships example values for PUBLIC_HOST, BOOTSTRAP_ORG_NAME and BOOTSTRAP_ADMIN_EMAIL, and the stack starts with them, so you must replace them. The other four values are blank, and the stack refuses to start while any of them is empty.

Variable What to set
PUBLIC_HOST Ships with an example value; replace it. The hostname members type in the browser. DNS must resolve it to this host. It cannot be localhost, because containers resolve this name to the proxy.
BOOTSTRAP_ORG_NAME Ships with an example value; replace it. The name of the first organization, created on first boot.
BOOTSTRAP_ADMIN_EMAIL Ships with an example value; replace it. The email address of that organization's first Administrator.
POSTGRES_PASSWORD The Postgres password. It is embedded in a connection URL, so it must be URL-safe.
WAREHOUSE_CREDENTIAL_ENCRYPTION_KEY The key that encrypts stored secrets. At least 16 characters.
KEYCLOAK_ADMIN_CLIENT_SECRET The secret the server uses to manage members and organizations in Keycloak.
KEYCLOAK_ADMIN_PASSWORD The password for Keycloak's own administrator account (admin console at https://<PUBLIC_HOST>/auth/admin/). The user name is admin unless you set KEYCLOAK_ADMIN_USERNAME.

Generate each secret with:

openssl rand -hex 32

Hex output is URL-safe, which POSTGRES_PASSWORD needs.

Also set these:

  • BOOTSTRAP_ADMIN_PASSWORD (strongly recommended): the Administrator's temporary password for the first sign-in. .env.example ships a placeholder value, so replace it. If you leave it unset, the Administrator is created with no password and you must set one in the Keycloak admin console. See Identity and first sign-in.
  • LLM_*: your OpenAI-compatible chat API. Without it, members see Chat needs an LLM endpoint until an organization adds its own endpoint under Settings → Inference. See Configure inference.
LLM_PROVIDER=openai-compatible
LLM_BASE_URL=http://llm.example.internal:8000/v1
LLM_API_KEY=<API_KEY>
LLM_MODEL=<MODEL_NAME>
# generic, or reasoning for models that accept reasoning_effort
LLM_CAPABILITY_PRESET=generic

Keep your secrets safe

Store the generated values somewhere safe, together with your backups. Changing them after the first boot locks you out:

  • Changing POSTGRES_PASSWORD locks you out of the database.
  • Changing or losing WAREHOUSE_CREDENTIAL_ENCRYPTION_KEY loses every stored warehouse credential, every API key for an LLM or Embedding endpoint that an organization added under Settings → Inference, and the catalog API secrets stored on connections.

Optional settings

Variable Purpose
HTTPS_PORT, HTTP_PORT Ports the proxy publishes. Defaults are 443 and 80.
PUBLIC_ORIGIN Set only when HTTPS_PORT is not 443, for example https://analyst.example.internal:8443.
EMBEDDING_MODEL, EMBEDDING_BASE_URL, EMBEDDING_API_KEY, EMBEDDING_DIMENSIONS Your OpenAI-compatible embedding API. Without it, semantic-layer search is lexical only.
EMAIL_TRANSPORT, EMAIL_FROM, SMTP_HOST, SMTP_PORT, SMTP_TLS, SMTP_USER, SMTP_PASSWORD An SMTP relay for product email, such as Scheduled Insights and notifications. SMTP_TLS is starttls (default), implicit (port 465) or none.
UNSUBSCRIBE_SIGNING_KEY Signs the unsubscribe links in notification emails.
AGENT_STREAM_TIMEOUT_MS How long one agent response may take, in milliseconds (240000 when unset). Raise it for self-hosted models that need minutes to answer.
BOOTSTRAP_SIGNUP_DOMAINS Sign-up domains for the first organization, comma-separated. Read only on the boot that creates the organization. See Identity and first sign-in.
VITE_EDITION_LABEL An edition label, for example Enterprise Edition. It adds a line reading "AI Analyst label" to the footer of the organization switcher menu.
SERVER_MEMORY_LIMIT, KEYCLOAK_MEMORY_LIMIT Container memory limits (3g and 1g by default).

For every variable, see the Configuration reference.

Step 3: Install the Licence

Put the signed Licence that Actian sent you in the licence directory of the install, named licence.json:

cp licence.json /opt/ai-analyst/licence/licence.json

To use another directory or file name, set LICENCE_DIR or LICENCE_FILE in .env.

Images from a Release bundle carry Actian's Licence verification key built in, so you do not need a key file. The installer's closing message also mentions licence-public.pem. With Release-bundle images you need only licence.json.

The server reads the Licence once, at startup. After you replace it, restart the server service. See Licence.

Step 4: Set up TLS

By default, Caddy issues the site certificate from its own internal certificate authority (CA). This works immediately, but browsers show a certificate warning until that CA's root certificate is trusted on members' machines. To export the root certificate after the first start:

docker compose cp proxy:/data/caddy/pki/authorities/local/root.crt .

For production, use your own certificate:

  1. Put the certificate (full chain) in ./certs/tls.crt and its private key in ./certs/tls.key.
  2. In .env, set:

    CADDY_TLS=/certs/tls.crt /certs/tls.key
    
  3. If the certificate chains to a private CA, also put that CA certificate in ./certs/ca.crt and set:

    SERVER_EXTRA_CA_CERTS=/etc/ai-analyst/certs/ca.crt
    

    The server fetches Keycloak's signing keys through the proxy, so it must trust the proxy's certificate. Without this setting, every API call fails with 401.

    This setting also decides which private CAs the server trusts for your LLM, Embedding and warehouse endpoints. It replaces the default Caddy internal CA, so put every CA the server must trust in that one file. See Private certificate authorities.

Step 5: Start the stack

From the install directory, run:

docker compose up -d --wait

The first boot takes a minute or two:

  1. Postgres initializes its databases.
  2. Keycloak imports the sign-in realm. This happens only when the realm does not exist yet, so later restarts and upgrades keep the changes you make in the Keycloak admin console.
  3. migrate applies the database schema.
  4. The server starts, and the Operator bootstrap creates the first organization and its Administrator from the BOOTSTRAP_* values.

When the command returns, open https://<PUBLIC_HOST>/ and sign in as the Administrator with BOOTSTRAP_ADMIN_EMAIL and the temporary password. Keycloak asks for a new password and a name. For details, including inviting members (which needs SMTP), see Identity and first sign-in.

Reach your own services

Because the internal network has no route off the host, the server cannot reach your LLM endpoint, warehouses or SMTP relay until you connect them. There are two ways.

Option A: Run the services as containers on this host

Run the service (for example, an LLM server) as a container on the same host and attach it to the stack's network, ai-analyst_internal:

docker run -d --name llm --network ai-analyst_internal <your-llm-image>

Then point the stack at it by container name, for example LLM_BASE_URL=http://llm:8000/v1. Nothing else in the stack changes.

Option B: Opt in to your network

Start the stack with the customer-network override:

docker compose -f docker-compose.yml -f compose.customer-network.yml up -d --wait

This attaches server, keycloak and jdbc-bridge to one more Docker bridge network (named ai-analyst-customer unless you set CUSTOMER_NETWORK_NAME). That network is routed like any Docker bridge.

Your host firewall now keeps the install air-gapped

With the override, Docker no longer blocks traffic leaving the host. Use the host firewall (for example, the DOCKER-USER iptables chain) to allow traffic out of that bridge only to your own address ranges: your LLM and Embedding endpoints, warehouses and SMTP relay.

Keycloak also needs this route to reach an SMTP relay for invitation and password-reset emails.

Use the same -f options on every later docker compose command for this install.

Private warehouse addresses

On a Compose install, warehouse connections may connect to the private ranges 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16 and loopback by default. To narrow this, set WAREHOUSE_EGRESS_ALLOW_PRIVATE_CIDRS in .env to a comma-separated list of CIDRs. Once it is set, only the listed private ranges are allowed. The same check applies to LLM and Embedding endpoints that an organization adds under Settings → Inference. This differs from the Helm install, where private ranges are refused until you list them. Link-local addresses are never allowed. See Warehouse connectivity.

Enable the JDBC bridge

Actian-family warehouses (Actian, Ingres, Informix and Zen) connect through the JDBC bridge.

  1. In .env, set:

    JDBC_BRIDGE_URL=http://jdbc-bridge:8080
    JDBC_BRIDGE_TOKEN=<generate with: openssl rand -hex 32>
    

    The bridge refuses to start without a non-blank token.

  2. Start the stack with the jdbc profile:

    docker compose --profile jdbc up -d --wait
    

    If you also use the customer-network override, combine both:

    docker compose -f docker-compose.yml -f compose.customer-network.yml --profile jdbc up -d --wait
    

Troubleshooting

Symptom Likely cause What to do
docker compose up stops with set <VARIABLE> in .env One of the four secrets is missing or empty. Set the named variable in .env. See Step 2.
The server does not become healthy The server refused to boot. Run docker compose ps and docker compose logs server. The log names the offending key. Messages starting NETWORK_POSTURE=air-gapped mean a vendor-hosted setting is present, such as LLM_PROVIDER=anthropic or openai, which are Actian Inference settings. Use openai-compatible with your own API. Messages starting LICENCE_PATH mean the Licence is missing, malformed or not signed by Actian. Missing required env vars lists keys to add.
Every API call returns 401 The server cannot verify Keycloak's tokens. Check that PUBLIC_HOST is not localhost. With your own certificate from a private CA, check that SERVER_EXTRA_CA_CERTS names that CA.
Members see Chat needs an LLM endpoint There is no deployment default LLM_* and the organization has not added its own endpoint, or the server cannot reach the endpoint. Set LLM_* and restart, or add an endpoint under Settings → Inference. Check that the server can reach the endpoint (see Reach your own services).
Browsers show a certificate warning The default internal CA is in use. Trust the exported root certificate on members' machines, or install your own certificate (Step 4).
Inviting members fails Keycloak has no SMTP relay. Configure SMTP in Keycloak and use the customer-network override so Keycloak can reach the relay. See Identity and first sign-in.

To collect information for Actian support, see Diagnostic export.

Next steps