ios-linuxkit runs an AArch64 Linux userland inside an iOS app and as a command-line process on an AArch64 Linux host. It derives from iSH and uses iSH's userspace kernel, filesystems and Asbestos threaded-code interpreter.
Read the announcement: Announcing ios-linuxkit: Linux on iPad, the Hard Way.
I’m done waiting for Apple to fix things. And one of the things I think should exist is a decent way to run Linux binaries on my iPad.
An expensive iPad has hardware capable of far more than iOS allows: a cheap ARM board can run containers and virtual machines, while Apple keeps hypervisor access locked away. A POSIX shell, a package manager and local development tools should not require a jailbreak, a remote server or Apple's permission to use hardware you own.
The aim is to run shells, compilers, language runtimes and agent/CLI tools locally, with the workspace on the device—not through a UI proxied from somewhere else. The default interpreter works within iOS's restrictions without JIT, RWX memory or MAP_JIT; it trades native speed for a usable Linux environment.
This is a reusable runtime kit. The terminal is a reference shell; the runtime and reproducible Linux-host tests are there so other developers can build better tools. I have no plans to publish it on the App Store myself. The point is to keep it open, fixable and useful on our own devices.
The current source version is 2.5.2 with Apple build number 826. The repository supports one guest architecture: ARM64. The interpreter decodes guest instructions into programs of pointers to precompiled host functions. By default, all executable host instructions come from the built application; the interpreter allocates only data for translated programs. The optional native/ahead-of-time (AOT) backend is disabled by default. Linux recording builds may emit native code; AOT-only builds instead link pre-generated translations into the executable. The isolated iOS AOT bootstrap can explicitly enable checked static images; reference iOS schemes remain gadget-only.
- an ARM64 instruction decoder and AArch64 host gadgets under
asbestos/guest-arm64/; - a 48-bit guest address space, Linux syscall layer, signals, sockets and fakefs;
- the
iSH-ARM64iOS application target, xterm.js terminal frontend (with Ghostty Web also available) and aniSH-ARM64-ffmpegintegration target; - Linux-host builds for development and regression testing;
- staged tests for instructions, syscalls, language runtimes and command-line packages;
- startup-only cooperative offload APIs with guest VFS/token ownership and restricted TCP streams; no production cooperative handler registration.
The iOS app is a reference terminal and packaging target. The outer iOS sandbox is the security boundary; read SECURITY.md before embedding the runtime or exposing guest workloads to untrusted input.
Install Clang, Meson, Ninja, pkg-config, SQLite development files and libarchive development files. On Debian or Ubuntu:
sudo apt install \
clang make meson ninja-build pkg-config git curl file tar \
libsqlite3-dev libarchive-devClone the submodules and build:
git clone --recurse-submodules https://github.com/rcarmo/ios-linuxkit.git
cd ios-linuxkit
CC=clang make build-arm64-linuxRun against the host filesystem:
./build-arm64-linux/ish -r / /bin/echo helloTo create an Alpine fakefs, download the root filesystem named in app/GuestARM64.xcconfig, then import it:
curl -fLO https://dl-cdn.alpinelinux.org/alpine/v3.24/releases/aarch64/alpine-minirootfs-3.24.2-aarch64.tar.gz
echo '9bf70a7f18ea44094cbb5f70c58f9af129c8214745743db0e68e5502cc2ce773 alpine-minirootfs-3.24.2-aarch64.tar.gz' | sha256sum -c -
./build-arm64-linux/tools/fakefsify \
alpine-minirootfs-3.24.2-aarch64.tar.gz \
alpine-arm64-fakefs
./build-arm64-linux/ish -f ./alpine-arm64-fakefs /bin/shfakefsify is built when Meson finds libarchive. Existing build directories retain their original Meson configuration; remove or reconfigure them when changing the compiler or build type.
| Task | Command |
|---|---|
| Build release | CC=clang make build-arm64-linux |
| Build release and debug | CC=clang make build-arm64-linux-all |
| Check documentation links | make check-docs |
| Test AdvSIMD FP widening and narrowing | CC=clang make test-arm64-fcvt-vector |
Test /proc/<pid>/mem seek semantics |
CC=clang make test-arm64-proc-mem-seek |
| Test full-width seeks and Python sparse files | CC=clang make test-arm64-lseek-width |
| Test signal delivery to guest computation | CC=clang make test-arm64-poke-stress |
| Test precise load fault-PC and retry state | CC=clang make test-arm64-load64-fault-pc |
| Test full procfs/exit stress and lock/lookup regressions | CC=clang make test-arm64-proc-exit-race |
| Test imported correctness, lifetime and failure handling | CC=clang make test-arm64-upstream |
| Run staged runtime coverage | make test-arm64-runtime-coverage |
| Run coverage with the debug binary | make test-arm64-runtime-coverage-debug |
| Run CLI corner cases | make test-arm64-cli-corner-smoke |
| Run npm CLI coverage | make test-arm64-npm-cli-runtime-coverage |
| Measure Node and Bun | make test-arm64-node-bun-perf |
The runtime and CLI targets can install packages into their fakefs. Use a disposable copy when package state matters. Reports are written to REPORT_DIR, which defaults to /workspace/tmp.
Build AOT on Linux to record musl, BusyBox, Python and zlib, link an emission-disabled executable, test it and compare it with gadgets. Freeze and share artifacts for repeatable builds from retained guest bytes and recordings. Prepare iOS images after implementing the required Apple build and recovery hooks.
The tested local prototype improves short shell and zlib workloads by about 12–13%; Python takes about 15% longer and uses more memory. See the 29 September measurements. Package upgrades can invalidate images. Existing installed userlands are left unchanged; ordinary Meson and Xcode configurations keep the gadget engine.
2.5.2 adds Alpine's Go toolchain to accelerated builds and improves first-time compilation. xterm remains the default terminal, with Ghostty available as an alternative. The accelerated iPhone test build includes Bun 1.4.2; a reported iPhone crash remains under investigation.
The current AOT build also bundles Go from Alpine's pinned ARM64 APK and records the Go command, formatter, compiler, assembler, linker and vet tool. See the accelerated iOS build guide for packaging, build checks and CGo requirements.
Earlier source releases and dated audits are indexed under reports. Their measurements apply to the revisions, hosts and guests named in each report.
| Document | Use it for |
|---|---|
| Documentation index | Choosing the maintained guide or dated report. |
| Architecture | Interpreter, memory, kernel and host boundaries. |
| Linux development | Building, fakefs creation, command-line use and diagnostics. |
| iOS application | Xcode schemes, rootfs packaging and host integration. |
| Linux AOT | Recording, linking, running, testing and measuring local AOT. |
| Native offload | Legacy/cooperative contracts, guest VFS, bounded streams and output policy. |
| Route-netlink and Tailscale | Opt-in host interface discovery and isolated userspace networking tests. |
| AOT artifacts | Freezing, restoring, validating and publishing reusable inputs/builds. |
| iOS AOT | Target compatibility checks, Mach-O conversion and Apple integration. |
| Validation | Test checks, reports and failure rules. |
| Limitations | Security, compatibility and unsupported workloads. |
| Contributing | Change and documentation requirements. |
| Versioning and releases | App versions, build numbers, Git tags and release checks. |
Dated benchmark, workload, release and audit records live under docs/reports/. They preserve their original observations and are not current operating instructions.
ios-linuxkit contains work derived from ish-app/ish and its dependencies. See LICENSE.md, LICENSE.IOS, the preserved May 2026 README, and docs/legacy/.