WWaSphere Docs
Getting Started

Configuration

Complete environment variable reference for every WaSphere service.

Configuration

All WaSphere configuration is driven by environment variables in the .env file at the project root. Copy .env.example to .env and edit it before starting the stack.

cp .env.example .env

Variables are grouped by the service that consumes them. Many variables are shared — when a variable appears in a shared section it applies to multiple services.

Never commit your .env file to source control. The .gitignore in the repository excludes it, but double-check before every git add.


Shared / Deployment

These variables affect the overall deployment and are consumed by Traefik and the dashboard services.

VariableTypeDefaultRequiredDescription
DOMAINstringYesYour domain name without protocol — e.g. wa.example.com. Traefik uses this to provision SSL and route traffic.
ADMIN_EMAILstringYesEmail address of the initial admin account. Also used as the Let's Encrypt registration email.
ADMIN_PASSWORDstringYesPassword for the initial admin account. Must be at least 12 characters.
REGISTRATION_LOCKEDbooleanfalseNoSet to true to disable new user registrations after initial setup. Recommended for production once your team is onboarded.

Dashboard API

The Dashboard API (NestJS, port 3000) is the main backend. It handles authentication, session management, message dispatch, webhooks, and the REST API your applications call.

VariableTypeDefaultRequiredDescription
DATABASE_URLstringYesPostgreSQL connection string in the format postgresql://USER:PASSWORD@HOST:PORT/DATABASE. Inside Docker, use postgresql://wasphere:changeme@postgres:5432/wasphere.
JWT_SECRETstringYesSecret key used to sign JWT access tokens. Must be at least 32 characters. Generate with openssl rand -hex 32. Rotate this to invalidate all existing sessions.
JWT_EXPIRES_INstring7dNoJWT token lifetime. Uses ms format — e.g. 1h, 7d, 30d.
WA_SERVER_URLstringhttp://wa-server:3001NoInternal URL the Dashboard API uses to reach the WA Server. In Docker this is the service name. Change only if running services on separate machines.
WA_TOKENstringYesShared secret the Dashboard API sends as X-Api-Token to authenticate with the WA Server. Generate with openssl rand -hex 32. Must match WA_TOKEN in the WA Server section.
DASHBOARD_PORTnumber3000NoPort the Dashboard API listens on. Only change if running without Docker.
CORS_ORIGINSstring*NoComma-separated list of allowed CORS origins. In production, set this to your exact frontend URL — e.g. https://wa.example.com.
LOG_LEVELstringinfoNoLog verbosity. Options: error, warn, info, debug, verbose. Use debug temporarily when diagnosing issues.

Webhook Delivery

VariableTypeDefaultRequiredDescription
WEBHOOK_SECRETstringYesDefault HMAC-SHA256 signing secret for webhook payloads. Each webhook endpoint can override this with its own secret via the dashboard.
WEBHOOK_TIMEOUT_MSnumber10000NoMilliseconds to wait for a webhook endpoint to respond before marking the delivery as failed.
WEBHOOK_MAX_RETRIESnumber5NoMaximum number of delivery attempts per event.
WEBHOOK_RETRY_BASE_DELAY_MSnumber30000NoBase delay (in ms) for the first retry. Subsequent retries use exponential backoff: baseDelay * 2^attempt.

Rate Limiting

VariableTypeDefaultRequiredDescription
RATE_LIMIT_TTLnumber60NoRate limit window in seconds.
RATE_LIMIT_MAXnumber100NoMaximum requests per API key per RATE_LIMIT_TTL window.
RATE_LIMIT_SKIP_ADMINbooleantrueNoWhether to skip rate limiting for requests authenticated with the admin JWT (not API keys).

Media & Storage

VariableTypeDefaultRequiredDescription
MEDIA_MAX_SIZE_MBnumber64NoMaximum file size for media uploads in megabytes. WhatsApp's own limit is 64 MB for most file types.
MEDIA_STORAGE_PATHstring/app/mediaNoLocal path where uploaded media files are stored before being sent.

WA Server

The WA Server (NestJS + Baileys, port 3001) manages WhatsApp connections. It only accepts requests from the Dashboard API.

VariableTypeDefaultRequiredDescription
WA_TOKENstringYesShared secret. Must match the value set in the Dashboard API. Incoming requests without a valid X-Api-Token: <token> header are rejected with 401.
PORTnumber3001NoPort the WA Server listens on. Only change if running without Docker.
SESSIONS_PATHstring/app/sessionsNoDirectory where Baileys stores session credentials. Map this to a Docker volume to persist sessions across container restarts.
LOG_LEVELstringinfoNoLog verbosity for the WA Server process.

Anti-Ban Defaults

These are platform-wide defaults. Each session can override them via the dashboard.

VariableTypeDefaultRequiredDescription
MSG_DELAY_MIN_MSnumber1000NoMinimum delay in milliseconds between consecutive messages sent by the same session.
MSG_DELAY_MAX_MSnumber3000NoMaximum delay in milliseconds. The actual delay is a random value between MIN and MAX.
TYPING_SIMULATIONbooleantrueNoWhen true, the WA Server sends a typing indicator before each text message. Duration scales with message length.
RATE_LIMIT_PER_MINnumber20NoMaximum messages per minute per session. Requests exceeding this limit are queued, not dropped.

Dashboard UI

The Dashboard UI (Next.js, port 13004) is a browser application. Variables prefixed with NEXT_PUBLIC_ are embedded in the built JavaScript and visible to the browser.

VariableTypeDefaultRequiredDescription
NEXT_PUBLIC_API_URLstringYesPublic URL of the Dashboard API, as seen from the browser. E.g. https://wa.example.com/api.
WA_SERVER_INTERNAL_URLstringhttp://wa-server:3001NoInternal Docker URL the Next.js server-side code uses to reach the WA Server directly (for QR code streaming).
NEXT_PUBLIC_APP_NAMEstringWaSphereNoBrand name shown in the dashboard UI title and header.

PostgreSQL (Docker Service)

These variables configure the PostgreSQL container in the Docker Compose stack.

VariableTypeDefaultRequiredDescription
POSTGRES_USERstringwasphereNoPostgreSQL superuser name. Must match the username in DATABASE_URL.
POSTGRES_PASSWORDstringchangemeYesPostgreSQL superuser password. Use a strong password in production. Must match the password in DATABASE_URL.
POSTGRES_DBstringwasphereNoDatabase name. Must match the database in DATABASE_URL.

The default POSTGRES_PASSWORD=changeme is intentionally insecure. Replace it before going to production. After changing it, update DATABASE_URL to match and recreate the postgres container: docker compose up -d --force-recreate postgres.


Example .env for Production

# ── Deployment ──────────────────────────────────────────
DOMAIN=wa.example.com
ADMIN_EMAIL=admin@example.com
ADMIN_PASSWORD=MyStr0ng!P@ssword
REGISTRATION_LOCKED=true

# ── Secrets ─────────────────────────────────────────────
JWT_SECRET=a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2
WA_TOKEN=f6e5d4c3b2a1f6e5d4c3b2a1f6e5d4c3b2a1f6e5d4c3b2a1f6e5d4c3b2a1f6e5
WEBHOOK_SECRET=9z8y7x6w5v4u3t2s1r0q9z8y7x6w5v4u3t2s1r0q

# ── Database ─────────────────────────────────────────────
DATABASE_URL=postgresql://wasphere:Sup3rS3cur3DB!@postgres:5432/wasphere
POSTGRES_USER=wasphere
POSTGRES_PASSWORD=Sup3rS3cur3DB!
POSTGRES_DB=wasphere

# ── Dashboard API ────────────────────────────────────────
WA_SERVER_URL=http://wa-server:3001
CORS_ORIGINS=https://wa.example.com
LOG_LEVEL=info
JWT_EXPIRES_IN=7d

# ── WA Server ────────────────────────────────────────────
PORT=3001
SESSIONS_PATH=/app/sessions
MSG_DELAY_MIN_MS=1000
MSG_DELAY_MAX_MS=4000
TYPING_SIMULATION=true
RATE_LIMIT_PER_MIN=20

# ── Dashboard UI ─────────────────────────────────────────
NEXT_PUBLIC_API_URL=https://wa.example.com/api
WA_SERVER_INTERNAL_URL=http://wa-server:3001

Rotating Secrets

JWT_SECRET — Rotating this immediately invalidates all active user sessions. Everyone signed in to the dashboard will be logged out. To rotate:

  1. Generate a new value: openssl rand -hex 32
  2. Update .env
  3. Restart the Dashboard API: docker compose restart dashboard-api

WA_TOKEN — Must be updated in .env and both the Dashboard API and WA Server containers restarted simultaneously to avoid a broken state:

# Update .env, then:
docker compose restart dashboard-api wa-server

WEBHOOK_SECRET — Per-webhook secrets can be rotated individually from the dashboard without affecting other webhooks. The global default only applies to webhooks that don't have their own secret set.

On this page