Self-host and operate

Railway deployment

A complete deployment uses up to five services. Provision only the connector infrastructure you need.

Deploy on Railway

Railway's template provisions the service matrix below automatically, including volumes. You still need to fill in the environment variables described under Environment wiring.

Service matrix

ServiceSourceTarget portPersistent volume
PostgresRailway templateManagedManaged
Redis (WhatsApp only)Railway templateManagedManaged
Evolution (WhatsApp only)evoapicloud/evolution-api:v2.3.78080/evolution/instances
Telegram bridge (Telegram only)ghcr.io/ju-li/automata-mcp-telegram-bridge:18095None
Webghcr.io/ju-li/automata-mcp-web:1Railway assignedNone

Postgres is always required because it holds the app's own tables. A deployment serving only PostgreSQL connections needs just Postgres and web.

Published images

The web app and Telegram bridge are published to GHCR on every release, tagged X.Y.Z, X.Y, X, latest, and sha-<commit> for linux/amd64. See Releases for upgrade guidance.

To run unreleased code, build from the repository instead. Keep the root directory at / and set the Dockerfile path to apps/web/Dockerfile or /apps/telegram-bridge/Dockerfile. A root directory of /apps/telegram-bridge fails with "/pnpm-workspace.yaml": not found.

Volumes and ports

Attach /evolution/instances to Evolution in its service settings. Railway rejects Dockerfile VOLUME instructions, so no image declares one and nothing warns you if it is missing. The Telegram bridge needs no volume; its sessions and chats live in Postgres.

Railway injects PORT into every service, so pin the internal ports explicitly:

evolution:        SERVER_PORT=8080
telegram-bridge:  TELEGRAM_BRIDGE_PORT=8095
web:              Railway-assigned public PORT

Environment wiring

Use Railway references such as ${{Service.VAR}} for shared secrets and database URLs, so rotated values propagate.

NUXT_DATABASE_URL=${{Postgres.DATABASE_URL}}
NUXT_PUBLIC_APP_URL=https://<web-domain>

# WhatsApp only
NUXT_EVOLUTION_URL=http://evolution.railway.internal:8080
NUXT_EVOLUTION_ADMIN_KEY=${{evolution.AUTHENTICATION_API_KEY}}
NUXT_EVOLUTION_DATABASE_URL=${{Postgres.DATABASE_URL}}
NUXT_WEBHOOK_URL=https://<web-domain>/api/webhook/evolution
NUXT_WEBHOOK_SECRET=<openssl rand -hex 32>

# Telegram only
NUXT_TELEGRAM_URL=http://<telegram-bridge-service>.railway.internal:8095
NUXT_TELEGRAM_ADMIN_KEY=${{telegram-bridge.TELEGRAM_BRIDGE_ADMIN_KEY}}
NUXT_TELEGRAM_DATABASE_URL=${{Postgres.DATABASE_URL}}

Evolution and bridge variables

  • Set Evolution WEBHOOK_GLOBAL_ENABLED=false. Automata registers webhooks per connection, and a global webhook would deliver every event twice.
  • Keep the DATABASE_SAVE_DATA_* flags on, including DATABASE_SAVE_DATA_HISTORIC, or message tools return nothing.
  • TELEGRAM_API_ID and TELEGRAM_API_HASH may stay empty until you need Telegram. Setting both later redeploys the bridge and enables it.
  • NUXT_TELEGRAM_WEBHOOK_URL is not needed; the bridge posts to NUXT_PUBLIC_APP_URL + /api/webhook/telegram.

Web mail and network settings

  • Configure NUXT_SMTP_* and NUXT_MAIL_FROM on web to deliver alerts and invitations.
  • Leave NUXT_ALLOW_PRIVATE_TARGETS unset.
  • Sign-up is invite-only unless you say otherwise: the first account gets through and everyone after joins by invitation. Set NUXT_SIGNUP_CODE to let holders of that code create their own organization (the first account then needs it too), or NUXT_SIGNUP=open to let anyone who finds the domain sign up. See Who can sign up.
  • Once SMTP is configured, new signups and email changes are verified by email. See Email verification.

Keep the Telegram bridge and web app at one replica, and leave RAILWAY_DEPLOYMENT_OVERLAP_SECONDS unset on the bridge. Multiple bridge processes compete for sessions; multiple web replicas run duplicate alert sweeps.

First-run checks

  1. Confirm web logs include [app-db] applied migrations. No manual schema step is needed.
  2. Open the web domain and create an account. The first account becomes the administrator; invite everyone else from the Team page.
  3. Create one connection and call a read-only status tool.
  4. Confirm connector URLs use the correct public origin.

Coming from PocketBase

Earlier versions stored users and connections in PocketBase. Deploy commit 2e1872e first; it imports every user, password, connection, and token into Postgres on first boot. Once that import is done, delete the PocketBase service and its volume.

View source