Self-host and operate

Configuration

Use the source .env.example for the complete comments and defaults. This page identifies the major boundaries and values required by each deployment shape.

Core application

VariableRequiredPurpose
NUXT_DATABASE_URLYesPostgres owner URL. The app creates and migrates its own app schema here at boot
NUXT_PUBLIC_APP_URLYesPublic origin used to build connector URLs
NUXT_ALLOW_PRIVATE_TARGETSNoPermit user-supplied private targets in trusted single-tenant installs. Defaults to off
NUXT_SIGNUPNoopen or invite-only. Defaults to invite-only. See Who can sign up
NUXT_SIGNUP_CODENoInvite-only mode: a shared code that lets its holder create their own organization
NUXT_EMAIL_VERIFICATIONNoauto, required, or off. Defaults to auto. See Email verification
POSTGRES_USER, POSTGRES_PASSWORD, POSTGRES_DBLocal composeValues for the bundled Postgres container

The app schema holds users, sessions, organizations, connections, invitations, connector-token hashes, and two-factor credentials. Connection credentials in it are not encrypted, so treat this database and its backups as holding every connected account.

WhatsApp

Everything in this section is optional. Without a default Evolution server, users can still create WhatsApp connections by supplying their own server URL and key.

VariableRequired when enabledPurpose
EVOLUTION_API_KEYFor bundled EvolutionGlobal Evolution administrator key
NUXT_EVOLUTION_URLFor a default serverEvolution origin reached by web
NUXT_EVOLUTION_ADMIN_KEYFor a default serverMust match EVOLUTION_API_KEY
NUXT_EVOLUTION_DATABASE_URLFor reads and searchThe Evolution Postgres. The owner URL works; a SELECT-only role is optional hardening
WEBHOOK_URLLocal composeCompose fallback webhook URL
NUXT_WEBHOOK_URLYes for fast Evolution alertsPer-connection webhook registered by web
NUXT_WEBHOOK_SECRETStrongly recommendedShared x-webhook-secret value, also used by Telegram webhooks

Set Evolution DATABASE_SAVE_DATA_HISTORIC=true before pairing if full history matters.

Telegram

VariableRequired when enabledPurpose
TELEGRAM_API_ID, TELEGRAM_API_HASHBoth or neitherCredentials from my.telegram.org. With neither, the bridge starts and reports Telegram as unconfigured
TELEGRAM_BRIDGE_ADMIN_KEYYesCreates and deletes bridge sessions
TELEGRAM_SESSION_ENCRYPTION_KEYYesSeals stored account sessions
TELEGRAM_BRIDGE_DATABASE_URLYesSame Postgres as Evolution; the bridge keeps to its telegram schema
TELEGRAM_READER_ROLENoA LOGIN-only role the bridge grants column-level SELECT to at every start
NUXT_TELEGRAM_URLFor a default bridgeBridge origin reached by web
NUXT_TELEGRAM_ADMIN_KEYFor a default bridgeMatches the bridge administrator key
NUXT_TELEGRAM_DATABASE_URLFor reads and searchRead access to the telegram schema
NUXT_TELEGRAM_WEBHOOK_URLLocal developmentBridge-to-web callback; production derives it from the app URL
TELEGRAM_TEST_SERVERSNoUse Telegram's separate test environment

Backfill is tuned by TELEGRAM_BACKFILL_MAX_PER_CHAT, TELEGRAM_BACKFILL_DAYS, TELEGRAM_BACKFILL_BROADCAST, and TELEGRAM_BACKFILL_PAGE_DELAY_MS.

Alerts and mail

The web server sends connection alerts, invitation emails, and verification codes over SMTP. Configure NUXT_SMTP_HOST, NUXT_SMTP_PORT, NUXT_SMTP_USERNAME, NUXT_SMTP_PASSWORD, NUXT_SMTP_TLS, NUXT_MAIL_FROM, and NUXT_MAIL_FROM_NAME.

NUXT_SMTP_TLS=false uses STARTTLS on port 587; set it to true for implicit TLS on 465. With NUXT_SMTP_HOST empty, alerts are computed and stay queued, and invitation links can still be copied by hand. NUXT_MAIL_FROM must be an address the provider accepts.

Who can sign up

Each self-signup creates a new organization, and its administrator can start connections on your Evolution server and Telegram bridge. So by default nobody can sign up without an invitation:

NUXT_SIGNUPNUXT_SIGNUP_CODEWho can sign up without an invitation
Unset or invite-onlyUnsetOnly the first account on an empty database, which becomes the administrator
Unset or invite-onlySetAnyone who enters the code, the first account included
openIgnoredAnyone who finds the URL

Invitation links work in every mode, and neither variable is required: a new install with both unset lets you sign up first, then you invite everyone else from the Team page. An unrecognized NUXT_SIGNUP value is read as invite-only, so a typo cannot open sign-up.

Until that first signup, a fresh install on a public address belongs to whoever opens it first. If that window matters, set NUXT_SIGNUP_CODE before starting the stack (openssl rand -base64 24) and give the code only to people who should get their own organization. Wrong codes are throttled per client address.

Email verification

Without verification, anyone can register someone@yourcompany.com before its owner does, and the owner can then neither sign up nor accept an invitation sent to that address. With it, signing up (with or without an invitation) and changing an account's email both send a six-digit code and a link, and nothing is created or changed until one comes back. An unconfirmed signup holds no claim on the address and expires after 30 minutes.

NUXT_EMAIL_VERIFICATIONBehavior
Unset or autoOn when NUXT_SMTP_HOST is set, off otherwise
requiredAlways on. Without SMTP, signups and email changes are refused
offNever. The password alone proves an email change

Any other value is read as required. The link is built from NUXT_PUBLIC_APP_URL only, never from the request, so a forged Host header cannot redirect it; without that URL the email carries only the code. A link only proves the address: it signs in only the browser that started the signup. Existing accounts are not asked to verify.

Docker Compose

The Docker Compose deployment reads a single .env created from .env.selfhost.example. It sets WEB_PORT for the published web port, the same NUXT_* and connector variables described above, and every secret that must be generated before first start. Sign-up settings use the short names SIGNUP, SIGNUP_CODE, and EMAIL_VERIFICATION. The single container reads the same names with --env-file, and generates any blank secret on first boot. Unlike local development, the web app runs in a container, so NUXT_DATABASE_URL points at the bundled Postgres service rather than localhost.

Production settings

  • Do not ship .env; use platform variables and secret references.
  • Set NUXT_WEBHOOK_SECRET.
  • Keep NUXT_ALLOW_PRIVATE_TARGETS unset for shared deployments.
  • Leave sign-up invite-only unless strangers should be able to create organizations.
  • Set NUXT_PUBLIC_APP_URL to the exact address people open; email verification links and passkeys depend on it.
  • Keep the web service at one replica so the five-minute alert sweep runs once.
  • Keep Evolution global keys, bridge keys, and database URLs out of client code and logs.
  • Back up Postgres, and restrict access to those backups.
  • Preserve TELEGRAM_SESSION_ENCRYPTION_KEY outside the deployment platform.
View source