Files
openclaw/docs/case-study-5-phone-deployment.md
Clawd Bot ca9b510922 chore: align with upstream openclaw/openclaw and overlay local additions
- Reset master to upstream/main (16,697 commits)
- Overlay 2,271 local-only files (skills, tools, workspace, configs, apps)
- Restore IDENTITY.md and USER.md templates
- Build verified, gateway running, Discord working

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-03 07:40:46 +01:00

11 KiB

summary, read_when, title
summary read_when title
Case study: 5 cheap Android phones each running an OpenClaw gateway on a different channel
Planning a multi-device distributed gateway deployment
Wanting to spread channels across separate phones
Budget hardware planning for an OpenClaw setup
Case Study: 5-Phone Distributed Gateway

Case Study: 5-Phone Distributed Gateway

This case study walks through a real-world deployment pattern: five cheap Android phones, each running its own OpenClaw gateway, each dedicated to one messaging channel. The result is a distributed setup where no single device is a point of failure for all channels, and each phone keeps its own channel account isolated.

Scenario

Device Channel Notes
Phone 1 WhatsApp WhatsApp Web (Baileys); dedicated number
Phone 2 Telegram Bot token; always-on polling
Phone 3 Discord Bot token; private server
Phone 4 Signal signal-cli + dedicated number
Phone 5 SMS (iMessage/Twilio fallback) SIM-based or Twilio; read section below

Each gateway runs independently. There is no cross-device routing by default; each device owns its own conversations, sessions, and workspace. Cross-channel routing (sending a WhatsApp reply from a Telegram prompt, for example) can be added via hooks or a shared orchestration agent but is not required for the basic setup.

Hardware

Device choice: Xiaomi Redmi 9 (or equivalent mid-range Android, ~50 EUR each).

Item Approx. cost
5x Xiaomi Redmi 9 5 x 50 EUR = 250 EUR
5x USB chargers + cables ~15 EUR
Small USB hub or power strip ~10 EUR
Total hardware ~275 EUR

Any Android phone with 3 GB RAM or more works. The Redmi 9 hits the budget sweet spot: it runs Node 22 (via Termux) comfortably, has adequate thermal performance for a background process, and charges reliably off a USB hub.

Why not a Raspberry Pi or VPS instead?

  • Phones already have LTE/SIM slots for the SMS/Signal use case.
  • WhatsApp Web requires an active mobile-linked session; a phone holding its own WhatsApp account stays linked without the re-link prompts that happen on a VPS after idle.
  • Total cost is comparable to a Pi 4 + SIM HAT per channel.

Software Stack (per phone)

  1. Termux (F-Droid build recommended) -- provides the terminal, pkg package manager, and persistent background process support via termux-services.
  2. Node 22 -- pkg install nodejs-lts (or build from source for exact version).
  3. OpenClaw (stable release) -- npm install -g openclaw.
  4. Tailscale -- pkg install tailscale; used for remote access and cross-device LAN.

Optional but useful:

  • termux-api + Termux:API companion app: exposes SMS send/receive on the phone's SIM for the SMS gateway device.
  • openssh in Termux: allows SSH from your laptop for maintenance.

Network Setup

Local network

All five phones connect to the same home WiFi. Each gateway binds to loopback by default (127.0.0.1:18789). Tailscale Serve exposes each gateway on the tailnet so you can reach the dashboard from any device on your Tailscale network.

Home router (192.168.1.0/24)
  Phone 1 (WhatsApp)   192.168.1.101  tailnet: phone1.your-tailnet.ts.net
  Phone 2 (Telegram)   192.168.1.102  tailnet: phone2.your-tailnet.ts.net
  Phone 3 (Discord)    192.168.1.103  tailnet: phone3.your-tailnet.ts.net
  Phone 4 (Signal)     192.168.1.104  tailnet: phone4.your-tailnet.ts.net
  Phone 5 (SMS)        192.168.1.105  tailnet: phone5.your-tailnet.ts.net

Tailscale for remote access

Each phone runs Tailscale in Termux. After tailscale up, each phone gets a stable tailnet hostname. The gateway dashboard (port 18789) is then reachable via Tailscale Serve:

# On each phone, one-time setup
tailscale serve --bg https+insecure://localhost:18789

With gateway.tailscale.mode: "serve" set in the OpenClaw config, OpenClaw manages this automatically. See Tailscale for auth details.

This means you can open any phone's dashboard from your laptop even when you are away from home, without exposing any port to the public internet.

OpenClaw Configuration (per phone)

Each phone has its own ~/.openclaw/openclaw.json. Here are minimal examples.

Phone 1 -- WhatsApp:

{
  channels: {
    whatsapp: {
      dmPolicy: "allowlist",
      allowFrom: ["+15551234567"],
    },
  },
  gateway: {
    tailscale: { mode: "serve" },
  },
}

Run openclaw channels login once to scan the WhatsApp QR code. After that, the session persists across restarts.

Phone 2 -- Telegram:

{
  channels: {
    telegram: {
      enabled: true,
      botToken: "<your-bot-token>",
      dmPolicy: "pairing",
    },
  },
  gateway: {
    tailscale: { mode: "serve" },
  },
}

Phone 3 -- Discord:

{
  channels: {
    discord: {
      enabled: true,
      token: "<raw-bot-token>",
      dmPolicy: "pairing",
    },
  },
  gateway: {
    tailscale: { mode: "serve" },
  },
}

Phone 4 -- Signal:

Signal requires signal-cli (Java-based). Install a Termux-compatible JDK (pkg install openjdk-17) and download the signal-cli release binary. Link the bot account once:

signal-cli link -n "OpenClaw"

Config:

{
  channels: {
    signal: {
      enabled: true,
      account: "+15550001111",
      cliPath: "/data/data/com.termux/files/usr/bin/signal-cli",
      dmPolicy: "pairing",
    },
  },
  gateway: {
    tailscale: { mode: "serve" },
  },
}

Note: signal-cli on Android/Termux uses more RAM than the others. Give Phone 4 a slightly beefier device (4 GB RAM) if budget allows.

Phone 5 -- SMS:

SMS via the phone's own SIM uses termux-api to send and receive. This is a community pattern; OpenClaw does not yet have a built-in SMS channel adapter. Alternatives:

  • Use a Twilio number and the OpenClaw webhook/HTTP integration.
  • Use a WhatsApp-linked number on Phone 5 as a second WhatsApp gateway instead.

For this case study, Phone 5 runs a Twilio-backed webhook adapter proxied into OpenClaw via the HTTP API.

Starting the Gateway (Termux)

To keep the gateway running after Termux is backgrounded, use termux-services:

# Enable the background service
sv-enable openclaw
sv up openclaw

Or use a simple nohup approach in a tmux session:

tmux new -s openclaw
nohup openclaw gateway run --bind loopback --port 18789 > ~/openclaw.log 2>&1 &

Check status:

openclaw channels status --probe
openclaw health

How Routing Works

Each phone is a fully independent gateway. Routing within a single device is standard OpenClaw routing: a message arrives on the configured channel, the gateway assigns it an agent session, the agent replies on the same channel.

There is no built-in cross-phone routing. If you want a message from WhatsApp (Phone 1) to be visible on Telegram (Phone 2), you have two options:

  1. Hooks: configure an outgoing hook on Phone 1 that POSTs to Phone 2's HTTP API.
  2. Orchestration agent: run a fifth agent that subscribes to a shared coordination channel (e.g., a private Discord channel on Phone 3) and fans messages out.

For most personal deployments, isolation per channel is actually the desired behaviour: each channel has its own conversation history and workspace.

Cost Breakdown

Item One-time Monthly
5x Android phones (~50 EUR) 275 EUR --
SIM cards (1 for Signal, 1 for SMS) ~10 EUR ~5-10 EUR
Electricity (5 phones idle, ~2W each, ~720 Wh/month total) -- ~0.15 EUR
Tailscale (Personal plan) -- Free
OpenClaw (self-hosted) -- Free
API keys (Anthropic/OpenAI) -- ~5-20 EUR (usage-dependent)
Total ~285 EUR ~10-30 EUR/month

The dominant ongoing cost is the LLM API usage, not the infrastructure. Using a local model (Ollama, llama.cpp) on one of the phones or a local server reduces this to near-zero for light workloads, at the cost of response quality.

Lessons Learned and Gotchas

WhatsApp re-linking: WhatsApp Web (Baileys) requires an active linked-device session. If the phone reboots and the session cookie expires, you need to re-scan the QR. Keep the Phone 1 screen accessible (use scrcpy over ADB or a small LCD). Avoid factory-resetting the WhatsApp account; that invalidates all sessions.

Signal and Java memory: signal-cli on ARM (Termux/Android) is memory-hungry. The JVM default heap can exceed 512 MB on some message loads. Set JAVA_OPTS="-Xmx256m" in your Termux environment to cap it, and accept slightly slower startup.

Termux wake lock: Android aggressively kills background processes. In Termux settings, enable "Acquire Wakelock" and add Termux to the battery optimization exclusion list for each phone. Without this, the gateway silently dies after ~20 minutes of screen-off.

Tailscale on Android Termux: Tailscale in Termux runs as a userspace daemon and needs /dev/tun. On some Android versions, /dev/tun requires root or a VPN permission. Grant the Termux app VPN permissions in Android settings, or use the official Tailscale Android app alongside Termux (the Tailscale app does not conflict with Termux's instance if you pick only one approach per phone).

Port conflicts: each phone runs a single gateway, so there are no port conflicts. If you later add a second gateway on the same phone (rescue-bot pattern), follow the port-spacing rules in Multiple Gateways.

SD card storage: store sessions and workspace on internal storage, not SD card. SD card I/O latency causes session file write delays that can corrupt JSONL session logs under load.

Power cycling: phones on USB hubs occasionally restart due to insufficient current. Use a powered USB hub (minimum 2 A per port) or individual USB chargers. Unplanned reboots trigger the WhatsApp re-link problem above.

Network interruptions: if home WiFi drops, Signal and Telegram reconnect automatically. WhatsApp Web needs the gateway process to handle reconnection; OpenClaw does this internally, but if the phone's WiFi stack stalls (common on budget Androids), a Termux wakeup script via termux-wake-lock + a cron-style ping loop helps.