OpenClaw
on Android
Everything that actually works. Written from real failures, not documentation.
One phone. Ubuntu proot. NordVPN Meshnet. nginx HTTPS. No fluff.
Battery Setup
If this phone is staying plugged in 24/7 as an AI agent, your battery will degrade fast unless you set a charge limit. 85% is the sweet spot β your phone stays usable but isn't held at peak voltage constantly.
Samsung (One UI 4+)
- 01
Settings β Battery and device care β Battery
- 02
Tap More battery settings
- 03
Enable Protect battery β this caps charging at 85%
Motorola / Stock Android
- 01
Settings β Battery β Adaptive preferences or Battery health
- 02
Enable Optimized charging or Charge limit
- 03
If no built-in option exists, leave it β don't worry about it. Running the phone at moderate temperatures matters more than the charge limit.
Keep the phone somewhere cool and ventilated. Heat is the #1 battery killer β more damaging than charge percentage. Don't leave it on a warm surface or under a pillow while it runs.
Expand RAM with Swap
OpenClaw + Ubuntu proot + Node.js 22 can push 1.2β1.8GB of RAM in active use. If your phone has 4GB or less, Android will start killing background processes to reclaim memory, which can take down your gateway mid-session. A swap file on internal storage acts as overflow RAM β slower than real RAM, but enough to keep things alive.
Swap doesn't make your phone faster. It's a safety net β when RAM fills up, Android moves idle pages to the swap file on storage instead of killing processes outright. For a 24/7 server this is exactly what you want: the gateway stays alive even when Android is under memory pressure. Modern UFS 3.x internal storage is fast enough and rated for many years of this workload.
SWAP β No ROOT (Play Store)
No root required, works on most Android phones. Search "SWAP No ROOT" by AllaKore on the Play Store.
- 01
Install SWAP β No ROOT by AllaKore from the Play Store.
- 02
Open the app β tap Create SWAP file.
- 03
Set the size. 2GB is the recommended starting point for a dedicated agent phone. Don't exceed 50% of your free internal storage β you need space for Ubuntu and OpenClaw files.
- 04
Tap Activate. The swap file is created on internal storage.
- 05
Enable "Activate on boot" in the app so swap persists through reboots.
4GB RAM phone β create 2GB swap. 6GB phone β 1β2GB still useful as a buffer. 8GB+ phone β swap is optional, OpenClaw fits comfortably. Check free storage first: Settings β Storage. Have at least 15GB free before creating swap.
If the app offers to put the swap on an SD card β don't. SD card write speeds are far too slow for swap and will hurt performance. Internal UFS storage only.
Verify swap is active inside Ubuntu
# Should show your swap file and its size
cat /proc/swaps
free -h
If /proc/swaps shows a swap entry, it's working. free -h will show a Swap: row with your allocated size next to it.
Keep it Cool
Heat is your biggest enemy for 24/7 operation. When the processor gets hot, Android's thermal governor cuts clock speeds β sometimes by 50% or more. This is why npm installs take longer than expected, and why a "faster" phone can finish tasks slower than an older one. Keeping the phone cool is the single most impactful hardware optimization you can make.
Physical setup
- 01
Remove the case. Phone cases trap heat. Running caseless can drop surface temps by 5β10Β°C.
- 02
Stand the phone upright or prop it on its side. Flat on a surface traps heat underneath.
- 03
Point a small USB fan at it. Even a cheap desk fan dramatically improves sustained CPU performance. This is the most effective and cheapest hardware upgrade for a phone server.
- 04
Don't stack both phones together β they'll heat each other. Keep at least 10cm between them.
- 05
Don't put them inside a drawer, cabinet, or any enclosed space.
Software tweaks
- 01
Set screen timeout to minimum (15 or 30 seconds). The display is a significant heat source β keeping it off while the gateway runs lowers temps noticeably.
- 02
Set display refresh rate to 60Hz in Settings β Display. 90/120Hz increases GPU and CPU load even when you're not actively looking at the screen.
- 03
Lower brightness to minimum when not using the phone actively.
- 04
On Samsung: Settings β Developer options β Rendering β Disable HW overlays β reduces GPU workload slightly.
A healthy 24/7 phone server runs at 35β45Β°C surface temperature. If the back of the phone feels too hot to hold comfortably for 10 seconds, it's throttling. Add a fan or remove the case first.
PC Control via scrcpy
If you have a PC, use scrcpy to control your phone from your desktop. This is strongly recommended for the installation process β you can paste long commands from your PC clipboard directly into Termux without typing everything on the phone screen.
Download scrcpy from github.com/Genymobile/scrcpy/releases β get the win64 zip, extract it anywhere.
Connect your phone
Enable USB Debugging on your phone: Settings β About phone β tap Build number 7 times β Developer options β USB debugging ON. Then plug in via USB and run:
# Single phone scrcpy.exe --prefer-text # If you have multiple phones connected, specify by serial scrcpy.exe -s YOUR_DEVICE_SERIAL --prefer-text # Find serials if needed adb devices
--prefer-text is required if you're on a Finnish/Nordic keyboard layout. Without it, characters like Γ₯, Γ€, ΓΆ get mangled or dropped entirely when pasting into the terminal.
Pasting into the phone terminal
scrcpy truncates pastes that are too long β commands over ~120 characters get cut off mid-paste. If this happens, paste the command one line at a time, or use nano to type multi-line config files directly on the phone.
Permissions & Wake Lock
Android aggressively kills background apps to save battery. Without the right permissions, Termux and NordVPN get killed the moment the screen turns off β which kills your OpenClaw gateway and drops the Meshnet.
Battery optimization β must disable for both apps
- 01
Settings β Apps β Termux β Battery β Set to Unrestricted (Samsung) or Don't optimize (Moto/stock)
- 02
Do the same for NordVPN
- 03
On Samsung: also go to Settings β Device care β Battery β Background usage limits β make sure Termux is NOT in the sleeping apps list
Termux wake lock (keep CPU running)
Run this inside Termux once and it keeps your session alive even with the screen off:
termux-wake-lock
Also install Termux:Boot from F-Droid. This lets Termux auto-start after a reboot without you having to manually open it. Critical for a 24/7 setup.
Install Termux
Install Termux from F-Droid, NOT the Google Play Store. The Play Store version is outdated (stopped being updated in 2020) and silently breaks npm installs, package signing, and more. Go to f-droid.org, install the F-Droid app, then search for Termux.
While you're in F-Droid, also install Termux:Boot for auto-start on reboot.
First run
# Update the package index first β always pkg update && pkg upgrade -y # Install proot-distro β this is the only thing we need from Termux pkg pkg install proot-distro curl -y # Lock the CPU awake termux-wake-lock
The vim/neovim package in Termux is called neovim, NOT nvim. Many online guides have this wrong and it causes a confusing error. pkg install neovim if you want an editor β though you won't need one for this guide.
Ubuntu proot
This is the most important decision in the entire guide: Ubuntu proot is not optional. Bare Termux uses Android's Bionic libc which is incompatible with how Node.js native modules compile. OpenClaw's core dependency (koffi) will fail to build every single time in bare Termux, no matter what flags you use.
Bare Termux fails because Android's Bionic libc is not binary-compatible with Linux glibc. The koffi module (which OpenClaw needs to call system functions) compiles for glibc and crashes immediately on Bionic. Ubuntu proot gives you real glibc, proper /tmp, and a real Linux filesystem. There is no workaround β use Ubuntu.
# Download and install Ubuntu β takes a minute on first run proot-distro install ubuntu # Enter Ubuntu β run this every time you open Termux proot-distro login ubuntu
Your prompt will change from $ to root@localhost:~#. Everything from this point forward runs inside Ubuntu unless stated otherwise.
# Update Ubuntu package lists apt update && apt upgrade -y # Install build tools and deps apt install -y curl git build-essential tmux lsof nano
Node.js 22
Use the NodeSource installer to get Node.js 22 inside Ubuntu. Do not use apt install nodejs directly β the version in Ubuntu's default repos is too old and will break OpenClaw.
# Add NodeSource repo for Node 22 curl -fsSL https://deb.nodesource.com/setup_22.x | bash - # Install Node.js apt install -y nodejs # Verify β should show v22.x.x node -v npm -v
You should see v22.22.0 (or similar) and 10.9.x for npm. If node -v shows v24 or higher, you have the wrong version β run the NodeSource setup script again.
Install OpenClaw
# Install OpenClaw globally
npm install -g openclaw@latest
You will see many npm warn deprecated messages during install. These are completely harmless β they're notices about outdated sub-dependencies inside packages that OpenClaw uses. The install is working correctly. Wait for it to complete (3β5 minutes on a phone). It's done when you see added 847 packages in Xm.
If you get a compilation error about koffi, sharp, or canvas, use --ignore-scripts to skip optional native builds. This skips Discord voice and image processing β neither is needed for basic agent use:
npm install -g openclaw@latest --ignore-scripts
# Verify install
openclaw --version
If a newer/faster phone finishes npm install slower than an older one β this is normal. The "faster" phone may be thermally throttling (gets hot under sustained CPU load and slows down). Don't cancel the install.
Android Network Fix
OpenClaw calls os.networkInterfaces() at startup. On Android/proot this call behaves oddly and can cause a crash or hang. A tiny script patches it before OpenClaw loads.
# Create the patch script cat <<'EOF' > /root/hijack.js const os = require('os'); os.networkInterfaces = () => ({}); EOF # Load it automatically on every session + fix tmp path cat >> ~/.bashrc <<'EOF' export NODE_OPTIONS="-r /root/hijack.js" export TMPDIR=/tmp EOF source ~/.bashrc
If you see "Cannot find module '/root/hijacks.js'" β note the extra s. A stale NODE_OPTIONS from a previous failed attempt is pointing to the wrong file. Fix it: unset NODE_OPTIONS, then recreate hijack.js as shown above.
Onboarding Wizard
Run the setup wizard once. This configures your API key, port, and initial settings. You won't need to run it again after this.
openclaw onboard
Wizard answers
| Prompt | What to choose |
|---|---|
| Gateway Bind | 0.0.0.0 β needed for Meshnet and browser access |
| Gateway Port | 18789 (default) β or pick anything above 1024 |
| Auth mode | Token (default) |
| Model provider | OpenRouter (free tier available at openrouter.ai) |
| API Key | Your OpenRouter key β starts with sk-or-v1- |
| Default model | openrouter/arcee-ai/trinity-large-preview:free (or any free model) |
| Telegram channel | Skip β configure manually after, wizard has a bug |
| Skills install | Yes β let it run, brew/go failures are expected and harmless |
"Gateway service install not supported on android" at the very end is completely normal β not an error. Android has no systemd. You'll run the gateway manually in tmux instead.
"telegram plugin not available" during onboarding is a known bug. Telegram is a channel in OpenClaw, not a plugin β the wizard incorrectly tries to configure it under plugins. Skip it in the wizard and configure it manually in ~/.openclaw/openclaw.json after setup:
{
"channels": {
"telegram": {
"enabled": true,
"botToken": "YOUR_BOT_TOKEN_FROM_BOTFATHER",
"dmPolicy": "pairing"
}
}
}
Running the Gateway
The gateway is what keeps OpenClaw alive. Run it inside a tmux session so it stays running when you close the Termux window or the screen turns off.
# Start a named tmux session tmux new -s openclaw # Inside tmux, start the gateway openclaw gateway --verbose # βββββββββββββββββββββββββββββββββββββββββββββββββ # To DETACH (leave gateway running): Ctrl+B, then D # To REATTACH later: tmux attach -t openclaw
When the gateway is running you'll see log lines like [gateway] listening on ws://0.0.0.0:18789. That means it's working.
Killing and restarting
You cannot use openclaw gateway restart β systemd isn't available in proot and it fails. Kill by PID instead:
# Find what's running on your port lsof -i :18789 # Kill by PID from above output kill <PID> # Or kill by name pkill -f "openclaw gateway"
Reconnecting after phone reboot
# In Termux proot-distro login ubuntu # In Ubuntu tmux attach -t openclaw # If session is gone, start fresh tmux new -s openclaw openclaw gateway --verbose
If you get "sessions should be nested with care" β you're already inside a tmux session. Run unset TMUX && tmux attach -t openclaw instead.
NordVPN Meshnet
NordVPN cannot run inside Ubuntu proot. It requires kernel-level networking and systemd β proot has neither. Attempting to install it inside Ubuntu gives "couldn't find nordvpnd.sock". Use the Android app instead. The Meshnet IP created by the Android app is automatically reachable from within Ubuntu proot.
- 01
Install NordVPN from the Google Play Store on your phone.
- 02
Sign in. Go to Products β Meshnet and toggle it ON. This feature is free β you don't need a paid VPN subscription.
- 03
Your phone gets a stable Meshnet IP in the
100.64.x.xrange. Find it in the Meshnet screen. - 04
Add other devices by linking them to your Nord account, or using the invite system.
- 05
Grant "Local network access" to each peer in the Meshnet devices list.
- 06
Disable "Local network discovery" in NordVPN settings. This sounds counterintuitive but it's required for cross-device Meshnet connections to work reliably.
Set NordVPN's battery optimization to Unrestricted in Android settings, same as Termux. If Android kills NordVPN in the background, your Meshnet drops and the phone becomes unreachable from other devices.
Once Meshnet is active, your OpenClaw gateway is reachable at your Meshnet IP β but only as HTTP. To access the dashboard remotely you need HTTPS, which is the next step.
nginx HTTPS Proxy
Browsers block device identity APIs on plain HTTP connections. To access the OpenClaw dashboard from another device via Meshnet, you need HTTPS. nginx provides a self-signed HTTPS proxy in front of OpenClaw, bound specifically to the Meshnet interface.
Step 1 β Install nginx and generate a certificate
# Install nginx and openssl apt install -y nginx openssl # Remove the default site (it tries to bind port 80 which proot blocks) rm /etc/nginx/sites-enabled/default # Create cert directory and generate self-signed certificate mkdir -p /etc/nginx/certs openssl req -x509 -nodes -days 365 -newkey rsa:2048 \ -keyout /etc/nginx/certs/openclaw.key \ -out /etc/nginx/certs/openclaw.crt \ -subj "/CN=openclaw"
Step 2 β Create the nginx config
Use nano to type this directly β do not try to paste it via scrcpy as long multiline pastes get truncated. Replace YOUR_MESHNET_IP with your actual Meshnet IP (e.g. 100.69.xxx.xxx).
nano /etc/nginx/sites-available/openclaw
server {
listen YOUR_MESHNET_IP:8443 ssl;
ssl_certificate /etc/nginx/certs/openclaw.crt;
ssl_certificate_key /etc/nginx/certs/openclaw.key;
location / {
proxy_pass http://127.0.0.1:18789;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection upgrade;
proxy_set_header Host $host;
}
}
Save with Ctrl+X, Y, Enter.
Step 3 β Enable and start nginx
ln -s /etc/nginx/sites-available/openclaw /etc/nginx/sites-enabled/
nginx -t && nginx
# If nginx is already running from a previous attempt, reload instead:
nginx -s reload
By binding nginx to your specific Meshnet IP (not 0.0.0.0), only traffic coming through the Meshnet interface can reach it. Combined with NordVPN's device allowlist, only devices you've explicitly linked can access your gateway. Your OpenRouter API key and agent data stay private.
Dashboard Access
Step 1 β Allow token auth and set origins
Detach from tmux first (Ctrl+B, D), then run:
# Allow token-based login over HTTPS openclaw config set gateway.controlUi.allowInsecureAuth true # Allow requests from your Meshnet HTTPS address openclaw config set gateway.controlUi.allowedOrigins \ '["https://YOUR_MESHNET_IP:8443"]' # Get your auth token openclaw config get gateway.auth.token # Verify the setting saved cat ~/.openclaw/openclaw.json | grep -i insecure
Step 2 β Restart the gateway to apply settings
pkill -f "openclaw gateway"
tmux attach -t openclaw
openclaw gateway --verbose
# Detach again: Ctrl+B, D
Step 3 β Access the dashboard
Open a browser on any Meshnet-linked device and go to:
https://YOUR_MESHNET_IP:8443/#token=YOUR_TOKEN_HERE
Accept the self-signed certificate warning (tap Advanced β Proceed). The dashboard loads and you're in.
Step 4 β Approve device pairing
The first time you connect from a new browser, OpenClaw requires pairing approval. Visit the dashboard URL, then immediately run:
# List pending device requests openclaw devices list # Approve (use the full ID from the list β no spaces) openclaw devices approve <requestId>
Pairing request IDs expire when the gateway restarts. If you get "unknown requestId", visit the dashboard URL again to generate a new request, then immediately run openclaw devices list and approve before restarting anything.
You can always access the dashboard locally on the phone itself without HTTPS at http://localhost:18789 β localhost bypasses all the browser security restrictions. The nginx HTTPS setup is only needed for access from other devices.
Troubleshooting
| Error | Cause | Fix |
|---|---|---|
| Cannot find module '/root/hijacks.js' | Stale NODE_OPTIONS pointing to wrong filename (note the extra 's') | unset NODE_OPTIONS then recreate hijack.js |
| koffi build failed / CMake not found | Compiling in bare Termux (Bionic libc incompatibility) | Must use Ubuntu proot β no workaround |
| E: Unable to locate package nvim | Wrong package name | Package is called neovim, not nvim |
| [FAIL] Not running in Termux ($PREFIX not set) | Running the myopenclawhub bash installer (doesn't work) | Use npm install method only β skip the bash installer |
| npm warn deprecated (many lines) | Normal β just warnings, not errors | Wait for install to complete β it's working fine |
| Gateway service not supported on android | No systemd in proot | Normal β expected, use tmux instead |
| Gateway already running / port in use | Previous gateway still alive | lsof -i :18789 β kill <PID> |
| nginx bind() failed (13: Permission denied) | Trying to bind port 80 β proot blocks ports below 1024 | rm /etc/nginx/sites-enabled/default |
| nginx bind() failed (98: Address already in use) | nginx already running from previous attempt | nginx -s reload instead of starting a new instance |
| control ui requires device identity | Accessing dashboard over HTTP from another device | Use nginx HTTPS proxy β access via https:// not http:// |
| origin not allowed | allowedOrigins not set or doesn't include your HTTPS address | openclaw config set gateway.controlUi.allowedOrigins '["https://IP:8443"]' |
| telegram plugin not available | Known wizard bug β Telegram is a channel, not a plugin | Skip in wizard, configure manually in openclaw.json |
| sessions should be nested with care | Already inside a tmux session | unset TMUX && tmux attach -t openclaw |
| NordVPN: couldn't find nordvpnd.sock | Trying to run NordVPN inside Ubuntu proot | Use the NordVPN Android app β not the terminal installer |
| Skills failing to install (brew, go) | Homebrew and Go not available on Android | Normal β core skills install fine, ignore brew/go failures |
| unknown requestId when approving pairing | Request expired when gateway restarted | Visit dashboard URL β immediately run devices list β approve quickly |
| scrcpy paste truncated / cuts off | Command too long for scrcpy injection buffer | Paste one line at a time, or type multi-line configs in nano directly |
Quick Commands
Daily startup sequence
# Enter Ubuntu proot-distro login ubuntu # Reattach to running gateway tmux attach -t openclaw # If gateway died, restart it tmux new -s openclaw openclaw gateway --verbose # Detach and leave it running # Ctrl+B, D
Config management
# View full config cat ~/.openclaw/openclaw.json # Get a specific value openclaw config get gateway.auth.token # Set a value (detach from tmux first) openclaw config set gateway.controlUi.allowInsecureAuth true # Check what port the gateway is on openclaw config get gateway.port
Killing gateway cleanly
# Find running gateway lsof -i :18789 # Kill by PID kill <PID> # Or kill by process name pkill -f "openclaw gateway"
nginx management
# Reload config (use this after editing nginx config) nginx -s reload # Test config before applying nginx -t # Start fresh (only if nginx isn't running) nginx
Dashboard URL format
# Via Meshnet HTTPS (from another device) https://YOUR_MESHNET_IP:8443/#token=YOUR_TOKEN # Locally on the same phone (no HTTPS needed) http://localhost:18789/#token=YOUR_TOKEN # Chat endpoint (alternative to full dashboard) https://YOUR_MESHNET_IP:8443/chat?session=main
scrcpy launch commands (PC)
# Single device scrcpy.exe --prefer-text # Specific device by serial scrcpy.exe -s YOUR_DEVICE_SERIAL --prefer-text # Find device serials adb devices # Once scrcpy window is open, to paste from PC clipboard: # Press Alt + Shift + V