Skip to main content
Version: 0.9.12

Prerequisites

platform v0.9.11verified 2026-05-14

Before you provision any instance, line up the accounts and shared resources every other step assumes are present. None of them is hard to create — but init.sh will fail loudly if anything in this list is missing.

Accounts and credentials

ItemWhy it's needed
Cloud provider accountCompute, networking, block storage. Hetzner Cloud is the reference; AWS EC2 is fully supported. Anything that runs Docker Compose on Linux works.
AWS accountSSM Parameter Store, Secrets Manager, S3 (config bundles + DB backups + recordings). Used regardless of which cloud hosts the compute.
AWS IAM user / roleRead SSM, read/write Secrets Manager, read S3, push and pull from your container registry, optionally call SES.
Container image registryReference setup uses AWS ECR. Any registry that supports docker login works as long as every host can reach it.
DNS control over two domainsOne for the dashboard (DOMAIN_TELWEB), one for telephony (DOMAIN_TELPRO). Optional third for SigNoz UI (DOMAIN_SIGNOZ).
TLS sourcesFor dashboard / telephony — Let's Encrypt by default, or pre-issued certs in Secrets Manager. For internal Postgres/Redis — your own internal CA.
AI provider keysOpenAI and/or Pythia/Vodafone TOBi/Azure, depending on which providers you enable in TelWeb after first boot.
(Optional) SIP carrierA SIP trunk to point at TelPro's public IP. Without a carrier you can still test the stack via the WebRTC phone in TelWeb.

Shared cloud resources

These resources are shared across every service in the deployment. Create them once per environment (staging, prod, etc.).

Namespace

Pick a NAMESPACE string of the form <org>/<environment>. Every SSM path and every Secrets Manager secret name is prefixed with it:

/voiceai/staging/api/REDIS_HOST
/voiceai/staging/database/INTERNAL_CA_CRT_B64
/voiceai/staging/api/DATABASE_SSL_MODE
voiceai/staging/api/secrets # JSON: DATABASE_URL, DATABASE_SSL_CA_BUNDLE_B64, REDIS_TLS_CA_BUNDLE_B64, …
voiceai/staging/web/secrets

The reference deployments use voiceai/staging and voiceai/production. If you operate multiple deployments under the same AWS account, use a unique NAMESPACE per deployment so the SSM paths and SM names never collide.

S3 config bucket

Every service host fetches its config bundle from a single S3 bucket at boot. The bucket layout is:

s3://<config-bucket>/
└─ deployments/<deployment-slug>/<release>/
├─ api/ docker-compose.yaml · init.sh · vars.yaml · otel-collector-config.yaml
├─ web/ docker-compose.yaml · init.sh · vars.yaml · Caddyfile · …
├─ voice/
├─ telpro/
├─ database/
├─ media/
├─ ops/
├─ signoz/
├─ squid/
└─ common/ fetch-env.sh · update.sh · prepare-tls.sh · …

The cloud-init on each host writes CONFIG_BUCKET and CONFIG_REF into /opt/deployment/.env; init.sh calls fetch-config to sync s3://${CONFIG_BUCKET}/deployments/<slug>/<CONFIG_REF>/<role>/ (and common/) into /opt/services/<role>/. Re-running update.sh --config-ref <new-ref> is how you roll a config change without rebuilding images.

The bundle itself is what you receive when a release is cut. The runtime path that consumes it is covered in Bootstrap and init.

Container images

Every release ships these images. Push them to your registry and remember the tag — it becomes ECR_TAG in the bootstrap environment:

ImageWhere it runs
voiceai-telapiAPI instances
voiceai-telwebWeb instance
voiceai-telphiVoice instances
voiceai-telsysVoice instances (Asterisk)
voiceai-telproTelPro instance (Kamailio with optional hiredis_ssl)
voiceai-webrtcTelPro instance (Janus) — only when the webrtc flag is on
voiceai-turnTelPro instance (coturn) — only when the webrtc flag is on
voiceai-audioprocVoice instances — only when the audioPreprocessing flag is on
voiceai-media-serverMedia instance — only when the ttsMediaCache flag is on
voiceai-scalerOps instance
voiceai-taskerOps instance
voiceai-postgresDatabase instance — wraps postgres:17-alpine
voiceai-redisDatabase instance — wraps redis:7-alpine
voiceai-pgbouncerDatabase instance — only when internal Postgres TLS is on
voiceai-squidSquid instance

Upstream images (SigNoz, OTel collector, Caddy) are pulled directly from their public registries via Squid. Image-specific operational notes live with their service pages; WebRTC / Janus details are in TelPro operations.

Networks

  • A private network (e.g. 10.0.1.0/24 in the reference) shared by every service instance.
  • A reserved fixed private IP for SigNoz (10.0.1.10 by default) — every OTel collector points at this address.
  • A reserved fixed private IP for Media (10.0.1.30 by default) — used as TTS_MEDIA_CACHE_BASE_URL host.
  • Static / floating public IPs for TelPro and Web so DNS records can be set without rotating after instance recreation.
  • A managed load balancer in front of the API instances, with TLS termination on DOMAIN_API and sticky sessions enabled (required for WebSocket).

IAM grants

Each instance role needs:

  • SSMssm:GetParametersByPath under /${NAMESPACE}/${SERVICE}/.
  • Secrets Managersecretsmanager:ListSecrets filtered by name prefix ${NAMESPACE}/${SERVICE}/, and secretsmanager:GetSecretValue for each match. Plus any external secrets referenced by secret.arn_from (e.g. an RDS master secret).
  • S3s3:GetObject, s3:ListBucket under s3://<config-bucket>/deployments/<slug>/.
  • ECRecr:GetAuthorizationToken, ecr:BatchGetImage, ecr:GetDownloadUrlForLayer for the registry you pushed images to.
  • (Ops only) Permissions to drive the cloud-provider scaling API: Hetzner API token in Secrets Manager, or AWS EC2 RunInstances if scaling on AWS. SES ses:SendEmail / ses:SendRawEmail if email goes through SES.
  • (Database only, if you use a managed RDS / Aurora cluster) secretsmanager:GetSecretValue on the RDS master secret ARN — see Managed database secrets.

Operator tooling

On the workstation you bring the deployment up from:

  • aws CLI v2 (configured for the deployment's AWS account).
  • Your provisioning tool of choice for creating instances, volumes, firewalls / security groups, and load balancers.
  • ssh, scp (Bastion access).
  • yq, jq (used by fetch-env.sh and many of the helper scripts on the host as well).

Next

Continue to Configure environment.