# Self-hosting

A live project runs two reference services: a resolver and an effects runner. You run both on
infrastructure you own. The resolver holds no signing key.

## The resolver

The resolver re-indexes the chain's [event logs](../protocol/event-spine.md) into a local projection
and serves the token API. It is read-only. Its endpoints include:

- `GET /t/{chainId}/{address}/{tokenId}`: ERC-721 token metadata, and `.../image` for the image.
- `GET /c/{chainId}/{address}`: ERC-7572 collection metadata.
- `GET /api/project/{address}`: the full reconstructed project state, including `abx_provenance`.
- `GET /d/{chainId}/{address}`: a per-contract dashboard.
- `GET /health`.

Run it locally with `abx serve`. This also runs a chain watcher that polls for new logs, about every
12 seconds, and re-indexes each registered project. Deploy it to a host with
`abx deploy-resolver --provider <fly | render | vps>`, which writes a self-contained deployment
artifact for that target. The production image installs `@artblocks/abx-cli` from npm and runs without
a browser.

Because a resolver re-indexes from the chain, moving to a new host is a configuration change. See
[migrating](#migrating).

## The effects runner

A code project's still image is rendered off-chain, so the resolver image stays browser-free and a
separate runner does the rendering. The runner uses Playwright and Chromium. It watches the spine,
renders new mints and parameter changes, and publishes each render to the resolver.

- Run it locally with `abx effects`. Add `--once` to sweep every project once and exit.
- Host it with `abx deploy-effects --resolver-url <https://your-resolver>`.
- Render one project's missing stills with `abx render <address>`.

Set `ABX_EFFECTS_URL` on the resolver so its chain watcher notifies the runner as soon as something
changes. A periodic sweep is the fallback.

## Storage

The resolver and runner read and serve the source bytes from a storage backend. For a hosted pair, use
a shared, addressable backend such as IPFS, Arweave, or S3-compatible cloud, not local disk. See
[Storage](guides/storage.md).

## Migrating

`abx migrate <address> --from <source-resolver-url> --to <dest-resolver-url>` moves a project's
off-chain state to a new resolver. It reconstructs the on-chain truth, copies the source resolver's
off-chain values (description, external URL, off-chain traits, image locators), re-pins images to a
durable backend after verifying them against the on-chain hash, and runs a parity check between source
and destination. It does not cut over: you re-point DNS, or the on-chain base URI with `set-token-uri`
and `set-contract-uri`, when you are ready. The two resolvers never talk to each other.
