Files
AppStore/README.md
2026-04-11 11:41:37 -05:00

2.9 KiB

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

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.

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