Skip to content
 
 

Repository files navigation

Claude Code on Android

The real Claude Code, running on an unrooted phone. No PC, no root, no paid plan.

Termux → proot-Ubuntu → Claude Code, with free model access through a local 9Router proxy.

Android 8+ No root Cost Arch Disk


Claude Code running in a Termux session on an Android phone, showing the welcome panel with the claude-opus-free model and a reply to 'hi what you can do for me?'

A real session — Claude Code in Termux on an unrooted phone, answering through a free claude-opus-free combo.


▶️ Full step-by-step setup video: youtu.be/DUBBbO6FzOo

The chapters in this repo match the chapters on screen. New here? Watch the video first, then use this page as the copy-paste reference.

Note

Verified 2026-07-26 on an unrooted aarch64 Android phone. Free provider tiers change often. If a step breaks: free-api-options.md, then troubleshooting.md.


Contents

How the pieces fit The one thing to understand before you start
What you need Requirements, and the Termux build that actually works
Quick start setup.sh — Chapters 1–3, unattended
After setup.sh finishes The manual half, as a copy-paste list
Full walkthrough Chapters 1–6, every command explained
Daily use The two-session routine
Useful commands Cheat sheet, split by which shell it runs in
Why proot-Ubuntu And why the easier-looking path breaks
Honest limits What this setup is bad at

How the pieces fit

Termux
├── session 1:  9router                      → listens on 127.0.0.1:20128
└── session 2:  proot-distro login ubuntu
                └── Ubuntu ── claude         → talks to 127.0.0.1:20128

9Router runs in Termux. Claude Code runs inside Ubuntu. proot doesn't isolate the network, so 127.0.0.1 inside Ubuntu still reaches the proxy running in Termux.

Always know which shell you're in. Most problems in this stack are the right command in the wrong environment:

Prompt You're in What lives here
~ $ Termux 9router, node, proot-distro
root@localhost:~# Ubuntu claude, ~/.claude/settings.json

Important

Ubuntu has its own home directory. ~/.claude/settings.json has to be created inside Ubuntu — a copy in Termux's home is silently ignored, with no error.

Node.js is needed in Termux (for 9Router), not in Ubuntu.


What you need

Phone Any Android 8+, not rooted
CPU aarch64 — check with uname -m
RAM 4GB or more
Storage ~5GB free (Ubuntu alone is ~2GB)
App Termux from F-Droid or GitHub Releases
Not needed A PC, a paid Claude plan, root

Warning

Don't use the Play Store build of Termux. It's an experimental branch the Termux maintainers recommend against, and it's the single most common cause of "nothing works." Uninstall it and install from F-Droid or GitHub Releases.


Quick start (scripted)

setup.sh does Chapters 1–3 — Termux packages, Ubuntu, Claude Code — unattended:

curl -fsSL https://raw.githubusercontent.com/iAmAjayTeli/claude-code-android/main/setup.sh -o setup.sh
cat setup.sh          # read it before you run it
bash setup.sh

Tested on a clean run: freshly wiped Termux → working claude inside Ubuntu, no manual fixes needed. Safe to re-run too — completed steps are detected and skipped.

What the script actually does, step by step

No surprises — this is everything it touches, in order:

Before installing anything, it checks:

Check If it fails
Running inside Termux Stops — this isn't a script for a PC
CPU is aarch64 Stops — Claude Code has no 32-bit build, no workaround
~5GB free storage Asks before continuing — Ubuntu unpacks before cleanup
A leftover Path A claude in Termux Warns only — it doesn't touch or delete it
Internet reachable Stops with a clear message — so it never downloads for minutes then fails on no connection

Step 1 — Termux packages. pkg update && pkg upgrade, then installs proot-distro (runs the Ubuntu container) and nodejs (only needed later, for 9Router). Fully non-interactive — keeps existing configs instead of pausing on a prompt. Each pkg operation retries up to 3× on a transient failure.

Step 2 — Ubuntu. proot-distro install ubuntu — a ~2GB download from the official proot-distro mirrors, retried up to 3×. If a previous run left a half-finished container (no /bin/bash inside), it's removed before starting fresh, so a dropped download can't leave a broken install that gets skipped as "already installed."

Step 3 — Claude Code, inside Ubuntu. Runs apt update && apt upgrade non-interactively (keeping existing configs, so it can't hang on a prompt), installs curl git wget build-essential, then downloads Anthropic's official installer from claude.ai/install.sh — to a file first, checked as non-empty, then run, with curl set to retry 5× on any transient error, so a failed download can't silently execute nothing. apt failures (e.g. Hash Sum mismatch from a stale mirror) are retried up to 3× after clearing the package index. Adds ~/.local/bin to PATH in Ubuntu's .bashrc and verifies with claude --version.

What it deliberately does NOT do:

  • No 9Router install, no API keys, no settings.json — those need your accounts and a browser, so they stay manual and the script prints them as next steps
  • Never asks for root, never runs su
  • Deletes nothing — not even a leftover Path A install
  • Sends nothing anywhere — the only network traffic is the package downloads above

The whole thing is ~230 lines of commented bash. cat setup.sh before running it — that's why the download step is separate.

It stops after Chapter 3 on purpose. Chapters 4–6 (9Router, providers, combos, settings.json) need your own API keys and a browser, so the script prints them as next steps instead of guessing.

Tip

Do it manually the first time anyway. When something breaks later — and on free tiers it will — you'll know which piece to look at.


After setup.sh finishes

The script leaves you with a working claude inside Ubuntu that isn't pointed at anything yet. Six steps left. They're the same as Chapters 4–6 below, collected here in order so you can work straight down the list.

1. Confirm the install, in Termux — prompt ~ $

proot-distro login ubuntu -- /root/.local/bin/claude --version

Prints a version and drops you back in Termux. Call the binary by its full path here: a non-interactive login (bash -lc 'claude ...') doesn't pick up the PATH line in .bashrc, so a bare claude would report "command not found" even though the install is fine. If the version check itself fails, stop here — troubleshooting.md.

2. Start 9Router, in Termux

npm install -g 9router
9router

Leave this session running. Close it and Claude Code loses its endpoint.

3. Set up the dashboard, in your phone's browser

Open http://localhost:20128 — password 123456.

  • Change that password first. It's a published default.
  • Add your free providers.
  • Create a combo, priority-ordered, named exactly claude-opus-free.

Ordering logic is in free-api-options.md. Ignore the dashboard's "CLI Tools → Claude Code" page entirely — see the note in Chapter 5.

4. Open a second Termux session and enter Ubuntu

Swipe from the left edgeNew session, then:

proot-distro login ubuntu

Prompt becomes root@localhost:~#. Everything below runs here.

5. Write the config, inside Ubuntu

mkdir -p ~/.claude
nano ~/.claude/settings.json

Paste the JSON from Chapter 6, then Ctrl+O, Enter, Ctrl+X.

Important

This has to be Ubuntu's home, not Termux's. A settings.json in Termux's ~ is silently ignored.

6. Check it, then run it — inside Ubuntu

cat ~/.claude/settings.json                                          # right file, valid JSON?
curl -s http://127.0.0.1:20128/ -o /dev/null -w '%{http_code}\n'     # any HTTP code = proxy reachable
claude

Watch the 9Router session while you send your first message. A line like ▶ POST claude-opus-free → provider/model means the whole chain works. Nothing at all means the combo name doesn't match the dashboard.

Every session after this — two Termux sessions, 9router in one, proot-distro login ubuntuclaude in the other. Full list of commands worth knowing: Useful commands.


Full walkthrough

Chapter 1 — Prepare Termux

Runs in Termux — prompt ~ $

pkg update && pkg upgrade -y
pkg install proot-distro nodejs -y

Press y if prompted about package maintainer configurations.

proot-distro runs the Ubuntu container. nodejs is for 9Router, which stays on the Termux side.

uname -m        # must print aarch64
node -v         # confirms Node is ready for 9Router

Chapter 2 — Install Ubuntu

Runs in Termux

proot-distro install ubuntu

2–5 minutes depending on connection speed. Then log in:

proot-distro login ubuntu

The prompt changes from ~ $ to something like root@localhost:~#. You are now inside Ubuntu. Everything in Chapter 3 runs here.

Leave Ubuntu with exit. Get back in with proot-distro login ubuntu.

Chapter 3 — Install Claude Code

Runs inside Ubuntu — prompt root@localhost:~#

apt update && apt upgrade -y
apt install -y curl git wget build-essential

Then Anthropic's official installer:

curl -fsSL https://claude.ai/install.sh | bash
echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.bashrc && source ~/.bashrc
claude --version

That's the real installer from Anthropic — no patching, no community shim. It installs a standalone binary, which is why you don't need Node.js inside Ubuntu.

Tip

Skip the nodesource step some guides put here. curl -fsSL https://nodesource.com | bash - is not a setup script — nodesource.com is just a website, so that command pipes a web page into bash and accomplishes nothing. If you want Node for your own projects, use NodeSource's actual instructions.

Chapter 4 — Install 9Router

Back in Termux — prompt ~ $

9Router gives you one local endpoint that fans out to several free providers, falling through to the next one when one runs dry.

Leave Ubuntu (exit), or open a fresh Termux session — swipe from the left edge → New session:

npm install -g 9router
9router

The proxy starts on http://localhost:20128. Leave this session running. Close it and the proxy dies, and Claude Code stops working.

Chapter 5 — Configure providers and combos

Open http://localhost:20128 in your phone's browser. Default dashboard password: 123456

Caution

Change that password. It's a published default. Low risk while the proxy only listens on localhost on your own phone — a real problem the moment that port is reachable from another device. Change it before you join any shared or public network.

Add your free providers, then build a combo: a priority-ordered list of them. Name it claude-opus-free.

See free-api-options.md for ordering logic and why a second combo is worth making.

Note

Ignore the dashboard's "CLI Tools → Claude Code" page. It will say "Claude CLI not detected locally" — correctly, because 9Router runs in Termux and your claude is inside Ubuntu, where Termux can't see it. Your install is fine.

Don't use that page's install button either: it points at npm install -g @anthropic-ai/claude-code in Termux, which rebuilds the native Path A install this guide exists to avoid. Use the dashboard for providers and combos only, and write settings.json by hand in Chapter 6.

Chapter 6 — Point Claude Code at 9Router

Runs inside Ubuntu — in your other session

proot-distro login ubuntu
mkdir -p ~/.claude
nano ~/.claude/settings.json

Important

This has to be Ubuntu's home directory, not Termux's. Claude Code runs inside Ubuntu and only reads the config there. A settings.json sitting in Termux's ~ is silently ignored — no error, nothing works. Expect this to be the most common mistake for anyone following along.

Paste this, then Ctrl+O, Enter, Ctrl+X:

{
  "hasCompletedOnboarding": true,
  "env": {
    "ANTHROPIC_BASE_URL": "http://127.0.0.1:20128/v1",
    "ANTHROPIC_AUTH_TOKEN": "sk_9router",
    "ANTHROPIC_DEFAULT_FABLE_MODEL": "claude-opus-free",
    "ANTHROPIC_DEFAULT_OPUS_MODEL": "claude-opus-free",
    "ANTHROPIC_DEFAULT_SONNET_MODEL": "claude-opus-free",
    "ANTHROPIC_DEFAULT_HAIKU_MODEL": "claude-opus-free"
  }
}

Four things in there that matter:

127.0.0.1, not localhost localhost can resolve to IPv6 ::1 while 9Router listens on IPv4 only — connection refused for no obvious reason. Use the numeric address.
/v1 on the end Without it the API paths don't line up and every request fails.
hasCompletedOnboarding Skips Claude Code's login flow. You're authenticating against your own local proxy, so this is what stops it asking for a Claude account.
sk_9router The local proxy's own token, not a real Anthropic key. Nothing secret — safe in a public repo. If you set a custom token in the dashboard, use that instead.

Important

claude-opus-free is a 9Router combo name, not a model name. You create the combo in the dashboard; Claude Code just asks for claude-opus-free, and 9Router picks the first available provider in the list, falling through when one is rate-limited or down. Claude Code never knows.

So the name here has to match the dashboard exactly. That's the most common silent failure in this setup.

Then start it:

claude
Optional: a second combo for the Haiku tier

All four aliases above point at one combo, which works. But Claude Code fires a constant stream of small background calls at the Haiku tier — file reads, summaries, tool routing, context compaction — and comparatively few at Opus/Sonnet, though those few are the real work.

Point everything at one combo and the background noise burns through your best providers before you've built anything. Make a second combo ordered by limit generosity rather than model quality, and map only Haiku to it:

"ANTHROPIC_DEFAULT_HAIKU_MODEL": "claude-haiku-free"

Daily use

Two Termux sessions, swipe from the left edge to switch:

Session Command
1 9router leave it running
2 proot-distro login ubuntuclaude do your work here

See troubleshooting.md for keyboard setup, session persistence, and battery survival.


Useful commands

Everything you'll actually reach for, grouped by the shell it belongs in. Running one of these in the wrong shell is the most common reason something "doesn't work."

In Termux — prompt ~ $

Command What it does
pkg update && pkg upgrade -y Refresh package lists and upgrade everything installed
pkg install <name> -y Install a Termux package
uname -m Print CPU architecture — must say aarch64
df -h $HOME Check free storage before installing Ubuntu
termux-setup-storage Grant Termux access to phone storage, creates ~/storage
cd ~/storage/shared Jump to your phone's internal storage (Downloads, Documents…)
termux-reload-settings Apply changes to ~/.termux/termux.properties, e.g. the extra-keys row
command -v claude Check whether a leftover Path A claude is still on the Termux side
9router Start the proxy — leave this session running
pkill -f 9router Kill a stuck proxy when the port is already in use
proot-distro list List available and installed distros
proot-distro login ubuntu Enter Ubuntu — this is where Claude Code lives

In Ubuntu — prompt root@localhost:~#

Command What it does
apt update && apt upgrade -y Ubuntu's own package refresh — separate from pkg in Termux
apt install -y <name> Install an Ubuntu package
claude --version Confirm Claude Code is installed and on PATH
claude Start Claude Code
mkdir -p ~/.claude Create the config directory — in Ubuntu's home, not Termux's
nano ~/.claude/settings.json Edit the config that points Claude Code at 9Router
cat ~/.claude/settings.json Read the config back to confirm you edited the right one
ls -la ~/.local/bin/claude Check the binary actually exists when claude isn't found
source ~/.bashrc Reload PATH after adding ~/.local/bin to it
curl -s http://127.0.0.1:20128/ -o /dev/null -w '%{http_code}\n' Test that Ubuntu can reach 9Router in Termux — any HTTP code means yes
cd /data/data/com.termux/files/home Reach Termux's home from inside Ubuntu, for files you also open in an Android app
cd /sdcard/Download Jump to your phone's internal Download folder — the short path to shared storage
cd /data/data/com.termux/files/home/storage/downloads Same folder via Termux's storage symlink — works once termux-setup-storage has been run
cd /data/data/com.termux/files/home/storage/external-1 The SD card — Termux's writable app folder on it (Android 11+ blocks the rest of the card)
ls /storage List mounted volumes; an SD card shows up as XXXX-XXXX — its root is /storage/XXXX-XXXX
exit Back out to Termux

Deploying from the phone — in Ubuntu

Command What it does
git config --global user.name "<name>" Set the name on your commits, once per install
git config --global user.email "<email>" Same for email
git clone https://github.com/<user>/<repo>.git Pull a repo down onto the phone
git add -A Stage everything you and Claude Code changed
git commit -m "<message>" Commit the staged changes
git push Push to GitHub — use a personal access token as the password, not your account password

Inside a Claude Code session

/help List every available command — start here
/clear Wipe the conversation and start fresh
/compact Summarise a long conversation to free up context
/model Switch which model tier gets used
/status Show the current config, including which base URL it's talking to
Esc Interrupt Claude mid-response
/exit Quit back to the shell

nano, for anyone who hasn't used it

Ctrl+O then Enter Save
Ctrl+X Exit
Ctrl+K Cut the current line — useful for clearing a bad config

Tip

Swipe from the left edge of Termux for the session drawer, then New session. That's how you run 9Router and Claude Code at the same time.

Starting over

Warning

proot-distro remove ubuntu deletes the container and everything inside it — Claude Code, your settings.json, and any project files you created in there. Only use it on an install that never worked.

proot-distro remove ubuntu     # destroys the container
proot-distro install ubuntu    # fresh one, then re-run Chapter 3

Why proot-Ubuntu, and not the native install

There are two ways to get Claude Code onto Android. The simpler-looking one is the one that breaks.

Native Termux (Path A) proot-Ubuntu (Path B) — this repo
How it works Patches Anthropic's linux-arm64 binary to run against Termux's glibc-runner Real Ubuntu userland inside Termux, running Anthropic's own installer
Disk ~230MB ~2GB
Setup time 5–10 min 10–15 min
When it goes wrong Sandbox errors, EACCES on file writes, hangs Behaves like ordinary Linux
Pick it when You're tight on storage Default

Anthropic ships Claude Code as a glibc-linked binary with no Android build, and Termux runs on Android's Bionic libc. Path A is a shim over that gap, so the filesystem and process.platform don't behave the way Claude Code expects. Path B removes the gap: as far as Claude Code can tell, it is ordinary Linux.

The maintainer of the Path A installer recommends the same:

"Native Termux (Path A) works and is great for those who need it, especially with hardware or storage limitations. I highly recommend running it in proot-Ubuntu (Path B) though: it is the most native way I could get it running since the 2.1.112 regression."

ferrumclaudepilgrim/claude-code-android

Choose Path A only if you're tight on storage, or on Android 8/10 where the native binary trips Android's seccomp filter anyway.


Honest limits

  • Ubuntu costs ~2GB of storage. That's the price of the version that actually works.
  • proot adds syscall-translation overhead. Noticeable on older devices, not prohibitive.
  • Free provider tiers have rate limits. 9Router's fallback softens this, it doesn't remove it.
  • Long agentic tasks drain battery fast. Stay plugged in for heavy work.
  • Big repos are slow on phone hardware. This shines for small-to-medium projects.
  • Anthropic's official mobile path (Claude Code Remote Control) needs a PC running and a Pro/Max plan. This setup needs neither — that's the whole point.

What's in this repo

File
setup.sh Automates Chapters 1–3. Idempotent, no 9Router.
free-api-options.md Providers, combo ordering, and why two combos beat one
troubleshooting.md Failure modes, each tagged with the shell it happens in

Credits

Path comparison and the native-install alternative: ferrumclaudepilgrim/claude-code-android · Container: proot-distro · Proxy: 9Router

Hit an error that isn't documented? Open an issue — troubleshooting.md is meant to grow.

Licensed MIT.

About

Run Claude Code on an unrooted Android phone via Termux + proot-Ubuntu, with free model access through a local 9Router proxy.

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages