Docker Compose Deployment

authlance/deployment docker-compose is a working reference environment that boots MySQL, Ory Kratos, Ory Hydra, the Auth Container, the License Operator, NATS, and an nginx edge proxy. The Loop/Scaffold dashboard remains on the host machine and talks to the containers through the same credentials rendered into .env.

Stack Contents

  • MySQL (mysql service) with initialization scripts under mysql-init/.
  • Ory Kratos + courier (kratos, kratos-migrate, kratos-courier) and Ory Hydra (hydra, hydra-migrate) that use configs rendered from templates/ory.
  • Auth Container (authlance) and License Operator (licenseoperator) which mount config files produced from templates/app/auth and templates/app/license.
  • NATS (nats) exposed on localhost:4222 for events plus an admin endpoint on localhost:8222.
  • nginx (nginx) terminating TLS on ${NGINX_HTTPS_PORT:-8443} and proxying the dashboard routes (/ and /authlance/loop) to host.docker.internal:3000 while forwarding /authlance and /authlance/license to the backend containers.

Kratos and Hydra only expose cluster-internal ports. The host touches them through the Auth Container or License Operator.

Prerequisites

  • Docker Desktop (Compose v2) on macOS or Linux.
  • A .env file in deployment/docker-compose (generated from .env.template).
  • A license file placed at deployment/docker-compose/licenses/authlance.lic (or update AUTH_LICENSE_FILE).
  • TLS material under deployment/docker-compose/nginx/certs if you do not want to rely on self-signed certs.

Bootstrapping the Stack

All commands run from deployment/docker-compose.

cp .env.template .env        # first-time setup
./start.sh

start.sh copies .env.template into .env when missing, pulls the referenced images, and launches the services in the correct order. The script prints health URLs for Kratos, Hydra, and MySQL once everything is on its way up.

Bring the Loop/Scaffold dashboard up on your host machine using the same connection info that Compose exports (see Development Environment for the full workflow). nginx/nginx.conf proxies https://localhost:${NGINX_HTTPS_PORT:-8443} to that host process, so the containerized services automatically receive the right cookies and callback URLs.

Template Rendering and Shared Configs

The ory-templates one-shot service uses envsubst to turn every file in templates/ory and templates/app/** into named Docker volumes:

  • ory_kratos_config/etc/kratos (includes kratos.yml, the identity schema, and Jsonnet mail templates).
  • ory_hydra_config/etc/hydra.
  • app_auth_config/app/config inside the Auth Container (config.yaml + authlance.lic).
  • app_license_config/app/config inside the License Operator (config.yaml + trialLicense).

Edit .env to any credentials or anything else referenced by the templates. Re-render after every change:

docker compose run --rm ory-templates
docker compose up -d authlance licenseoperator

Stopping the consuming services before re-rendering is recommended so that they remount the updated volumes:

docker compose stop authlance licenseoperator
docker compose run --rm ory-templates
docker compose up -d authlance licenseoperator

Customize the App Config Templates

The templates under deployment/docker-compose/templates/app/** ship with safe placeholders only. Before you render production-ready configs:

  • License Operator (templates/app/license/config.yaml.template) – Replace the example-subscription and example-one-off products (plus the matching security entries) with your own product keys, Stripe product/price IDs, and copy any commented examples if you need tiered or bundled SKUs. The checked-in template deliberately avoids real Authlance values.
  • Auth Container (templates/app/auth/config.yaml.template) – The paymentTier block is commented because it is optional. Uncomment it only if you enforce per-group member caps, and provide your values directly in the file (no .env variables are rendered for those keys).

Call out these tweaks in your team docs so everyone knows to customize the templates whenever they clone the repo.

Reusing Rendered Files for Kubernetes Secrets

Each Helm chart consumes a secret referenced through duna.configSecret. Rather than rebuilding configuration by hand, you can export the rendered volumes produced by Compose and create Kubernetes secrets from them:

# 1. Render the latest configs
docker compose run --rm ory-templates

# 2. Copy the files out of the volumes (COMPOSE_PROJECT_NAME defaults to duna)
docker run --rm -v duna_app_auth_config:/src alpine cat /src/config.yaml > auth-config.yaml
docker run --rm -v duna_app_license_config:/src alpine cat /src/config.yaml > license-config.yaml

# 3. Turn them into secrets that match the value files used by Helm
kubectl create secret generic auth-config --from-file=config.yaml=auth-config.yaml
kubectl create secret generic license-config --from-file=config.yaml=license-config.yaml

Use the same technique for ory_kratos_config or ory_hydra_config when you need to hydrate ConfigMaps or Secrets that feed your Ory workloads. Because .env drives every template, you can keep one authoritative set of credentials, render them with Compose, and reuse the outputs elsewhere.

Loop/Scaffold Configuration

Compose does not render templates/app/loop-scaffold/config.json.template automatically. When you extend the dashboard locally (or build a dashboard image), generate loop-scaffold/app-config.json from the same .env file:

cd deployment/docker-compose
set -a && source .env && set +a
envsubst < templates/app/loop-scaffold/config.json.template > ../../loop-scaffold/app-config.json

That file is the exact artifact mounted by the dashboard Helm chart. Keeping it in sync with .env means the host dashboard talks to the same MySQL schema, NATS server, and Stripe/Postmark credentials as the containers.

TLS and Routing Notes

  • Drop server.crt and server.key into nginx/certs/ to terminate HTTPS. Self-signed certs or mkcert outputs work well for local development.
  • nginx redirects plain HTTP (port ${NGINX_LOCAL_PORT:-8080}) to HTTPS (${NGINX_HTTPS_PORT:-8443}) by default; edit nginx/nginx.conf if you want different behavior.
  • Requests for /authlance go straight to the Auth Container, /authlance/license hits the License Operator, and /authlance/loop plus / proxy the dashboard on the host. Update this map if you place a different host port or run multiple dashboards.

Lifecycle Commands

  • docker compose down tears everything down but keeps databases and rendered configs. Add -v if you want to remove the named volumes as well.
  • docker compose logs -f authlance licenseoperator tails the backend logs.
  • ./start.sh is safe to rerun whenever you refresh .env; it re-pulls images and brings the services back up.
  • Health endpoints are exposed at:
    • Kratos admin: http://localhost:${KRATOS_ADMIN_PORT:-4434}/health/ready
    • Hydra admin: http://localhost:${HYDRA_ADMIN_PORT:-4445}/health/ready
    • MySQL: 127.0.0.1:${MYSQL_LOCAL_PORT:-3307}

Once you are comfortable with the Compose stack, move on to Helm deployments for production or GitOps-driven setups.