Self-host and operate

Local deployment

The development compose file runs supporting services only. Nuxt stays on the host for hot module replacement and listens on port 3000.

Service profiles

CommandServicesUse for
pnpm services:upPostgresPostgreSQL connectors
pnpm services:up:whatsappPostgres, Redis, EvolutionWhatsApp connectors
pnpm services:up:telegramPostgres, Telegram bridgeTelegram connectors
pnpm services:downAll enabled profilesRoutine shutdown
pnpm services:logsAll enabled profilesCombined service logs
pnpm services:psAll enabled profilesService status

After bringing up services, run pnpm dev on the host.

One Postgres, three schemas

SchemaOwnerHolds
appWebUsers, sessions, organizations, connections, invitations, token hashes
publicEvolutionWhatsApp instances, chats, and messages
telegramTelegram bridgeEncrypted sessions and synced chats

The web app applies its migrations at startup under an advisory lock. To start over locally, drop the schema; the next boot recreates it:

psql postgres://evolution:change-me@localhost:5432/evolution -c 'DROP SCHEMA app CASCADE'

Local topology

FromToAddress
NuxtPostgres (app and messages)localhost:5432
NuxtEvolutionhttp://localhost:8080
NuxtTelegram bridgehttp://localhost:8095
EvolutionNuxt webhookhttp://host.docker.internal:3000/api/webhook/evolution
Telegram bridgeNuxt webhookhttp://host.docker.internal:3000/api/webhook/telegram

Ports and webhooks

Postgres 5432, Redis 6379, Evolution 8080, and the Telegram bridge 8095 bind to loopback in the development compose file. Nuxt listens on 0.0.0.0 so containers can reach its webhook.

Set WEBHOOK_URL and NUXT_WEBHOOK_URL to the same Evolution callback. Set NUXT_WEBHOOK_SECRET so per-instance webhook requests carry and verify x-webhook-secret.

Testing mail locally

Run a mail catcher and point NUXT_SMTP_HOST at it:

docker run -d --name wamcp-mailpit -p 1025:1025 -p 8025:8025 axllent/mailpit:v1.21
# .env: NUXT_SMTP_HOST=localhost, NUXT_SMTP_PORT=1025, NUXT_MAIL_FROM=alerts@automata.test

Read sent mail at http://localhost:8025. See Connection alerts for how detection works. Trigger the alert sweep by hand with curl -X POST http://localhost:3000/_nitro/tasks/alerts:sweep.

Linux firewall

On Linux with ufw, container-to-host webhook traffic enters the host input chain and may time out. The compose subnet is pinned so it can be narrowly allowed:

sudo ufw allow from 172.31.250.0/24 to 172.17.0.1 \
  port 3000 proto tcp comment 'automata webhooks'

Verify from the Evolution container:

docker compose -f docker-compose.dev.yml exec evolution \
  wget -T 5 -qO- --post-data='{"event":"ping"}' \
  --header='content-type: application/json' \
  http://host.docker.internal:3000/api/webhook/evolution

A response of {"ok":true} confirms the path. A timeout usually means the firewall rule or subnet is wrong.

View source