--- description: Install Actian AI Analyst on a single Docker host from the Release bundle, configure .env, the Licence and TLS, and connect your own LLM, warehouses and SMTP relay. --- # 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](install-kubernetes-helm.md) instead. !!! info "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](network-posture.md). | | Entitlements | From the Licence | A missing or invalid Licence stops the server from starting. See [Licence](licence.md). | | 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](#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](configure-inference.md). ## 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](release-bundle.md). 2. From the extracted bundle directory, run the installer. Pass the directory to install into, or leave it out to use `./ai-analyst`: ```sh ./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](upgrade-and-backup.md). ## 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:///auth/admin/`). The user name is `admin` unless you set `KEYCLOAK_ADMIN_USERNAME`. | Generate each secret with: ```sh 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](identity-and-first-sign-in.md). - **`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](configure-inference.md). ```bash LLM_PROVIDER=openai-compatible LLM_BASE_URL=http://llm.example.internal:8000/v1 LLM_API_KEY= LLM_MODEL= # generic, or reasoning for models that accept reasoning_effort LLM_CAPABILITY_PRESET=generic ``` !!! warning "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](identity-and-first-sign-in.md). | | `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](configuration-reference.md). ## Step 3: Install the Licence Put the signed Licence that Actian sent you in the `licence` directory of the install, named `licence.json`: ```sh 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](licence.md). ## 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: ```sh 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: ```bash 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: ```bash 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](configuration-reference.md#private-certificate-authorities). ## Step 5: Start the stack From the install directory, run: ```sh 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:///` 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](identity-and-first-sign-in.md). ## 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`: ```sh docker run -d --name llm --network ai-analyst_internal ``` 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: ```sh 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. !!! warning "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](warehouse-connectivity.md). ## Enable the JDBC bridge Actian-family warehouses (Actian, Ingres, Informix and Zen) connect through the JDBC bridge. 1. In `.env`, set: ```bash JDBC_BRIDGE_URL=http://jdbc-bridge:8080 JDBC_BRIDGE_TOKEN= ``` The bridge refuses to start without a non-blank token. 2. Start the stack with the `jdbc` profile: ```sh docker compose --profile jdbc up -d --wait ``` If you also use the customer-network override, combine both: ```sh 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 in .env` | One of the four secrets is missing or empty. | Set the named variable in `.env`. See [Step 2](#step-2-fill-in-env). | | 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](#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](#step-4-set-up-tls)). | | 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](identity-and-first-sign-in.md). | To collect information for Actian support, see [Diagnostic export](diagnostic-export.md). ## Next steps - [Configure inference](configure-inference.md) - [Warehouse connectivity](warehouse-connectivity.md) - [Identity and first sign-in](identity-and-first-sign-in.md) - [Upgrade and back up](upgrade-and-backup.md) - [Scaling and operations](scaling-and-operations.md)