Docker Compose

This page takes you from nothing to a running, healthy Adriano with Docker Compose, against your own catalog file and identity provider. Read Deploying Adriano first; it explains what you deploy and how to register the identity provider client. Read this page top to bottom; every step is required unless marked optional.

Prerequisites

  • Docker Engine with Docker Compose v2.24 or newer. Older Compose versions cannot read the optional environment file this stack uses.

  • The things listed in Deploying Adriano: an identity provider client, a record source and a TLS-terminating ingress or load balancer.

Obtaining the stack

Download docker-compose.yml and deploy/compose.defaults.env from the source archive of the release you deploy, and keep the relative paths: put compose.defaults.env in a deploy/ folder next to docker-compose.yml.

The stack has two services:

db

PostgreSQL 18 with a named volume (adriano-db-data). Remove it, and the depends_on entry of adriano, if you use your own PostgreSQL (see Using your own PostgreSQL).

adriano

The Adriano image. It is the only service published on the host (port 8180 by default).

Pin the image to one release in .env (next section) and pull it:

docker compose pull adriano

Configuration

You provide two files next to docker-compose.yml:

.env

Environment settings: database password, OIDC settings, and the secrets that the catalog file names (source access tokens and push tokens). Every setting is described in Configuration reference. Keep this file out of version control; it holds secrets.

catalog.yaml

Which sources to index, the approval policy and the role permissions. See The catalog file.

A minimal production .env:

# The release to run: a full version, never a channel
ADRIANO_IMAGE_TAG=2026.10.1

# Database (the bundled db service)
ADRIANO_DB_PASSWORD=<long random password>
ADRIANO_DATABASE_URL=postgresql://adriano:<same password>@db:5432/adriano

# Your catalog file on the Docker host
ADRIANO_CATALOG_FILE_HOST=./catalog.yaml

# OIDC: used by the API and by the web UI
ADRIANO_OIDC_AUTHORITY=https://idp.example.com/realms/adr
ADRIANO_OIDC_CLIENT_ID=adriano-web
ADRIANO_OIDC_AUDIENCE=adr_viewer
ADRIANO_OIDC_ROLES_CLAIM=realm_access.roles

# Secrets that catalog.yaml refers to by name
# only needed for a gitlab source
ADRIANO_GITLAB_TOKEN_PLATFORM=<GitLab access token>
ADRIANO_PUSH_TOKEN_PLATFORM=<long random token>

# Never set the dev-only sign-in settings here:
# ADRIANO_DEV_AUTH_ENABLED, ADRIANO_DEV_SHARED_SECRET

Warning

ADRIANO_CATALOG_FILE_HOST defaults to the bundled demo catalog. Always set it to your own file, or Adriano indexes the sample records. The ./samples mount in docker-compose.yml only serves the demo catalog; remove it once you use your own.

The bundled database address uses the default credentials. When you change ADRIANO_DB_PASSWORD, change the password in ADRIANO_DATABASE_URL as well.

Validate the catalog file before the first start (the database does not need to be running):

docker compose run --rm --no-deps adriano adriano check-config

Fix every line marked error before you continue.

Bring-up

  1. Start the stack:

    docker compose up -d
    

    Compose starts db, waits until it is healthy, then starts adriano. Adriano applies pending database migrations before it serves (set ADRIANO_MIGRATE_ON_START to false to turn this off and run adriano migrate yourself).

  2. Point your ingress or load balancer at the published port, with TLS. Forward the X-Forwarded-For, X-Forwarded-Proto and X-Forwarded-Host headers. Adriano trusts them only from the addresses in ADRIANO_FORWARDED_ALLOW_IPS: set it to your proxy’s address, or to * if only the proxy can reach the published port.

  3. Run the first poll, so the catalog has content:

    docker compose exec adriano adriano poll
    

    Each registration prints one line with its status and counts. See Polling sources for what partial and failed mean.

  4. Schedule polls, as described in the next section.

  5. If CI should push draft records, hand out the push tokens (Pushing candidates from CI).

Scheduling polls

Compose has no scheduler. Run adriano poll from cron or a systemd timer on the Docker host, for example every 15 minutes:

*/15 * * * * docker compose -f /opt/adriano/docker-compose.yml exec -T adriano adriano poll >> /var/log/adriano-poll.log 2>&1

-T is needed because cron has no terminal. Alert on a non-zero exit code; Polling sources lists them.

Verification

  1. The service is healthy:

    docker compose ps -a
    

    adriano and db show healthy.

  2. The health endpoint answers:

    curl -fsS http://localhost:8180/healthz
    

    A healthy production deployment answers:

    {"status": "ok", "database": "ok", "config": "ok",
     "policy": "configured", "registrations": "synced",
     "rbac": "configured", "auth": "oidc", "version": "2026.10.1"}
    

    version is the release you pinned. auth must be oidc. Any value containing dev means the development sign-in bypass is active: stop and fix it (see Authentication and access). Every field is explained in Health checks and logs.

  3. Open the web UI through your ingress and sign in with a user that has the read permission. The sign-in page must not offer a “Dev sign-in” button.

  4. Sign in as an operator and open the Sources page. Every registration should show the status OK.

Trusting an internal certificate authority

If your identity provider or GitLab uses a certificate from an internal certificate authority, give Adriano the authority’s certificate. Adriano then trusts it in addition to the public authorities. Put the PEM file (for example internal-ca.pem) in a folder on the Docker host, and mount that folder read-only in a docker-compose.override.yml next to docker-compose.yml:

services:
  adriano:
    volumes:
      - ./ca:/etc/adriano-ca:ro

Then point ADRIANO_EXTRA_CA_CERTS at the mounted folder in .env:

ADRIANO_EXTRA_CA_CERTS=/etc/adriano-ca

Adriano reads the *.pem and *.crt files of the folder. Check that it loads them; the log lists the subject of every added certificate:

docker compose run --rm --no-deps adriano adriano check-config

A wrong path or a file without a certificate stops Adriano at start, and the message names the file. Do not turn off verification with ADRIANO_TLS_VERIFY in production.

Upgrade and rollback

An upgrade may change the database schema, and a schema change cannot be undone by going back to the old image. Back up the database first (Backup, restore and retention). Then:

  1. Set ADRIANO_IMAGE_TAG in .env to the new version.

  2. Validate your catalog file against the new release (docker compose run --rm --no-deps adriano adriano check-config).

  3. Pull and recreate:

    docker compose pull adriano
    docker compose up -d
    

    The new container applies the migrations before it serves. Plan a short maintenance window: the old release may not work against the new schema.

  4. Verify as above.

To roll back, set the previous version and run docker compose up -d. That works only while the release you left did not change the schema. If it did, restore the backup taken before the upgrade (Backup, restore and retention) and then start the previous version. Upgrading has the details.

Using your own PostgreSQL

To use a managed PostgreSQL (version 18 is what Adriano is tested with):

  1. Set ADRIANO_DATABASE_URL in .env to its address. Your value wins over the bundled default.

  2. Remove the db service and the depends_on entry of adriano from docker-compose.yml.

For production, create the two database users described in Database roles and tamper resistance. Run the migrations with the owner and the application with the application user: start once with ADRIANO_DATABASE_URL set to the owner’s address, then switch it to the application user’s address, or set ADRIANO_MIGRATE_ON_START to false and run the migrations with the owner before each upgrade:

docker compose run --rm --no-deps \
  -e ADRIANO_DATABASE_URL=<owner address> adriano adriano migrate