open-wa v5 is alpha. Use v4.76.0 for mature production systems unless you are validating v5.
The Client APIAPI ExplorerLicensing

Security and Deployment

Secure your API, manage keys, and deploy to production safely.

Security Shield Wally

Security and Deployment

Running open-wa in production requires attention to API key management, network security, and session protection.

Runtime prerequisites

For monorepo development and source builds, the repo declares Node.js >= 22.21.1 and pnpm >= 10.25.0, with packageManager pinned to pnpm@10.26.1. Match those versions before debugging runtime or build issues.

API Key Management

Why API Keys Are Required

Every open-wa session should be protected by an API key. Without one, anyone who can reach your server can control your WhatsApp session.

Generating Secure Keys

Use a cryptographically random string:

# Generate a random key
openssl rand -hex 32
# or
node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"

Storing Keys Safely

Environment variables are the recommended approach:

export WA_API_KEY="your-generated-key"
npx @open-wa/wa-automate --port 8080 --api-key "$WA_API_KEY"

Or in a .env file:

WA_API_KEY=your-generated-key

For production deployments, use a secrets manager (AWS Secrets Manager, HashiCorp Vault, Doppler, etc.).

Rotating Keys Without Downtime

  1. Start a new session with the new API key
  2. Update all consumers to use the new key
  3. Stop the old session
  4. The session data (auth tokens) is separate from the API key, so rotation does not require re-authentication

What Happens If a Key Is Leaked

If your API key is exposed:

  1. Stop the running session immediately
  2. Generate a new API key
  3. Restart with the new key
  4. Audit what actions were taken with the leaked key
  5. Consider logging out from the phone and re-authenticating if you suspect unauthorized access

Port and Network Security

Exposing Ports to the Internet

Never expose the Easy API port directly to the internet without authentication. At minimum:

  • Always use --api-key "your-secure-key"
  • Use a reverse proxy (nginx, Caddy) with HTTPS
  • Restrict access to known IP addresses when possible

Using Reverse Proxies

nginx example:

server {
    listen 443 ssl;
    server_name whatsapp-api.example.com;

    location / {
        proxy_pass http://localhost:8080;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
}

Caddy example:

whatsapp-api.example.com {
    reverse_proxy localhost:8080
}

Cloudflare Tunnel Alternative

Instead of opening ports, use Cloudflare Tunnel to expose your API securely:

cloudflared tunnel --url http://localhost:8080

This gives you HTTPS without managing certificates or opening firewall rules.

Firewall Rules

If you must expose the API directly, restrict access:

# Only allow specific IPs
ufw allow from 1.2.3.4 to any port 8080

Webhook Security

Securing Webhook Endpoints

When open-wa sends webhooks to your service:

  • Use HTTPS for the webhook URL
  • Add authentication headers via the webhook headers config
  • Verify the source IP if your endpoint is public

Signature Verification

If your webhook endpoint is public, implement signature verification to ensure requests come from your open-wa instance.

Rate Limiting Webhook Receivers

Your webhook receiver should handle the volume of incoming events. The webhook plugin supports:

  • concurrency (default: 10): max concurrent deliveries
  • retries (default: 3): retry attempts on failure
  • retryDelay (default: 1000ms): base delay with exponential backoff
  • timeout (default: 30000ms): request timeout

MCP Security

API Key Enforcement

MCP requires an Easy API API key. It will not start without one. Every MCP request must include the same key as the Easy API through an accepted API-key header: X-API-Key, api_key, or key.

Endpoint Exposure Risks

If the MCP endpoint is exposed publicly, the API key is leaked, or untrusted agents are allowed to use the key, those agents could:

  • Read all messages in all chats
  • Send messages to any contact
  • Access session information

Always protect the MCP endpoint with the API key, keep the key secret, and, ideally, place the endpoint behind a reverse proxy.

Restricting AI Agent Operations

Currently, MCP exposes all Easy API methods as tools. There are no permission scopes, so any authenticated agent can call any method. Plan your deployment accordingly.

Audit Trails

Monitor MCP usage through:

  • API access logs
  • The dashboard MCP page (http://localhost:8080/dashboard/mcp)
  • Your reverse proxy access logs

Proxy Security

Cloudflare Proxy Token Rotation

The Cloudflare Session Proxy uses consumer tokens for authentication. Rotate these tokens periodically:

  1. Update the token in your Cloudflare Worker
  2. Update the token in your consumer connection string
  3. Test the new connection before removing the old token

Custom Domains

You can attach a custom domain to your Cloudflare Worker for a cleaner connection URL.

Production Checklist

Before deploying to production:

  • API key set and stored securely (not in code or config files committed to git)
  • HTTPS enabled (reverse proxy or Cloudflare Tunnel)
  • Session persistence configured (volumes for Docker, persistent disk for servers)
  • Webhook auth configured (headers or IP restriction)
  • Rate limits understood and safe defaults applied
  • Logging enabled and monitored
  • Backup strategy for session files in place
  • Monitoring configured (health checks, alerting on session disconnect)
  • Process manager configured (PM2, systemd, Docker restart policy)
  • Firewall rules applied (only necessary ports open)

Deployment Topologies

Single Server

[Your App] ←→ [open-wa Easy API] ←→ WhatsApp Web (browser)
  • Simplest setup
  • Run with npx @open-wa/wa-automate --port 8080 --api-key "key"
  • Use PM2 or systemd for process management

Docker Container

docker run -p 8080:8080 \
  -e WA_PORT=8080 \
  -e WA_API_KEY="your-key" \
  -e WA_SESSION_ID=sales \
  -e WA_USER_DATA_DIR=/sessions/sales \
  -v ./sessions:/sessions \
  --init \
  openwa/wa-automate
  • Isolated environment
  • Volume mount plus WA_USER_DATA_DIR for session persistence
  • --init for proper process cleanup

The v5 Docker image runs from /usr/src/app. If WA_USER_DATA_DIR is not set and the session is not ephemeral, the runtime derives profile storage as /usr/src/app/_IGNORE_<sessionId>. For Docker, prefer mounting /sessions and setting WA_USER_DATA_DIR=/sessions/<sessionId> so the browser profile is on the mounted volume.

Docker Compose (Multi-Session)

version: '3'
services:
  sales-bot:
    image: openwa/wa-automate
    ports:
      - "8080:8080"
    volumes:
      - ./sessions:/sessions
    environment:
      - WA_API_KEY=sales-key
      - WA_SESSION_ID=sales
      - WA_PORT=8080
      - WA_USER_DATA_DIR=/sessions/sales

  support-bot:
    image: openwa/wa-automate
    ports:
      - "8081:8081"
    volumes:
      - ./sessions:/sessions
    environment:
      - WA_API_KEY=support-key
      - WA_SESSION_ID=support
      - WA_PORT=8081
      - WA_USER_DATA_DIR=/sessions/support

After first authentication, restart each container with the same WA_SESSION_ID and WA_USER_DATA_DIR. Expected local verification: the session reconnects without a new QR prompt because the profile directory under ./sessions/<sessionId> is reused. This is a checklist expectation for local deployment validation, not captured terminal output from this docs update.

Cloudflare Proxy + Local Runtime

[Your App] ←→ [Cloudflare Proxy] ←→ [open-wa Easy API (local)] ←→ WhatsApp

Kubernetes

For large-scale deployments:

  • One pod per session (sessions do not share state)
  • Persistent volumes for session data
  • Horizontal Pod Autoscaler based on session count
  • Service mesh for internal routing
Wally the Walrus typing

Was this helpful?

Wally and his cute companion coffee mug are coding day and night to keep this up-to-date!

On this page