Quickstart

Get Speaknode running in a few minutes

Speaknode ships as a bundle — a docker-compose.yml and a reference .env.example — served directly from this docs site. Images live in our private container registry at registry.nodul.ru — pull access is granted via a read-only token (see below).

1. Download the quickstart bundle

mkdir Speaknode && cd Speaknode
curl -O https://docs.speaknode.com/cdn/docker-compose.yml
curl -O https://docs.speaknode.com/cdn/.env.example
mkdir -p env-gen caddy
curl -o env-gen/generate.sh https://docs.speaknode.com/cdn/env-gen/generate.sh
curl -o caddy/Caddyfile https://docs.speaknode.com/cdn/caddy/Caddyfile
  • docker-compose.yml — full service stack (includes a one-shot postgres-init service that creates the extra databases/users after Postgres is healthy)
  • .env.example — reference environment variables
  • env-gen/generate.sh — script for the one-shot container that generates a ready-to-use .env for your PUBLIC_HOST (see steps 4b and 4c)
  • caddy/Caddyfile — Caddy reverse-proxy config for the optional TLS mode (used only in 4c)

2. Request a registry token

Container images at registry.gitlab.com/nodevoice/* require a read-only token. Tokens are issued per customer on request — email us at [email protected] and we'll send you one.

Once you have it, log in on the host — docker will prompt for username and password:

docker login registry.gitlab.com/nodevoice

3. Configure

cp .env.example .env

The baseline .env.example already contains everything needed to bring the stack up locally — you can leave it as-is and start. Provider keys (LLM / STT / TTS), Keycloak SMTP, billing, telephony and other integrations are optional and only needed for the corresponding functionality.

Full variable reference is in Configuration.

4. Start the stack

Apple Silicon / ARM64. The images are built for linux/amd64. To ensure Docker pulls and runs that platform explicitly (on Apple M1/M2/M3, via Rosetta), the commands below are prefixed with DOCKER_DEFAULT_PLATFORM=linux/amd64. On x86_64 systems the prefix is a no-op and can be left in.

Pull the latest images first, so you're not running a stale :latest cached from a previous docker login:

DOCKER_DEFAULT_PLATFORM=linux/amd64 docker compose pull

Three deployment scenarios are described below. Choose the one matching your infrastructure.

4a. Local development (default)

Scenario: Compose runs on the same machine you use to open the application in the browser. The stack works out of the box — no additional configuration is required.

DOCKER_DEFAULT_PLATFORM=linux/amd64 docker compose up -d

The application will be available at http://localhost:4200.

4b. Remote host, access via IP

Scenario: Compose runs on a remote machine (cloud instance, on-premise server, machine on the local network), and you open the application from a different device.

In this configuration, the browser would by default reach localhost of your own device rather than the remote host. To make the public URLs in the stack point to the correct address, regenerate the .env file with the address of the remote host:

# 1. On the remote host — determine its IP address:
curl -4 https://ifconfig.me           # public IP (cloud instances)
hostname -I | awk '{print $1}'        # LAN address (Linux)

# 2. Generate .env with that address:
DOCKER_DEFAULT_PLATFORM=linux/amd64 PUBLIC_HOST=10.0.0.5 \
    docker compose run --rm env-gen

# 3. Start the stack:
DOCKER_DEFAULT_PLATFORM=linux/amd64 docker compose up -d

env-gen is a single-purpose helper container that generates .env from the .env.example template. It does not start with the regular docker compose up (it is behind the tools profile) — invoke it explicitly when needed.

4c. Remote host, access via domain name with TLS

Scenario: the stack is served via a real domain over HTTPS, for example https://app.dev.voxagent.ru, https://api.dev.voxagent.ru, etc.

DNS setup

All subdomains must point to the same IP — the public address of your host. Routing between services is handled by Caddy inside the stack. Two DNS configurations are supported.

Option A. Wildcard record (recommended)

TypeNameValue
A*.dev.voxagent.ru<host IP>
Adev.voxagent.ru<host IP> (optional, for the apex domain)

Option B. Explicit A-records per subdomain

TypeNameService
Aapp.dev.voxagent.ruAngular Client (application frontend)
Awidget.dev.voxagent.ruAngular Widget (embeddable widget)
Aapi.dev.voxagent.ruASP.NET Backend (REST API)
Aidentity.dev.voxagent.ruKeycloak (authentication / OAuth)
Alivekit.dev.voxagent.ruLiveKit (WebRTC + WebSocket)
Adocs.dev.voxagent.ruDocumentation
As3.dev.voxagent.ruMinIO S3 API
As3-console.dev.voxagent.ruMinIO Web Console
Alago.dev.voxagent.ruLago Billing UI
Alago-api.dev.voxagent.ruLago Billing API
Awebhooks.dev.voxagent.ruWebhook Receiver
Akafka-ui.dev.voxagent.ruKafka UI (optional, for administration)

After the records are created, wait for DNS to propagate (typically 5-30 minutes). You can verify with dig +short app.dev.voxagent.ru — it should return the configured IP address.

TLS configuration

Caddy supports two certificate-issuance modes:

  • Let's Encrypt — publicly trusted certificates, no browser warnings. Used by default when PUBLIC_HOST is set to a real domain. Requires port 80 of the host to be reachable from the public internet (for the HTTP-01 challenge).
  • Caddy local CA — Caddy issues its own root CA and certificates signed by it. Used automatically when PUBLIC_HOST=localhost. On every device that opens the application, the root CA must be added to the system trust store via docker compose exec caddy caddy trust (this affects the container; for the host system the certificate must be extracted and installed manually).

Start the stack

# 1. Generate .env (env-gen automatically switches Caddy to Let's
#    Encrypt when a real domain is specified):
DOCKER_DEFAULT_PLATFORM=linux/amd64 PUBLIC_HOST=dev.voxagent.ru PUBLIC_MODE=tls \
    [email protected] \
    docker compose run --rm env-gen

# 2. Start the stack with the tls profile (enables Caddy):
DOCKER_DEFAULT_PLATFORM=linux/amd64 COMPOSE_PROFILES=tls docker compose up -d

The CADDY_LE_EMAIL parameter is the email address Let's Encrypt uses to send certificate expiry notifications. If not provided, env-gen falls back to admin@${PUBLIC_HOST}.

After startup the application is available at the following endpoints: https://app.dev.voxagent.ru, https://identity.dev.voxagent.ru, https://api.dev.voxagent.ru, etc.

The full certificate-issuance procedure for all subdomains takes about 5-10 minutes on the first run. You can follow the progress in the logs: docker compose logs -f caddy.


First boot takes a few minutes — Postgres initialises, Keycloak imports the realm, Lago runs migrations and seeds the billing organisation.

5. Wait for angular-client to become healthy

Check service status:

docker compose ps -a --format "table {{.Service}}\t{{.Status}}\t{{.Ports}}"

As soon as the angular-client row shows Up ... (healthy), the app is ready — open it at http://localhost:4200.

6. Create a user

On the sign-in screen hit Sign up and create an account.

The docker compose bundle ships with email verification disabled (KEYCLOAK_VERIFY_EMAIL=false), so registration is instant.

Enable email verification

To require users to confirm their email before first login, edit .env:

  1. Turn the flag on:
    KEYCLOAK_VERIFY_EMAIL=true
  2. Fill in Keycloak SMTP credentials (used for verification + password-reset emails):
    KEYCLOAK_SMTP_HOST=smtp.example.com
    KEYCLOAK_SMTP_PORT=465
    KEYCLOAK_SMTP_FROM=[email protected]
    KEYCLOAK_SMTP_USER=<smtp-user>
    KEYCLOAK_SMTP_PASSWORD=<smtp-password>
    KEYCLOAK_SMTP_SSL=true       # for port 465
    KEYCLOAK_SMTP_STARTTLS=false # flip to true for port 587
  3. Recreate Keycloak to pick up the changes:
    docker compose up -d --force-recreate keycloak

Other entrypoints

Once the stack is fully up:

Ports are configurable in .env under the HOST PORTS section — change any that clash with something already running on your machine.

Next steps

On this page