deploying-to-remote-clouds
Deploying To Remote Clouds
When to use
- Target is a real Taubyte cloud (not Dream local)
- Switching from Dream to remote (or vice versa)
- After a
tau push projectto remote, build status is unclear - Error:
project ids not equal <patrick> != <yaml> - Generated domain looks wrong (or you're about to create one and aren't sure if you're on remote)
- Verifying that GitHub webhook delivery actually reached the cloud
Mental model
A remote Taubyte cloud is reached by FQDN rather than by Dream universe. After git push (or tau push project), the cloud is notified by a GitHub webhook, builds happen automatically, and serving picks up the latest successful build. There is no dream inject step for remote — that's Dream-only. Verification therefore relies on tau query builds/build/logs and, when those are silent, GitHub's webhook delivery records.
Selecting a remote cloud
tau --defaults --yes select cloud --fqdn <cloud_fqdn>
tau --defaults --yes json current
Verify in the JSON output:
| Field | Expected |
|---|---|
Cloud |
<cloud_fqdn> |
Cloud Type |
remote |
Profile |
The authenticated profile that has access to this cloud |
If Cloud Type is anything other than remote, stop before any deploy or domain create — see selecting-taubyte-context. Projects are per-cloud, so re-list:
tau --defaults --yes list projects
tau --defaults --yes select project --name <project_name>
Project-id alignment (critical for remote)
Each project on a remote cloud has a canonical id stored cloud-side ("Patrick"). The local config/config.yaml carries the same id as id:. They must match, or every push will fail with:
project ids not equal <patrick_id> != <yaml_id>
Recovery:
# Cloud-side id (canonical)
tau --defaults --yes query project <project_name> --json | grep -i '"id"'
# Local id
awk '/^id:/{print $2; exit}' config/config.yaml
If they differ, edit config/config.yaml to use the cloud's canonical id, then push again. (This is one of the few cases where touching config/config.yaml directly is correct — it's the project identity, not a resource definition.)
Push flow (remote)
Remote push progress:
- [ ] tau --json current shows Cloud Type: remote and the right Project
- [ ] Project ids match (config.yaml id == cloud canonical id)
- [ ] tau push project --config-only -m "<msg>" (when config changed)
- [ ] Wait for config build success on the cloud
- [ ] tau push project --code-only -m "<msg>" (when code changed)
- [ ] tau push website <site> -m "<msg>" (when site changed)
- [ ] tau push library <lib> -m "<msg>" (when library changed)
- [ ] Verify each build via tau query builds / tau query logs
--message is required when --defaults is set — see pushing-taubyte-projects.
No dream inject for remote. The webhook does the equivalent automatically.
Project registration on remote (easy to overlook)
Projects are per cloud. If tau --defaults --yes list projects on your target FQDN does not list the project yet, tau push cannot wire real builds. Register the GitHub repo pair once:
tau --defaults --yes select cloud --fqdn <fqdn>
tau --defaults --yes import project <snake_case_name> \
--config <org>/tb_<name> \
--code <org>/tb_code_<name>
tau --defaults --yes query project <name> --json # canonical id:
Then set config/config.yaml root id: to that id (same alignment as bootstrapping-taubyte-projects — not only for Dream) and tau push project --config-only before relying on code/website builds.
Verification commands
# Recent jobs (filter by time)
tau --defaults --yes query builds --since 1h # default --since 168h (one week)
# Inspect a single job
tau --defaults --yes query build --jid <job_id>
# Download logs to a directory (or print to terminal if --output is omitted)
tau --defaults --yes query logs --jid <job_id> --output ./logs_<job_id>
tau query builds (alias jobs) returns recent builds; tau query build / tau query job (singular, --jid required) returns a single job; tau query logs --jid fetches logs for that job.
Per-resource queries (handy for verifying that the cloud sees what you just pushed):
tau --defaults --yes query project <project_name> --json
tau --defaults --yes query function <fn_name> --json
tau --defaults --yes query website <site_name> --json
tau --defaults --yes query library <lib_name> --json
tau --defaults --yes query domain <domain_name> --json
tau --defaults --yes query database <db_name> --json
tau --defaults --yes query storage <store_name> --json
tau --defaults --yes query messaging <msg_name> --json
tau --defaults --yes query service <svc_name> --json
When tau query builds is empty after push
This usually means the cloud didn't pick up the push. The webhook is the prime suspect.
Empty-builds diagnosis progress:
- [ ] Confirm the git remote actually received the push (git log origin/main -1)
- [ ] On GitHub: repo → Settings → Webhooks → click the cloud webhook → Recent Deliveries
- [ ] Check the most recent delivery: status code (200/201 expected), response body, redelivery option
- [ ] If delivery failed: redeliver from GitHub UI
- [ ] If delivery succeeded but tau query builds is still empty: re-check tau --json current cloud + project; you may be querying the wrong cloud
- [ ] Cross-check via tau --defaults --yes query project <name> --json
GitHub's "Recent Deliveries" panel shows the actual webhook payload and the cloud's HTTP response — this is the source of truth when "did the cloud see this push?" is the question.
Remote website/library gotchas (common “silent deploy” causes)
- Repo not registered on that cloud: run
tau import website <site>/tau import library <lib>once on the selected remote cloud. - Duplicate GitHub webhooks (from repeated imports): delete repo hooks and re-import once to recreate a single clean hook.
- Strict website routing: for root hosting ensure website
pathsincludes exactly"/"(route matching is strict). - Builder config typos:
.taubyte/config.yamlmust useenvironment:(notenviroment:); typos can make builds look “ignored”.
If tau query builds is empty but you’re sure webhooks delivered
tau query builds can be incomplete or misleading on some remote clouds. In that case:
- fetch the job id from the cloud’s jobs service (Patrick), then
- pull logs directly with
tau query logs --jid <jobid>.
Treat job logs as the deploy truth source, not “push succeeded”.
Generated domains rule (remote vs Dream)
tau new domain --generated-fqdn produces a hostname under the currently selected cloud's generated suffix. On Dream the suffix is .<universe>.localtau. On a remote cloud it's that cloud's configured generated TLD.
Rule: only run tau new domain --generated-fqdn while tau --json current shows Cloud Type: remote (or the correct Dream universe). If you generate a domain while pointed at the wrong cloud, the FQDN won't resolve in the cloud you actually deploy to.
Forbidden flag (re-emphasized): never pass --generated-fqdn-prefix / --g-prefix to tau new domain. Use --generated-fqdn alone, or --fqdn <controlled_hostname> with proper DNS delegation.
For a custom FQDN on remote:
tau --defaults --yes new domain <name> \
--fqdn api.example.com \
--type auto \
--description "<desc>"
--type auto lets the cloud handle TLS issuance.
TLS / certificates
- Remote clouds issue TLS certificates automatically for generated domains under the cloud's TLD, and for custom domains where DNS delegation + verification is satisfied.
- Use
--type httpsfor HTTP API functions on remote (see authoring-taubyte-function-types). - A
--type httpfunction on a remote cloud is usually unreachable (the gateway expects TLS).
Hosts file is not typically needed
Unlike Dream's *.localtau (which has no public DNS), remote-cloud FQDNs resolve via real DNS — generated domains under the cloud's TLD, or your custom DNS-delegated domain. Don't add hosts entries for remote cloud testing. If a remote URL doesn't resolve, the issue is DNS (or the domain isn't created yet), not hosts.
For Dream-specific hosts mapping, see verifying-taubyte-functions.
Smoke-testing a deployed function
curl -i "https://<fqdn>/<path>"
# expect HTTP 200 and the expected body
If the request hangs or 404s but tau query function <fn> shows the function exists:
- The build may not have promoted yet — wait a few seconds and re-curl.
- The domain may not be attached to the function — re-check the function YAML's
domains:array. - For custom domains: DNS may not have propagated;
dig <fqdn>to check.
Recovery — symptom → likely cause
| Symptom | Likely cause | Fix |
|---|---|---|
GET / returns 500 / no HTTP match for method GET while GET /api/... returns 200 |
Website static bundle not deployed: only the code repo built; the website repo (tb_code_<project>_<site>) has no successful job / AssetCid |
Run tau push website <site_name>; in tau query builds --json, confirm a job whose Meta.Repository is the website repo and AssetCid maps the website resource id → a baf… artifact. Relative fetch("/api/...") in index.html is fine once / serves HTML. |
Config job: domain … invalid fqdn … *.default.localtau / TXT lookup … localtau … no such host |
Dream-generated *.default.localtau left in config after switching to a public remote (compiler checks real DNS, e.g. 1.1.1.1) |
tau delete domain <name> then tau new domain <name> --fqdn <remote-suitable> --type auto (CLI only — never hand-edit domain YAML); tau push project --config-only. Remove orphan app-scoped domains still on localtau the same way. |
Config job: generated fqdn … does not contain last 8 of project id <CID> |
On some remotes, *.gen.<cloud> hostnames must embed the last 8 characters of the project CID |
python3 -c "s='<project_cid>'; print(s[-8:])" and choose an *.gen.<cloud> FQDN that contains that substring; when recreating, reuse the same logical domain name (e.g. generated) so existing domains: lists in websites/functions stay valid. |
tau pull project prints already up-to-date and exits non-zero |
tau pull quirk — not necessarily a git failure |
Confirm with git fetch + git status in config/ and code/; treat as success if trees match origin. See pushing-taubyte-projects. |
unknown cloud on push |
Cloud selection lost between sessions | tau select cloud --fqdn <fqdn> then retry push |
project ids not equal <a> != <b> |
config/config.yaml id: differs from cloud canonical |
Update id: to the cloud's canonical id, push config |
tau query builds empty after push |
Webhook delivery failed / pointed at wrong cloud | Check GitHub Webhooks → Recent Deliveries; verify tau --json current |
| Generated domain FQDN not under expected TLD | Generated while pointed at Dream | Delete the domain, switch to the right cloud, recreate |
| 404 from custom domain | DNS not delegated yet, or domain --type issue |
dig <fqdn>; consider --type auto |
| TLS error on a remote function URL | Function trigger.type: http (not https) |
Switch the function to https (or recreate) |
| Build succeeds but old version served | Browser cache / CDN edge cache | Hard refresh; verify with curl first |
Gotchas
dream injectdoes not work on remote. It only triggers Dream-local builds. On remote the webhook is the trigger, period.--messageis mandatory fortau pushwhen--defaultsis set; same rule as Dream.- Project selection is per-cloud. After switching clouds, re-select the project before any push or query.
- Don't generate domains while pointed at Dream and expect them to work on remote — the generated TLD is per-cloud.
config/config.yamlid:is the project identity. Treat it like a primary key — only edit it to align with the cloud's canonical id, never to "rename" a project.- GitHub webhook delivery is the truth when build status seems silent. Don't keep retrying
tau pushif the webhook isn't being delivered; fix the webhook first.
Related skills
selecting-taubyte-context—--fqdncloud selection +tau --json currentverificationpushing-taubyte-projects— push variants and the--messagerulecreating-taubyte-resources—tau new domainpatterns (generated vs--fqdn)authoring-taubyte-function-types—--type httpsfor remote functionsdiagnosing-dream-builds— analogous, but Dream-side; many concepts mirror this skillunderstanding-taubyte-architecture— webhook vs inject build flow
More from taubyte/skills
verifying-taubyte-functions
Verifies a Taubyte Go function locally via the `taubyte/go-wasi` Docker recipe (preferred over `tau build`, with tmpfs+bind-mount-ro to avoid root-owned artifacts in the source tree), and verifies a function actually serves on Dream by curling the gateway with the right `Host:` header (plus `/etc/hosts` mapping for `*.localtau`). Use when locally compiling a Go function to WASM, when smoke-testing a function before pushing, or when probing a Dream-hosted HTTP function from the laptop.
12creating-taubyte-resources
Creates Taubyte resources non-interactively via `tau new` for domain, website, library, function, application, database, storage, messaging, and service. Encodes the project-vs-application scope rule, the database `min < max` constraint, the website/library `--generate-repository` + import sequence, and the forbidden `--generated-fqdn-prefix` flag. Use when adding any resource to a Taubyte project's config repo.
12diagnosing-dream-builds
Diagnoses Dream local-cloud builds when `tau list/query builds` is empty or unreliable, by hitting the jobs HTTP endpoint directly (`GET /jobs/<project_id>`, `GET /job/<job_id>`) using the GitHub token from `~/tau.yaml`, then downloading logs with `tau query logs --jid`. Use when Dream builds appear silent, the build table is empty after `dream inject`, or you need raw job ids and logs for a failing build.
11taubyte-resource-creation
Scope-aware resource creation workflow. Uses non-interactive mode by default and references the shared flags catalog.
11taubyte-push-build-verify
Pushes config/code and verifies builds/logs. Includes website/library push handling with tau command first, git fallback.
11taubyte-scope-routing
Routes project-level vs application-scoped work; defaults to a website when a browser UI is logically appropriate; avoids unnecessary applications for simple website/function-only tasks unless needed.
11