# OpenWA - Local smoke / quick-start compose # # This builds and runs the PRODUCTION image (same Dockerfile) against a local SQLite DB # with a bind-mounted ./data — it is a single-container local smoke test, NOT a # hot-reload development environment (there is no source mount or `start:dev`). # DATABASE_SYNCHRONIZE=true keeps the SQLite schema zero-config for local use; the # production compose (docker-compose.yml) never forces synchronize (it defaults to false). # # Quick Start: docker compose -f docker-compose.dev.yml up -d services: # API Backend openwa: build: context: . dockerfile: Dockerfile container_name: openwa-api # Container hardening — same posture as production (same Dockerfile/entrypoint). security_opt: - 'no-new-privileges:true' cap_drop: - ALL cap_add: - CHOWN - DAC_OVERRIDE - FOWNER - SETGID - SETUID read_only: true tmpfs: - /tmp # Per-container PID ceiling (cgroup pids.max). 2048 fits several whatsapp-web.js sessions, which # each run a multi-process Chromium; Baileys (no Chromium) uses far fewer. A fork-bomb guard, not # an allocation — raising it is free for light containers. Do NOT use -1 (drops the guard). #636 pids_limit: ${OPENWA_PIDS_LIMIT:-2048} mem_limit: ${OPENWA_MEM_LIMIT:-2g} ports: # Bind to localhost by default; set BIND_HOST=0.0.0.0 in .env to reach it from another host. - '${BIND_HOST:-127.0.0.1}:2785:2785' # User-facing settings read from the environment (or .env) with a sane default fallback # (${VAR:-default}); override any of them without editing this file. The data paths default # under /app/data (the ./data bind mount) so they persist out of the box — override only if you # also mount that target. Truly container-internal values (HOME, XDG_*, PORT) stay fixed: they # must match the image/entrypoint. Same convention as the production docker-compose.yml. environment: - NODE_ENV=${NODE_ENV:-development} - PORT=2785 - HOME=/tmp # Chromium reads its home from the passwd entry (no /home/openwa), so it needs writable, existing # config/cache dirs on the tmpfs or it hard-crashes at launch; the entrypoint pre-creates them. (#254) - XDG_CONFIG_HOME=/tmp/.config - XDG_CACHE_HOME=/tmp/.cache - LOG_LEVEL=${LOG_LEVEL:-info} - DATABASE_TYPE=${DATABASE_TYPE:-sqlite} - DATABASE_NAME=${DATABASE_NAME:-} - DATABASE_SYNCHRONIZE=${DATABASE_SYNCHRONIZE:-true} # Engine. Forwarded empty by default so the dashboard (Infrastructure > Engine) selects the # active engine via data/.env.generated (default whatsapp-web.js); main.ts treats a blank # ENGINE_TYPE as unset, so .env.generated wins. Set ENGINE_TYPE in your .env/host to pin an # engine (e.g. baileys) — a real value flows through here and keeps top precedence. - ENGINE_TYPE=${ENGINE_TYPE:-} - SESSION_DATA_PATH=${SESSION_DATA_PATH:-/app/data/sessions} - PUPPETEER_HEADLESS=${PUPPETEER_HEADLESS:-true} - PUPPETEER_ARGS=${PUPPETEER_ARGS:---no-sandbox,--disable-setuid-sandbox,--disable-dev-shm-usage,--disable-gpu} # Optional WhatsApp Web version override. Leave empty for whatsapp-web.js auto-selection. # If a session hangs at "authenticating", set WWEBJS_WEB_VERSION to a known-good cached build # from wppconnect-team/wa-version; latest|auto|off also forces auto-selection. - WWEBJS_WEB_VERSION=${WWEBJS_WEB_VERSION:-} - WWEBJS_WEB_VERSION_REMOTE_PATH=${WWEBJS_WEB_VERSION_REMOTE_PATH:-} # Raise whatsapp-web.js's first-boot init wait (default 30000ms) on slow boots. Empty = default. - WWEBJS_AUTH_TIMEOUT_MS=${WWEBJS_AUTH_TIMEOUT_MS:-} - STORAGE_TYPE=${STORAGE_TYPE:-local} - STORAGE_LOCAL_PATH=${STORAGE_LOCAL_PATH:-/app/data/media} # Install plugins into the writable, persistent data volume (the root FS is read-only). Matches # docker-compose.yml; without this it falls back to ./plugins on the read-only root and install fails. - PLUGINS_DIR=${PLUGINS_DIR:-/app/data/plugins} - WEBHOOK_TIMEOUT=${WEBHOOK_TIMEOUT:-10000} - WEBHOOK_MAX_RETRIES=${WEBHOOK_MAX_RETRIES:-3} - QUEUE_ENABLED=${QUEUE_ENABLED:-false} volumes: - ./data:/app/data restart: unless-stopped healthcheck: test: ['CMD', 'curl', '-f', 'http://localhost:2785/api/health/ready'] interval: 30s timeout: 10s retries: 3 start_period: 30s # The dashboard SPA is bundled into the image and served by NestJS on the same port: # open http://localhost:2785 — there is no separate dashboard container. networks: default: name: openwa-network