Signal Deployment

March 1, 2026 ยท View on GitHub

Run nullclaw as a Signal chatbot using Docker Compose and a local signal-cli container.

Architecture

Signal app  <-->  signal-cli container (:8080)  <-->  nullclaw gateway (:3000)

Setup

docker compose -f docker-compose.yml -f docker-compose.signal.yml up -d signal-cli
docker compose -f docker-compose.yml -f docker-compose.signal.yml exec signal-cli signal-cli link -n nullclaw

Scan the QR code in Signal (Settings -> Linked Devices -> Link New Device), then stop the signal-cli container.

2. Create local config files

Create .env.signal with your secrets:

OPENROUTER_API_KEY=...
SIGNAL_ACCOUNT=+1...
SIGNAL_RECIPIENT=+1...   # or uuid:...

Create config.signal.json (example):

{
  "models": {
    "providers": {
      "openrouter": {
        "api_key": "YOUR_OPENROUTER_API_KEY"
      }
    }
  },
  "agents": {
    "defaults": {
      "model": {
        "primary": "openrouter/anthropic/claude-sonnet-4"
      }
    }
  },
  "channels": {
    "signal": {
      "accounts": {
        "main": {
          "http_url": "http://signal-cli:8080",
          "account": "+10000000000",
          "allow_from": ["+10000000001"],
          "group_policy": "allowlist",
          "ignore_attachments": true,
          "ignore_stories": true
        }
      }
    }
  },
  "gateway": {
    "port": 3000,
    "host": "0.0.0.0",
    "require_pairing": false
  }
}

Keep http_url as http://signal-cli:8080 for Docker networking.

3. Build nullclaw image

DOCKER_BUILDKIT=0 docker build -t nullclaw:latest .

Runtime modes (env-gated)

To prevent regressions, Docker defaults to the legacy JSON-RPC mode:

  • SIGNAL_USE_REST_API=0 (default)
  • SIGNAL_CLI_MODE=json-rpc (default)

To opt into signal-cli-rest-api REST mode explicitly:

export SIGNAL_USE_REST_API=1
export SIGNAL_CLI_MODE=normal

Then start as usual.

Usage

Start

docker compose -f docker-compose.yml -f docker-compose.signal.yml --profile gateway up -d

Stop

docker compose -f docker-compose.yml -f docker-compose.signal.yml --profile gateway down

Logs

docker compose -f docker-compose.yml -f docker-compose.signal.yml --profile gateway logs -f

Health checks

curl http://localhost:3000/health
curl -i http://localhost:8080/v1/health

Cleanup

docker compose -f docker-compose.yml -f docker-compose.signal.yml --profile gateway down -v
docker rmi nullclaw:latest
docker rmi bbernhard/signal-cli-rest-api:latest
rm -rf ~/.local/share/signal-cli
rm -f .env.signal config.signal.json