# Server and App Manager

App Manager gives your devices a shared home for app installation, updates, and signature refreshes. Signing and installation happen on your Mac.

## Run the server

```sh
ipa-hub serve
ipa-hub serve --port 19464 --host 0.0.0.0
```

Opening the server redirects to the manager hosted on GitHub Pages, with your Mac’s address in the URL. Open `http://localhost:19464` on the Mac for direct administration. Other devices require a personal App Manager installation link from the CLI or an admin's installation sheet; opening the server address alone does not authorize them. Keep the Mac awake and the device reachable for installation.

## Install the background service

```sh
npm i -g ipa-hub && ipa-hub service install --setup-manager
ipa-hub service status
ipa-hub service stop
ipa-hub service start
```

Service installation is available only after a global npm or Bun install, not from temporary npx/bunx installations. It starts immediately and at user login. `service uninstall` removes the LaunchAgent while retaining app records and downloads. Logs are in `~/.ipa-hub/server/stdout.log` and `stderr.log`.

`--setup-manager` presents your available compatible devices. Use ↑/↓ to navigate and Enter to select, or choose **Skip App Manager installation** at the end. This step requires an interactive terminal, even when only one device is available. After setup, the CLI prints the command for adding another device.

With a globally installed CLI, `ipa-hub install gh:utmapp/UTM --setup-manager` first selects the device, ensures the service is installed and running, and installs the app through it. It then sets up **App Manager** on that same device, opening its personal link by default. Use `--open` to open the installed app instead; `--no-open` leaves the installed app closed while opening the manager. Independent installs (`--bypass-server`) and simulators cannot use manager setup. A temporary npx/bunx CLI can reuse an existing server or start an already installed service but cannot install a service itself.

## Set up App Manager

```sh
ipa-hub service manager install -n "My iPhone"
ipa-hub service manager install --make-admin
```

The server must be running. If the service is installed, the command starts it when needed. Safari opens the personal setup link unless `--no-open` is supplied. Choose **Share → Add to Home Screen**, keep **Open as Web App** enabled if shown, and tap **Add**. Open **ipa-hub** from its Home Screen icon to finish setup.

The CLI stays open during setup. It waits for the visible Safari page to connect, shows the Home Screen instructions, then confirms success with a green checkmark when you open the installed app. Press **O** to reopen Safari on the selected device, or **Esc** to cancel. If Safari cannot open, unlock the device and press **O** to retry. Closing the CLI before confirmation cancels setup and invalidates the unfinished installation. `--no-open` displays the personal link and waits without opening Safari automatically; `--json` prints its result only after setup finishes.

On iOS, iPadOS and identified visionOS devices, a regular browser visit shows installation instructions instead of the manager. The generated manifest keeps the personal link's full fragment in its launch URL, including the server addresses, certificate pin and device credentials. Setup therefore does not depend on Safari and the installed app sharing browser storage. On visionOS versions without **Add to Home Screen**, use your Mac or another admin device to manage that device.

In App Manager's **Devices** screen, **Install manager** opens Safari on the selected device and follows its progress in the **App Manager installation** sheet. Keep that sheet open until the green success checkmark appears. Closing it early asks you to confirm cancellation; closing the browser or losing its server connection also cancels unfinished setup.

Remote access to App Manager requires a paired device and its installation key. Devices with admin access can manage other paired devices. Treat the setup link as private until installation finishes.

The link contains a temporary key limited to setup requests. On its first Home Screen launch, the PWA receives a replacement private key through the encrypted connection, saves it in `localStorage`, and reconnects to confirm possession. The server then saves only the replacement public key in the device's `install.json`. The original URL key becomes invalid when replaced, so sharing the link left in Safari cannot authorize another installation afterward. Opening the setup page in Safari does not replace the key.

If setup is cancelled, the server restarts before it finishes, or the PWA cannot save its replacement key, install App Manager again. Clearing the installed PWA's storage also requires reinstalling it; the old URL cannot recover its key.

Library consumers must keep their instance alive until setup completes:

```ts
import {getIpaHub} from "ipa-hub";

await using hub = await getIpaHub();
const manager = await hub.installManager({device: {name: "My iPhone"}});
await hub.waitForManagerInstallation(manager);
```

Disposing the instance or aborting the installation signal cancels unfinished setup.

## Install and manage apps

The manager opens on your device’s apps. Admins can use **Devices** in the toolbar to choose another paired device; other managers only see their own device. **Settings** includes alternative server addresses and **Show specific provisioning profiles**. Signing choices show only unrestricted `*` profiles by default; enabling this saved preference also shows compatible app-specific and prefix-scoped profiles.

Opening a device’s app list, including returning to App Manager from the background, checks which apps are still installed. Apps confirmed missing are removed from ipa-hub’s registry along with their retained IPA, icon, saved access token, and global update link. Unavailable devices and failed inventory queries never trigger removal. Checks wait for any installation in progress to finish.

Paste a repository, release URL, IPA URL, or `ipa-hub install` command into the input. The preview shows its source, release, IPA filenames and sizes. Release history loads when you open the release selector. A single IPA is selected automatically; choose a file when there are several. The filter button reveals a filename filter and highlights when one is active, including filters from pasted commands. If several signing teams are available, the most recently used team is preselected. Publisher release notes expand below the install button and support GitHub-flavored Markdown.

**Install app** always asks you to confirm that you trust the publisher. Apps are checked for updates when the device screen opens. Use **Check for updates**, **Update everything**, or an app’s **Download update** button. Each app shows its installed version, release date when available, and signature expiration. Its **•••** menu opens the source repository, release changelog, copyable installation command, signature refresh, or global update link. File sizes and release dates are shown as unavailable when the publisher does not expose them; existing records acquire release dates when reinstalled or updated.

Each installation keeps a local copy of the app’s icon alongside its retained IPA, refreshed on every update. App Manager loads these images through its authenticated WebRTC connection without an internet lookup. Apps without an extractable PNG icon show their initials.

Filename filters match text anywhere, ignoring case: `tv` and `*tv*` are equivalent. Use `advanced*tv` to match those text segments in order. A leading `^` or trailing `$` enables regex, such as `^UTM$`. Matching tries names without `.ipa` first, then full filenames if none match. [Filter Healing](?page=sources#filter-healing) repairs ambiguous update filters when the installed release or device compatibility identifies a unique candidate.

On **Devices**, hover a card to grant or revoke admin access. Touch devices expose these actions in **•••**. The tooltip explains that admins can manage all paired devices, enroll managers, and grant or revoke other devices’ admin access.

### Open an installed app

An **Open** button appears only when the selected device is the one authenticated by the manager’s enrollment key and matched by its current network address. Open ipa-hub from that device’s Home Screen and keep it visible and focused. Admin access does not permit launching apps on another device, and the Mac’s manager does not show this action.

The server issues a ten-second, single-use challenge bound to the encrypted connection and the tracked app. It checks the device’s current IP, pairing, key registration, and foreground confirmation before launching. The PWA checks visibility and focus before both requests and cancels if it loses focus. Foreground state is an authenticated assertion from the trusted webapp, not an independent iOS attestation; a compromised device or stolen enrollment key is outside this protection. If a VPN or network setup prevents a unique IP match, Open is unavailable while other authenticated management can still work.

## Move an app list to another device

**Export apps list** saves `ipa-hub-apps.json`. It contains source URLs, selected releases and filenames, and filters, without access tokens, device keys, signing profiles, or update links. On the destination device, choose **Import apps list**, review the selected apps, and confirm installation. They install sequentially with progress; one failure does not prevent the remaining selected apps from installing.

Imports accept up to 100 remote sources in a JSON file smaller than 1 MiB. Local file paths cannot be transferred through the manager: replace them with a repository or hosted IPA URL. Private sources require a new token on the destination Mac; install those individually with `--access-token`. Exported release versions are pinned so recipients receive the same release.

## Global update links

An app’s **••• → Get global update URL** issues a private link granting update access to that app on that device. Opening it checks for an update. Add `?install` to install an available update in the background, or `?install=foreground` to wait and stream progress. A newly issued link can be used from an unpaired machine without granting general device-management access. Treat it as a credential; older links retain their previous caller restrictions until you issue a new one from the menu.

For a step-by-step example, see [Remote coding agents](?page=remote-agents): install an agent's hosted IPA once, then let the agent publish new builds and trigger updates on demand. See the [update endpoint contract](?page=app-updates#global-update-links) for request and response details.

## Network connections

HTTP and WebRTC API handlers use the same runtime schemas. JSON fields keep their declared types: for example, a boolean must be `true` or `false`, not a string, and a release page must be a positive integer. The server bounds request sizes and field lengths, rejects unsafe object keys and duplicate query parameters, and strips undeclared properties.

Invalid requests return HTTP 400 with a field path, without echoing submitted values or tokens. JSON responses and streamed progress are also validated before transmission; invalid JSON outputs return 500, while an invalid installation result is reported as a stream error. Malformed WebRTC protocol messages close the affected connection without stopping the server.

These schemas and transport contracts are internal implementation details. Library consumers use [`getIpaHub`](?page=api/functions/getIpaHub) and its typed instance methods; the library handles server communication and progress events.

The manager uses WebRTC Direct over UDP on the same numeric port as the HTTP server. Its personal URL contains a fragment such as `#server=Mac.local:19464;192.168.1.10:19464;[fd00::1]:19464&h=<certificate-fingerprint>`, plus a unique device credential. URL fragments are not sent to the Pages host. The browser checks the pinned DTLS certificate before sending application data, then proves possession of the device's private installation key. The Mac checks the matching public key in `devices/<device-id>/install.json` and applies that device's permissions.

Direct host administration requires a loopback socket source (`127.0.0.1` or `::1`) and a private credential supplied by the local HTTP redirect. That temporary credential has a one-minute setup window. Within it, the browser automatically saves and confirms a replacement key without requiring a CLI guide or Home Screen installation. Its public key is stored in `server/manager.json`; the replacement remains restricted to loopback connections. An expired setup requires opening the server's localhost address again. This exception never applies to remote devices, including paired iPhones, iPads and Apple Vision Pro.

A website that merely connects to localhost cannot become an administrator. HTTP management APIs require the CLI's private token; browsers use their authenticated WebRTC connection. Host headers and browser origins are checked, and forwarded-IP headers never establish local access. Local processes on the Mac, enrolled admins, and the hosted webapp remain trusted. Keep setup links private until consumed; JavaScript running on the webapp's origin can access credentials in `localStorage`.

The certificate is generated on first use, expires after 1000 years and is reused across restarts. It lives with its private key in `server/webrtc.json`. The signed application handshake also uses `server/key.json`. Back up both files; replacing either identity requires new enrollment links. Existing enrollments from the WebSocket version also need a fresh link with the DTLS fingerprint.

No local HTTPS server or trusted HTTPS certificate setup is needed. Allow incoming TCP and UDP on the server port (19464 by default), and grant browser local-network access when prompted. WebRTC needs a reachable UDP path; ipa-hub does not use a TURN relay or fall back to unverified HTTP APIs.

## Offline and alternative addresses

Once cached, the manager opens offline and reconnects automatically. Edit alternative server addresses in **Settings**; changes save automatically. Authenticated connections also learn the Mac’s available IPv4, IPv6, and Tailscale addresses. Tap the computer icon in the header to see these addresses and the active connection. The manager tries every known address in parallel and uses the first one to prove the pinned server identity. Each round has a 30-second timeout; the next starts at least five seconds after the previous round began.

Documentation requires a connection. Search runs in your browser using FlexSearch; it does not submit queries to a server.

## Troubleshooting

For an unauthorized-device message, open **Device Hub** on your Mac (installed with Xcode), choose **File → Pair Nearby Device...** from the macOS menu bar at the top of the screen, and follow the pairing prompts. Then open the device’s personal enrollment link. If the server key changed, restore `server/key.json` and `server/webrtc.json` from backup or enroll the manager again. Never accept an unfamiliar server key just because an address matches.

Native app update URLs remain separate HTTP endpoints. They retain paired-device authorization and do not use the manager’s encrypted channel. See [in-app updates](?page=app-updates).
