RemoteDeploy

RemoteDeploy: An iPhone Install in Ten Seconds

3 min read Updated July 23, 2026

iOS deployment is broken in a specific, annoying way. RemoteDeploy is a macOS menu-bar app that builds, signs, and serves iOS apps over your Tailscale network, so any iPhone installs a fresh build from Safari in about ten seconds - from anywhere.

The Problem

Getting a fresh build onto a physical iPhone is slow. TestFlight runs 15 to 30 minutes per upload, USB means physically holding the device, and Xcode wireless debugging needs both machines on the same network. I wanted a build on my phone in seconds, from anywhere.

What I Built

An open-source (MIT) macOS menu-bar app - no dock icon, no main window - that wraps xcodebuild to archive and export with ad-hoc signing, then serves the IPA over HTTPS using SwiftNIO.

I opened the repo on March 30, 2026 not with code but with a 697-line spec written as an agent prompt: architecture decisions up front, a list of commandments that read like scar tissue from past projects. The whole app materialized against that spec in a single day across about thirty commits, and went open-source the next day with a README, an app icon, and a signed DMG.

Four days after launch, v2.0 added an iOS companion app, a 20-endpoint REST API, and a progressive web app, with QR-code pairing and Bonjour discovery. From there it grew ticket by ticket: live build-log streaming over WebSocket, Expo and React Native support behind a BuildEngineRouter abstraction, macOS self-deploy (RemoteDeploy deploys itself - quits the running binary, swaps the bundle, relaunches via a trampoline script), auto-renewing Tailscale TLS certificates, push notifications through Prowl, Pushover, or ntfy, and IPA import for pre-built binaries.

Tech Stack

Languages
  • Swift
  • TypeScript (Copilot Auto-Keep)
Runtime & frameworks
  • SwiftUI
  • SwiftNIO
Infra & deploy
  • Tailscale (secure tunnel + TLS)
  • Bonjour / mDNS
  • LaunchAgent auto-start
Notable libraries
  • NIOSSL
  • XcodeGen
  • Swift Package Manager
  • os.Logger
  • VS Code Extension API

How It Works

Every major component is a Swift protocol with a concrete implementation - BuildEngineProtocol, DeployServerProtocol, TailscaleProviderProtocol, CertificateProviding, and about eight more - so the codebase is testable and extensible without touching existing code. It ships as four targets: the menu-bar host, a headless SwiftNIO server in its own process, the iOS companion, and a shared Swift package for models and API types.

RemoteDeploy: one signed IPA, two paths in Two inputs feed the menu-bar host: xcodebuild, which archives and exports a project with ad-hoc signing to produce the IPA, and Tailscale, which supplies a secure tunnel and an auto-renewing valid TLS certificate. The menu-bar host itself has no dock icon and no main window; every major piece of it is a Swift protocol with a concrete implementation, including BuildEngineProtocol which wraps xcodebuild, DeployServerProtocol which is the SwiftNIO IPA server, TailscaleProviderProtocol, and CertificateProviding, plus about eight more. From the host, two independent paths fan out: an iPhone installs the signed IPA straight from a Safari URL over HTTPS in about ten seconds, and an iOS companion app together with a progressive web app drive and monitor builds through a twenty-endpoint REST API plus a WebSocket for live build-log streaming, authenticated by a bearer token stored in the iOS Keychain and hashed with SHA-256 on the server, so the raw token never touches disk on the Mac. The whole system ships as four targets: the menu-bar host, a headless SwiftNIO server split into its own process, the iOS companion app, and a shared Swift package for models and API types. RemoteDeploy one signed IPA, two paths in xcodebuild archive + export, ad-hoc signing produces the IPA Tailscale secure tunnel to the tailnet auto-renewing valid TLS certificate Menu-Bar Host (macOS) - no dock icon BuildEngineProtocol - wraps xcodebuild DeployServerProtocol - SwiftNIO IPA server TailscaleProviderProtocol + CertificateProviding + about eight more - every major piece is a protocol iPhone - OTA install Safari URL -> installed in ~10s signed IPA served over HTTPS iOS Companion + PWA REST API (20 endpoints) + WebSocket live logs bearer token: Keychain, SHA-256 hashed server-side four targets: menu-bar host · headless SwiftNIO server · iOS companion · RemoteDeployShared
Two inputs - the build toolchain and the Tailscale tunnel - narrow into one protocol-oriented host, which fans back out to an iPhone installing over the air and a companion app driving builds through an authenticated API.

The REST API covers the full surface: project CRUD, build trigger and cancel, build and install history, settings, filesystem browsing for project discovery, device pairing and revocation, plus the WebSocket for real-time logs. Auth is bearer tokens stored in the iOS Keychain and hashed with SHA-256 server-side, so the raw token never touches disk on the Mac. A deploy.sh installer builds the release .app, installs to /Applications, and configures a LaunchAgent for auto-start and crash recovery, with no runtime dependency on Xcode or the source tree.

Also in the dev-tooling bucket: Copilot Auto-Keep, a VS Code extension that auto-accepts Copilot agent edits by watching for workspace edit bursts and firing Keep All after a debounce. Same instinct - if the machine can handle it, don’t make me click.

What Made It Hard

Signing and serving an installable IPA correctly, over the air. Streaming build logs live over WebSocket to the phone and the PWA. And keeping the design clean as the surface grew - the protocol-oriented Swift 6 architecture is what let v2.0 bolt on a companion app, a full API, and self-deploy without rewrites.

The Throughline

RemoteDeploy is what happens when I hit a friction point and build through it rather than around it. Write a spec sharp enough to build from, ship it in a day, harden it in public - the same pattern behind Rejog Stash, whose native iOS build is exactly the kind of app this exists to get onto a phone in ten seconds.

Status

Shipped and open-source, still maintained. The repo sits at roughly 330 commits and 217 Swift files across four targets. It went MIT the day after launch; I wrote up the release in I released my first open-source Mac app today, and the living day-one spec is still updated as decisions get made. Code at github.com/danrichardson/mac-remote-deploy.