- 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>
302 lines
11 KiB
Markdown
302 lines
11 KiB
Markdown
---
|
|
summary: "Case study: 5 cheap Android phones each running an OpenClaw gateway on a different channel"
|
|
read_when:
|
|
- Planning a multi-device distributed gateway deployment
|
|
- Wanting to spread channels across separate phones
|
|
- Budget hardware planning for an OpenClaw setup
|
|
title: "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:
|
|
|
|
```bash
|
|
# 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](/gateway/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:**
|
|
|
|
```json5
|
|
{
|
|
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:**
|
|
|
|
```json5
|
|
{
|
|
channels: {
|
|
telegram: {
|
|
enabled: true,
|
|
botToken: "<your-bot-token>",
|
|
dmPolicy: "pairing",
|
|
},
|
|
},
|
|
gateway: {
|
|
tailscale: { mode: "serve" },
|
|
},
|
|
}
|
|
```
|
|
|
|
**Phone 3 -- Discord:**
|
|
|
|
```json5
|
|
{
|
|
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:
|
|
|
|
```bash
|
|
signal-cli link -n "OpenClaw"
|
|
```
|
|
|
|
Config:
|
|
|
|
```json5
|
|
{
|
|
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`:
|
|
|
|
```bash
|
|
# Enable the background service
|
|
sv-enable openclaw
|
|
sv up openclaw
|
|
```
|
|
|
|
Or use a simple `nohup` approach in a `tmux` session:
|
|
|
|
```bash
|
|
tmux new -s openclaw
|
|
nohup openclaw gateway run --bind loopback --port 18789 > ~/openclaw.log 2>&1 &
|
|
```
|
|
|
|
Check status:
|
|
|
|
```bash
|
|
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](/gateway/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.
|
|
|
|
## Related Docs
|
|
|
|
- [Channels overview](/channels)
|
|
- [WhatsApp](/channels/whatsapp)
|
|
- [Telegram](/channels/telegram)
|
|
- [Discord](/channels/discord)
|
|
- [Signal](/channels/signal)
|
|
- [Tailscale](/gateway/tailscale)
|
|
- [Multiple Gateways](/gateway/multiple-gateways)
|
|
- [VPS Hosting](/vps)
|