# iOS App Store Self-hosted iOS OTA app distribution server. Build with your dev/distribution certs, host the IPAs, install on registered devices over the air — no Xcode tether, no TestFlight. ## Features - Web UI for browsing and installing apps (mobile-friendly, dark theme) - Drag-and-drop IPA upload with automatic metadata + icon extraction - CLI/API uploads with token auth - Automatic manifest plist generation for `itms-services://` installs - Multiple builds per app, version history, release notes - Password-protected web UI, token-protected API ## Requirements - iOS device UDID registered in the provisioning profile embedded in the IPA - IPA exported with `method: ad-hoc` (development-signed IPAs cannot be installed OTA) - Server reachable over HTTPS with a trusted certificate ## Stack Node.js + Express + SQLite + Docker. Sharp for icon resizing. No client framework — vanilla HTML/CSS/JS. ## Endpoints | Method | Path | Auth | Description | |--------|------|------|-------------| | `GET` | `/` | session | App listing | | `GET` | `/upload` | session | Upload page | | `POST` | `/api/upload` | token or session | Upload IPA | | `GET` | `/api/apps` | token or session | List apps + latest build | | `GET` | `/api/apps/:id` | token or session | App detail with all builds | | `DELETE` | `/api/apps/:id` | token or session | Delete app + all builds | | `DELETE` | `/api/builds/:id` | token or session | Delete a single build | | `GET` | `/api/manifest/:buildId` | public | Plist manifest for OTA install | | `GET` | `/api/download/:buildId` | public | Download IPA file | | `GET` | `/api/health` | public | Health check | The manifest and download endpoints are intentionally public — iOS fetches them unauthenticated during install. ## CLI Upload ```bash curl -X POST https://appstore.example.com/api/upload \ -H "X-Api-Token: $API_TOKEN" \ -F "ipa=@path/to/YourApp.ipa" \ -F "notes=Build notes" ``` Response includes the install URL (`itms-services://...`) ready to open in Safari on the device. ## Configuration Copy `.env.example` to `.env` and set: | Variable | Description | |----------|-------------| | `ADMIN_PASSWORD` | Web UI login password | | `API_TOKEN` | Token for CLI/automation uploads | | `SESSION_SECRET` | Express session secret | | `BASE_URL` | Public HTTPS URL of the server | | `PORT` | Listen port (default `3000`) | ## Deployment Runs as a single Docker container. The `/data` volume holds the SQLite DB, uploaded IPAs, and extracted icons. ```bash docker compose up -d --build ``` Put a reverse proxy with HTTPS in front of it. iOS requires a trusted SSL certificate for OTA installs to work. ## Project Layout ``` src/ server.js Express app, routes, middleware db.js SQLite schema ipa-parser.js Extracts Info.plist + icon from IPA manifest.js Generates OTA manifest plist auth.js Session + token auth middleware public/ Static assets (CSS, JS) views/ HTML pages ```