File size: 6,153 Bytes
46252cd
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
# 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}
      # Restart-resilience: auto-start previously authenticated sessions on boot. The liveness
      # watchdog (#798) only covers a RUNNING container β€” a `compose down/up` or rebuild kills every
      # engine, and without this flag sessions sit at `disconnected` until started by hand. Default
      # ON for the dev compose (single-operator box); the app-level default stays OFF.
      - AUTO_START_SESSIONS=${AUTO_START_SESSIONS:-true}
      - 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:-}
      # Forward the plain-HTTP dashboard CSP override; unset preserves the application default.
      - CSP_UPGRADE_INSECURE_REQUESTS=${CSP_UPGRADE_INSECURE_REQUESTS:-}
      - 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_RETRY_DELAY=${WEBHOOK_RETRY_DELAY:-5000}
      - WEBHOOK_DISPATCH_CONCURRENCY=${WEBHOOK_DISPATCH_CONCURRENCY:-16}
      - WEBHOOK_DISPATCH_MAX_QUEUED=${WEBHOOK_DISPATCH_MAX_QUEUED:-1000}
      - RATE_LIMIT_SHORT_TTL=${RATE_LIMIT_SHORT_TTL:-}
      - RATE_LIMIT_SHORT_LIMIT=${RATE_LIMIT_SHORT_LIMIT:-}
      - RATE_LIMIT_MEDIUM_TTL=${RATE_LIMIT_MEDIUM_TTL:-}
      - RATE_LIMIT_MEDIUM_LIMIT=${RATE_LIMIT_MEDIUM_LIMIT:-}
      - RATE_LIMIT_LONG_TTL=${RATE_LIMIT_LONG_TTL:-}
      - RATE_LIMIT_LONG_LIMIT=${RATE_LIMIT_LONG_LIMIT:-}
      # Max request body size. Base64 media sends ride in the JSON body, so the default is generous;
      # raise this for large documents (e.g. BODY_SIZE_LIMIT=50mb). Blank keeps the app default of 25mb.
      - BODY_SIZE_LIMIT=${BODY_SIZE_LIMIT:-}
      - TRUSTED_PROXIES=${TRUSTED_PROXIES:-}
      - 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