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 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.

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.

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.