Quickstart
This is the first static deploy. You need Node.js 20 or newer (for npx) and an email address. Nothing else: no account is created until the CLI opens a browser.
1. A directory with an index.html
Section titled “1. A directory with an index.html”mkdir hello-tori && cd hello-toricat > index.html <<'EOF'<!doctype html><meta charset="utf-8"><title>Hello from Tori</title><h1>Hello from Tori</h1>EOFIf you already have a site that builds to dist/, build/, out/, or _site/ with an index.html inside, use that project instead.
2. Deploy
Section titled “2. Deploy”npx tori.hostIf this machine has never signed in, a browser opens. Sign in (or sign up — same click). The CLI packs the files, uploads them, and waits until the site answers:
✓ live: https://plucky-wren.tori.cloudOpen that URL. You should see the page you just wrote.
The first deploy creates the app and writes tori.json in the current directory:
{ "slug": "plucky-wren"}Keep that file in version control so later deploys update the same app. Commands such as tori logs and tori env read the slug from it.
3. Deploy again
Section titled “3. Deploy again”Edit index.html and run npx tori.host from the same directory. The CLI reuses the slug in tori.json. live means the files of this deploy are the ones the URL serves. There is no separate promote step. Ctrl+C stops watching; it does not cancel an upload that already finished.
What the CLI looks for
Section titled “What the CLI looks for”With no directory argument it uses dist/, build/, out/, or _site/ when one of them contains index.html. Otherwise it runs npm run build and looks again, then ./index.html.
Pass a directory to skip detection:
npx tori.host deploy ./distIf none of those exist, it exits with nothing to deploy and names what it looked for. Build the site first, or pass the directory that holds index.html.
Frameworks
Section titled “Frameworks”Vite, Astro, and similar tools work when you deploy the output directory, not the source tree:
npm run buildnpx tori.host deploy ./distnode_modules and .git at the top of the packed directory are skipped. Do not pack tori.json into the site; the CLI already excludes it.
If it is a server, not a site
Section titled “If it is a server, not a site”A service is a different app kind: a container the zone runs for you. With a Dockerfile at the root, npx tori.host builds it on Tori; without one, say so and the language is detected:
npx tori.host deploy --serviceIf you already have an image, nothing is packed — the reference travels, digest-pinned:
npx tori.host deploy --image registry.example.com/acme/api@sha256:<64 hex>The container must listen on port 8080 and declare a numeric non-root USER. See Deploy a container service and tori deploy.
If something fails
Section titled “If something fails”| What you see | What to do |
|---|---|
| Browser does not open (SSH, CI, no display) | Use the printed https://my.tori.host/cli-auth code, or set TORI_TOKEN in CI. Sign in |
no API token found, and this looks like CI |
Mint a token in the console under Settings → API tokens and export TORI_TOKEN |
nothing to deploy |
Create index.html, run the framework build, or pass ./dist |
npm run build failed |
Fix the build, then deploy the output directory explicitly |
| Archive refused before upload | Drop large files; the CLI checks a local size cap, and the server also enforces the plan’s artefact limit |
deploy failed: … |
The server stored a reason (deploys.error). Fix that, then deploy again. Deploy status and recovery |
Download this page as Markdown.