Amba

Sites

Host a static site on Amba — deploy a bundle of files, serve it at a free subdomain, attach your own custom domain with managed TLS, and roll back instantly.

Amba hosts static sites — marketing pages, docs, SPAs, anything that's a bundle of files. Deploy a directory and Amba serves it at https://{slug}.app.amba.host with a managed TLS certificate. Attach a custom domain when you're ready, and roll back to any previous deployment in one call. Every deployment is immutable, so a rollback is just a pointer flip — no rebuild.

The fastest paths are the CLI (amba sites deploy ./dist) and the amba_sites_* MCP tools. The REST surface below is what both wrap.

On the free tier, a site serves with a small "Built with Amba · preview" bar and an X-Robots-Tag: noindex header, and custom domains are a paid feature. Upgrading the project removes the bar and unlocks custom domains. See free-tier limits.

Concepts

  • Site — a named container for deployments. The name must match ^[a-z][a-z0-9_-]{0,49}$ and becomes part of the public URL. Public URL: https://{slug}.app.amba.host, where slug is the first 8 characters of your project id plus the site name.
  • Deployment — one immutable upload of files. The current deployment serves all traffic; older ones are retained for rollback.
  • Custom domain — your own hostname (e.g. app.example.com) bound to the site, with a TLS certificate Amba provisions and renews for you.

Deploy

The CLI bundles a directory and ships it in one command:

amba sites deploy ./dist --name marketing

From an agent, amba_sites_deploy creates the site (if needed) and uploads the files in a single tool call — pass project_id, name, and a files object mapping each relative path to its content.

Under the hood, deploy is two REST calls — register the site, then upload the bundle as multipart form data (one part per file, keyed by relative path):

MethodPathDescription
POST/admin/projects/:projectId/sitesRegister a site. Body { name }.
POST/admin/projects/:projectId/sites/:name/deploymentsUpload a deployment (multipart).
GET/admin/projects/:projectId/sitesList sites.
GET/admin/projects/:projectId/sites/:nameDescribe a site + its custom domains.
PATCH/admin/projects/:projectId/sites/:nameSet status (active / disabled).
POST/admin/projects/:projectId/sites/:name/rollbackRepoint to a prior deployment.
DELETE/admin/projects/:projectId/sites/:name?confirm=:nameDelete a site (full cascade).

A successful deploy returns the canonical URL plus file/byte counts:

{
  "data": {
    "deployment_id": "…",
    "site_name": "marketing",
    "url": "https://abcd1234-marketing.app.amba.host",
    "deployed_at": "2026-05-27T10:00:00.000Z",
    "status": "active",
    "file_count": 12,
    "total_bytes": 348201
  }
}

The per-file cap is 25 MiB. A failed upload leaves your live site untouched — the new deployment is only made current after all files land.

Routing

Amba maps each request path to a file in the current deployment using the same conventions as other static hosts, so directory-style exports from Astro, Hugo, Next.js (output: 'export'), and similar generators work with their default links. Each request shape resolves in this order:

RequestResolves to
/index.html
/start/start/index.html. When only start.html exists, a 308 redirect to /start.
/startThe exact file start, then start.html. When only start/index.html exists, a 308 redirect to /start/.
/start.html, /app.cssThat exact file.
Anything unresolvedYour 404.html with status 404, or the single-page-app fallback.

Paths with a dot in the last segment, such as /blog/release-2.0, follow the /start rules once the exact file misses, so dotted slugs resolve to release-2.0.html or redirect to release-2.0/. Redirects keep the query string, so /start?ref=nav lands on /start/?ref=nav. The trailing slash matters for directory pages because the browser resolves relative links (./logo.png, ../) against it. File names with spaces or non-ASCII characters resolve from their percent-encoded URLs (/caf%C3%A9 serves café.html).

Not found. Ship a 404.html at the root of the bundle and Amba serves it, with status 404, for every path that doesn't resolve.

Single-page apps. Without a 404.html, a path with no file extension (/dashboard/settings) serves the root index.html with status 200 so your client-side router can take over. A missing file with an extension (/assets/missing.js) always returns 404, so a broken script or stylesheet reference never receives HTML. If your framework writes its single-page-app shell to 404.html (some static adapters do), every deep link returns status 404. Have it write the shell to index.html so the single-page-app fallback serves it.

Caching. HTML responses and redirects are sent with Cache-Control: no-cache, no-store, must-revalidate, so a new deployment is visible on the next request. Other files are sent with public, max-age=3600; give long-lived assets content-hashed filenames (most bundlers do this by default) so a deploy never serves a stale copy.

Custom domains

Bind your own hostname, then publish the DNS records Amba returns. Amba registers the hostname and provisions and renews the certificate for you — you don't need any third-party credentials.

Subdomains like app.yourdomain.com are the simplest path. Apex (root) domains such as yourdomain.com work only when authoritative DNS can store a real CNAME record at the apex. Provider-native CNAME-at-root flattening is compatible when the provider retains that record as a CNAME in its control plane. ALIAS, ANAME, and copied A/AAAA addresses are not substitutes: they remove the CNAME relationship required for standard custom-hostname activation. If your provider cannot store an apex CNAME, use www or another subdomain. Platform domains (*.amba.host, *.amba.dev) are reserved and rejected.

amba sites domain add marketing app.example.com
MethodPathDescription
POST/admin/projects/:projectId/sites/:name/domainsAttach a hostname.
GET/admin/projects/:projectId/sites/:name/domainsRe-poll and list attached hostnames + authoritative readiness.
POST/admin/projects/:projectId/sites/:name/domains/:hostname/refresh-certForce provider, Worker route, host KV, and managed-DNS reconciliation.
DELETE/admin/projects/:projectId/sites/:name/domains/:hostnameDetach a hostname.

Lifecycle fields are read-only. The former PATCH .../domains/:hostname surface returns 405 LIFECYCLE_READ_ONLY; clients cannot declare a hostname active. Use the refresh endpoint and wait for the server-derived readiness field instead.

The attach response returns the records you publish to verify ownership (ssl_validation + ownership_verification), the dns_target to point a CNAME at, a Public-Suffix-List-derived is_apex flag, an unconditional dns_note record-type warning, and independent provider and serving-plane statuses:

{
  "data": {
    "hostname": "app.example.com",
    "cert_status": "pending_validation",
    "ownership_status": "pending",
    "route_status": "active",
    "kv_status": "active",
    "dns_managed": false,
    "dns_status": "not_required",
    "live": false,
    "dns_target": "abcd1234-marketing.app.amba.host",
    "dns_record_type": "CNAME",
    "is_apex": false,
    "dns_note": "Publish a real CNAME; ALIAS, ANAME, and copied A/AAAA records do not activate standard custom-hostname routing.",
    "ssl_validation": [
      {
        "txt_name": "_acme-challenge.app.example.com",
        "txt_value": "<token>"
      }
    ],
    "ownership_verification": {
      "type": "txt",
      "name": "_amba-challenge.app.example.com",
      "value": "<token>"
    }
  }
}

The flow is:

  1. Publish the verification records. Add the ssl_validation TXT record(s) and the ownership_verification TXT record at your DNS provider. If ssl_validation is empty on the immediate response, it populates shortly — re-fetch the live records via the refresh-cert endpoint or amba_sites_list_domains.
  2. Point DNS at dns_target. Publish the returned dns_record_type exactly; the real-CNAME warning is returned for every hostname, not only apexes. For a root domain (is_apex: true), provider-native CNAME-at-root flattening is valid only when the provider stores a real CNAME. Do not substitute an ALIAS, ANAME, or resolved A/AAAA value. Use a subdomain if your DNS provider cannot store an apex CNAME (see dns_note on the response).
  3. Wait for every required plane to reach active. ownership_status (pending → active) confirms you control the hostname; cert_status (pending_validation → pending_issuance → pending_deployment → active) tracks the TLS certificate. route_status and kv_status confirm the edge route and host-to-site mapping. Purchased domains also require dns_status: active; externally managed DNS reports not_required.

Your domain is live — and the certificate renews automatically — only once the server-derived live field is true. A successful TLS handshake, or even active certificate and ownership states together, do not prove the Worker route and host KV are ready. Poll the list endpoint (or amba_sites_list_domains), or call refresh-cert to force all-plane repair. route_status, kv_status, and managed dns_status errors are retryable and remain eligible for bounded CLI polling/refresh. Provider-terminal cert_status or ownership_status errors require re-attachment.

Rollback

Every deployment is immutable and kept on file. To revert, point the site back at a previous deployment_id (find ids via amba_sites_get or GET /sites/:name):

curl -X POST 'https://api.amba.dev/v1/admin/projects/$PROJECT_ID/sites/marketing/rollback' \
  -H 'Authorization: Bearer $AMBA_PAT' \
  -H 'Content-Type: application/json' \
  -d '{ "deployment_id": "…" }'

The flip is atomic — the next request serves the prior bundle. You can't roll back to a failed deployment, and rolling back to the already-current deployment is rejected.

Pause and delete

PATCH .../sites/:name with { "status": "disabled" } stops the site (and its custom domains) from serving without losing the deployment history; set it back to active to resume.

DELETE .../sites/:name?confirm=<name> tears everything down — custom hostnames are unbound, every deployment's files are removed, and the site row is archived. The ?confirm=<name> guard is required; the CLI and MCP tool set it for you. The response reports what was cleaned up:

{
  "data": {
    "name": "marketing",
    "deleted": true,
    "cascade": { "domains_removed": 1, "objects_removed": 12 }
  }
}

MCP tools

ToolDoes
amba_sites_deployCreate-or-deploy in one call.
amba_sites_listList sites.
amba_sites_getDescribe a site + its domains.
amba_sites_deleteDelete a site (cascade).
amba_sites_add_domainAttach a custom hostname.
amba_sites_list_domainsList hostnames + cert status.
amba_sites_remove_domainDetach a hostname (idempotent).

See the CLI reference for the full amba sites command set.

On this page