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/Caddyfiledocker-compose.yml— full service stack (includes a one-shotpostgres-initservice that creates the extra databases/users after Postgres is healthy).env.example— reference environment variablesenv-gen/generate.sh— script for the one-shot container that generates a ready-to-use.envfor yourPUBLIC_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/nodevoice3. Configure
cp .env.example .envThe 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 pullThree 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 -dThe 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 -denv-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)
| Type | Name | Value |
|---|---|---|
| A | *.dev.voxagent.ru | <host IP> |
| A | dev.voxagent.ru | <host IP> (optional, for the apex domain) |
Option B. Explicit A-records per subdomain
| Type | Name | Service |
|---|---|---|
| A | app.dev.voxagent.ru | Angular Client (application frontend) |
| A | widget.dev.voxagent.ru | Angular Widget (embeddable widget) |
| A | api.dev.voxagent.ru | ASP.NET Backend (REST API) |
| A | identity.dev.voxagent.ru | Keycloak (authentication / OAuth) |
| A | livekit.dev.voxagent.ru | LiveKit (WebRTC + WebSocket) |
| A | docs.dev.voxagent.ru | Documentation |
| A | s3.dev.voxagent.ru | MinIO S3 API |
| A | s3-console.dev.voxagent.ru | MinIO Web Console |
| A | lago.dev.voxagent.ru | Lago Billing UI |
| A | lago-api.dev.voxagent.ru | Lago Billing API |
| A | webhooks.dev.voxagent.ru | Webhook Receiver |
| A | kafka-ui.dev.voxagent.ru | Kafka 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_HOSTis set to a real domain. Requires port80of 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 viadocker 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 -dThe 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:
- Turn the flag on:
KEYCLOAK_VERIFY_EMAIL=true - 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 - Recreate Keycloak to pick up the changes:
docker compose up -d --force-recreate keycloak
Other entrypoints
Once the stack is fully up:
| Service | URL |
|---|---|
| Speaknode app | http://localhost:4200 |
| Keycloak admin | http://localhost:8081 |
| Backend Swagger | http://localhost:8040/swagger |
| Lago billing UI | http://localhost:4203 |
| MinIO console | http://localhost:9001 |
| Kafka UI | http://localhost:8084 |
Ports are configurable in .env under the HOST PORTS section — change any
that clash with something already running on your machine.
Next steps
- Requirements — size your host for expected concurrent load.
- Configuration — complete environment reference.
- Installation — other deployment options (managed, Kubernetes).