The project's README from github.com/34306/vphone-web. As one markdown file: README.md.
I vibe code this repo so please if you had anything issue with AI then just skip it. (i vibed but still checking the function before sharing so it must be work fine)
A self-hosted web platform for running multiple virtual iPhones at once in the browser — user accounts + RBAC, per-user device assignment, live screen streaming (WebRTC with an MJPEG/WebSocket fallback), touch & hardware-key input, IPA/TIPA install, an in-browser root shell and a file browser, on top of the vphone-cli engine (Apple Virtualization.framework, PV=3 research VMs).
You need build the vphone-cli and create your own base VM locally, i did not included it here due to large files.
git clone --recursive https://github.com/34306/vphone-web.git
cd vphone-web
This also creates vendor/vphone-cli/ with the full engine + toolchain.
cd vendor/vphone-cli
make setup_tools # brew deps, build toolchain, create its Python venv
make build # build + sign the vphone-cli binary
make bundle # app bundle (bundles the IPA signing cert) — recommended
cd ../..
Each web VM is an instant copy-on-write clone of a base VM directory. Build one with vphone-cli's automated pipeline (downloads IPSW + cloudOS, restores, patches, installs CFW, first boot).
See vendor/vphone-cli/README.md for the full firmware matrix, supported iOS/cloudOS builds, variants (regular / dev / jb / exp), and how to resolve IPSW URLs. When it finishes, the base lives at vendor/vphone-cli/vm/ (contains Disk.img, nvram.bin, SEPStorage, config.plist, AVPBooter*.bin, .vphoned.signed).
Tip — one base per iOS version. Keep each version's base in its own folder (
vm/,vm-26.5/,vm-27/, …) and point the matchingVPHONE_BASE_VM*env var at it. The web only offers versions whoseDisk.imgactually exists.
Boot cleanly. Always Stop a VM from the web UI (or Ctrl-C the process) and let it finish shutting down before copying/promoting a base — a hard kill leaves the APFS volume dirty and the next boot does a slow fsck replay.
cp .env.example .env # then edit paths (see below)
make web_setup # create .venv, install web deps
make web_seed_admin USER=admin PASS='choose-a-strong-password'
make web_run # serves http://127.0.0.1:8080
Open http://127.0.0.1:8080, sign in as the admin, then:
.ipa/.tipa on the install zone to install.Admin-only logs dashboard live-tails every VM at /logs.
The server binds 127.0.0.1 only. To reach it from the internet without opening a port, use a Cloudflare Tunnel. You need a domain on Cloudflare.
brew install cloudflared
cloudflared tunnel login # authorize your domain (opens browser)
cloudflared tunnel create vphone # creates a tunnel + credentials json
cloudflared tunnel route dns vphone phone.example.com # your hostname
Create ~/.cloudflared/config.yml (replace the id + hostname with yours):
tunnel: <YOUR-TUNNEL-ID>
credentials-file: /Users/<you>/.cloudflared/<YOUR-TUNNEL-ID>.json
ingress:
- hostname: phone.example.com
service: http://localhost:8080
- service: http_status:404
Run it:
cloudflared tunnel run vphone
Notes:
logs.phone.example.com), set VPHONE_COOKIE_DOMAIN=.example.com in .env so the session cookie is shared.~/.cloudflared/*.json credentials or cert.pem.Run the web + tunnel automatically after a reboot/power-restore by creating two per-user LaunchAgents (~/Library/LaunchAgents/…) that RunAtLoad + KeepAlive: one execs make web_run (or uvicorn directly) from this repo, the other execs cloudflared tunnel run vphone. Web VMs need a GUI login session (WindowServer), so use a LaunchAgent (per-user), not a system LaunchDaemon; enable macOS Automatic Login for a fully unattended restore.
Built on vphone-cli by Lakr233. This repo adds the web platform layer on top.