Stand up Heyo Web Services on a Linux host: install heyvm, then the HWS services in dependency order, wire them together, and register a first deployment.
HWS is a set of independent binaries. Each one is configured entirely by environment variables, runs in the foreground, and ships a supervisord program file. You can install them three ways:
| Method | Needs a credential | Use it when |
|---|---|---|
bootstrap-host.sh |
No (secrets are written to files first) | You are turning a fresh Debian/Ubuntu machine into an app-lb host in one step |
install-apps.sh |
No | You want the published release of one or more apps from get.us2.heyo.work |
.ci/install.sh |
ART_API_KEY |
You run your own CI and artifact store and install what it built |
| Build from source | No | You are developing HWS or need a platform the releases do not cover |
Published releases are built for linux-x86_64 only.
What you are installing
| Component | Binaries | Default listeners | Depends on |
|---|---|---|---|
| heyvm | heyvm, heyvmd |
heyvmd API 127.0.0.1:34099 (or a unix socket) |
KVM, Firecracker, docker (for image builds) |
| heyosecret | heyosecret |
:4455 |
PostgreSQL |
| art (artifact store) | art |
127.0.0.1:8080 (art serve) |
Local disk |
| app-lb | app-lb, heyctl |
proxy 0.0.0.0:6188, TLS 0.0.0.0:6189, admin 127.0.0.1:9090 |
heyvmd; art on the same host for workspace/artifact features |
| app-obs | app-obs, app-obs-dump |
ingest 0.0.0.0:9500, syslog 0.0.0.0:9514, API 127.0.0.1:9600 |
app-lb admin API |
| ci | ci |
127.0.0.1:9500 |
PostgreSQL, NATS JetStream, heyvm runner hosts |
| pg-fc (optional) | pg-vm-pool |
127.0.0.1:6432 |
heyvmd on the same host |
| queue (optional) | queue |
127.0.0.1:9700 |
A NATS server with monitoring on :8222 |
| mcp (optional) | Node.js app | set by HEYO_MCP_HTTP_PORT (stdio if unset) |
app-lb, app-obs, ci, art APIs |
The defaults for app-obs ingest and ci both use port 9500. If you run both on
one host, move one of them (APP_OBS_INGEST_ADDR or CI_LISTEN_ADDR).
Host requirements
- Linux x86_64 with
/dev/kvm(bare metal, or a VM with nested virtualisation). - Firecracker on
PATH.bootstrap-host.shinstallsv1.16.1by default. - docker and
e2fsprogsif the host builds guest images (any deployment with abuildblock, orheyctl build). supervisorif you want to use the shipped program files. Any process manager works; the.conffiles show the environment each service needs.curl,tar,sha256sumfor the installers.- PostgreSQL reachable from heyosecret and ci. pg-fc can provide it.
Recommended order
Install in this order. Each step depends only on the ones above it.
- heyvm (
heyvmd) — the microVM daemon every VM-backed service drives. - heyosecret — secrets store; other services and CI read credentials from it.
- art — artifact store for guest images, release tarballs, and workspaces.
app-lb also needs the
artbinary on its own host. - app-lb — load balancer, autoscaler, and control plane. From here on you
register workloads with
heyctl. - app-obs — logs, metrics, and alerts fed by app-lb.
- ci — the CI orchestrator, if you want to build and release on HWS.
- Optional: pg-fc (Postgres microVMs and pooler), queue (NATS dashboard), mcp (MCP server for agents).
heyosecret and art can themselves run as app-lb deployments once app-lb is up
(see app-lb/examples/heyosecret.json and app-lb/examples/artifacts.json).
The order above installs them directly on the host, which is simpler for a
first install.
Bootstrap a fleet host
.ci/bootstrap-host.sh turns a fresh
Debian/Ubuntu host into an app-lb host: it installs packages and Firecracker,
installs heyvm, app-lb and art with install-apps.sh, writes supervisor
units for heyvmd and app-lb, starts them, and routes admin.<domain> to
the admin API. It creates no workload VMs.
Write the secrets first, mode 0600, over a channel that does not record them:
sudo install -d -m0755 /etc/app-lb /etc/heyvm
sudo sh -c 'umask 077; printf "APP_LB_DASHBOARD_PASSWORD=%s\n" "<password>" > /etc/app-lb/env'
# optional: /etc/heyvm/env with heyvmd's environment (for example CLOUD_INTERNAL_API_KEY)
/etc/app-lb/env may also carry APP_LB_OBS_TOKEN and
APP_LB_DAEMON_API_KEY. If /etc/heyvm/env sets CLOUD_INTERNAL_API_KEY,
that value is heyvmd's operator key, and app-lb must present the same value as
APP_LB_DAEMON_API_KEY.
Then run, as root:
curl -fsSL https://get.us2.heyo.work/bootstrap-host.sh | sh -s -- \
--id us4 --domain us4.example.com \
--public-ip 203.0.113.4 --acme-email ops@example.com
| Flag | Required | Meaning |
|---|---|---|
--id NAME |
yes | Short lowercase host name; becomes APP_LB_NAME |
--domain HOST |
yes | Base domain; sets APP_LB_DEPLOY_BASE_DOMAIN and the admin.<domain> route |
--public-ip IP |
yes | The host's public address (APP_LB_PUBLIC_IPS) |
--acme-email EMAIL |
yes | Let's Encrypt account contact (APP_LB_ACME_EMAIL) |
--acme-staging |
no | Use the Let's Encrypt staging directory |
--releases-url URL |
no | Manifest site. Default https://get.us2.heyo.work |
| Environment | Default | Meaning |
|---|---|---|
RELEASES_URL |
https://get.us2.heyo.work |
Same as --releases-url |
FIRECRACKER_VERSION |
v1.16.1 |
Firecracker release to install if the one on PATH differs |
DASHBOARD_USER |
heyo |
APP_LB_DASHBOARD_USER |
What the host looks like afterwards:
heyvmd --api-port 34099under supervisor,MVM_DATA_DIR=/var/lib/heyvm, logs in/var/log/heyvmd/.app-lbas root, proxy on:80, TLS on:443, admin on127.0.0.1:9090, state in/var/lib/app-lb/app-lb-state.json, ACME in/var/lib/app-lb/acme,APP_LB_ART_BIN=/usr/local/bin/art, images in/var/lib/heyvm/images/firecracker.- A
localheyctl context and anapp-lb-admindeployment routingadmin.<domain>to127.0.0.1:9090. ACME issues its certificate once DNS points at the host.
Re-running the script is safe: it upgrades binaries, keeps existing supervisor
units (new ones land beside them as .conf.new), and re-applies the admin
route.
Install published releases
.ci/install-apps.sh installs published releases
with no credential. It reads <app>.json manifests from the release site,
downloads the public blob each names, and verifies it.
curl -fsSL https://get.us2.heyo.work/install-apps.sh | sh -s -- --list
curl -fsSL https://get.us2.heyo.work/install-apps.sh | sudo sh -s -- heyvm app-lb art
curl -fsSL https://get.us2.heyo.work/install-apps.sh | sudo sh -s -- --version app-lb=<ver> app-lb
Pass flags through a pipe with sh -s --, or sh treats them as its own.
HWS apps it installs: app-lb, app-obs, ci, queue, art, heyosecret,
and heyvm. The same manifests also list cloud, auth and retail, which
are built outside this repository and are not part of HWS.
| Option | Meaning |
|---|---|
--list |
Show what the manifests offer; install nothing |
--dry-run |
Download and verify; install nothing |
--version APP=VER |
Install VER of APP instead of the latest. Repeatable |
--supervisor |
Install shipped supervisor units. Default when /etc/supervisor/conf.d exists |
--no-units |
Install no process-manager units |
--restart |
Run supervisorctl reread/update and restart what was installed |
| Environment | Default | Meaning |
|---|---|---|
RELEASES_URL |
https://get.us2.heyo.work |
Where the manifests are |
STORE_URL |
the manifest's store |
Override the artifact store to download from |
PREFIX |
/usr/local |
Binaries go in $PREFIX/bin |
STATE_ROOT |
/var/lib |
Migrations go in $STATE_ROOT/<app>/migrations |
OPT_ROOT |
/opt/heyo |
Where tree apps are installed |
SITE_ROOT |
/srv/heyo |
Where site apps are installed |
SUPERVISOR_DIR |
/etc/supervisor/conf.d |
Where supervisor programs go |
What gets installed depends on the manifest's kind:
| Kind | Installs |
|---|---|
bin |
The named binaries into $PREFIX/bin (by rename, so a running binary is replaced safely), migrations/ into $STATE_ROOT/<app>/migrations, and <app>.conf into $SUPERVISOR_DIR |
tarball |
heyvm and heyvmd from the release tarball inside the artifact |
tree / site |
The whole release under <root>/<app>/releases/<version>, with current repointed at it |
Every download is checked twice: the blob's sha256 must equal the digest it
was fetched by, then sha256sum -c SHA256SUMS runs over the unpacked files.
The script sends no Authorization header; the store rejects a presented
stale key even for a public blob.
It never overwrites an existing supervisor file. The shipped file is written
beside yours as <app>.conf.new, and you merge new settings by hand.
Install from your own artifact store
.ci/install.sh installs the newest build of each app
from an art serve that your CI pushes to. It resolves tags, so it needs the
store's API key.
ART_URL=https://art.example.com ART_API_KEY=... sh .ci/install.sh
sh .ci/install.sh --list
sh .ci/install.sh --dry-run
sh .ci/install.sh app-lb
sh .ci/install.sh --ref ci-app-lb-<run>-release-app-lb app-lb # roll back
PREFIX=~/.local SUPERVISOR_DIR= sh .ci/install.sh # unprivileged, no units
| Option | Meaning |
|---|---|
--list |
Show what the store has, with each artifact's description |
--dry-run |
Resolve, download and verify; install nothing |
--restart |
supervisorctl update and restart each installed program |
--ref TAG |
Install this exact tag instead of the newest |
--prefix PATH |
Same as PREFIX |
| Environment | Default | Meaning |
|---|---|---|
ART_URL |
(required) | Base URL of the art serve |
ART_API_KEY |
(required unless the store is open) | Bearer token for it |
PREFIX |
/usr/local |
Binaries go in $PREFIX/bin |
STATE_ROOT |
/var/lib |
Migrations go in $STATE_ROOT/<app>/migrations |
SUPERVISOR_DIR |
/etc/supervisor/conf.d |
Set empty to skip supervisor files |
APPS |
app-lb app-obs ci art |
Which apps to install when none are named |
Installable names: app-lb, app-obs, ci, art, codegraph, queue,
heyosecret, pg-fc. queue and pg-fc are deliberately not in the default
set: queue belongs only on the host that runs nats-server, and pg-fc
installs only the pg-vm-pool binary without configuring or restarting a
pooler.
CI tags each upload ci-<workflow>-<run>-<job>-<name>, for example
ci-app-lb-<run>-release-app-lb. The run id is fixed-width hex, so sorting
tags lexicographically sorts them chronologically; that is how the script
finds the newest build. See ci and artifacts.
Build from source
Every service has its own lockfile. Build with --locked:
cargo build --release --locked --manifest-path app-lb/Cargo.toml --workspace # app-lb + heyctl
cargo build --release --locked --manifest-path app-obs/Cargo.toml # app-obs + app-obs-dump
cargo build --release --locked --manifest-path artifacts/Cargo.toml # art
cargo build --release --locked --manifest-path heyosecret/Cargo.toml
cargo build --release --locked --manifest-path ci/Cargo.toml
cargo build --release --locked --manifest-path queue/Cargo.toml
cargo build --release --locked --manifest-path pg-fc/Cargo.toml # pg-vm-pool
cargo build --release --locked --manifest-path orchestrator/Cargo.toml
Binaries land in <crate>/target/release/ unless CARGO_TARGET_DIR is set.
Copy them into /usr/local/bin, and copy each crate's
deploy/supervisor/*.conf into /etc/supervisor/conf.d/.
System packages the builds need:
| Crate | Packages (Debian/Ubuntu) |
|---|---|
| app-lb | build-essential cmake perl pkg-config (OpenSSL and zlib-ng are compiled from source) |
| app-obs | build-essential cmake pkg-config |
| ci | build-essential pkg-config libssl-dev |
| codegraph | build-essential |
Without --workspace, the app-lb build produces only app-lb, not heyctl.
app-obs needs noticeably more memory to compile than the other crates; lower
CARGO_BUILD_JOBS if the build is OOM-killed.
The MCP server is Node.js:
cd mcp && npm ci && npm run build # output in mcp/dist/
Step by step
1. heyvm
heyvm is the Firecracker/KVM microVM runtime. Its CLI and daemon are documented at heyo.computer/docs. Install both binaries from the release manifests:
curl -fsSL https://get.us2.heyo.work/install-apps.sh | sudo sh -s -- heyvm
Run heyvmd under a process manager with a fixed data directory. The unit
bootstrap-host.sh writes is a good template:
[program:heyvmd]
command=/bin/sh -c 'set -a; [ -f /etc/heyvm/env ] && . /etc/heyvm/env; set +a; exec /usr/local/bin/heyvmd --api-port 34099'
directory=/var/lib/heyvm
user=root
environment=
PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
HOME="/var/lib/heyvm",
MVM_DATA_DIR="/var/lib/heyvm"
autostart=true
autorestart=true
stopsignal=TERM
stopwaitsecs=15
stopasgroup=true
killasgroup=true
redirect_stderr=true
stdout_logfile=/var/log/heyvmd/heyvmd.log
Check it answers (a 401 is fine when an operator key is set):
curl -s -o /dev/null -w '%{http_code}\n' http://127.0.0.1:34099/deployed-sandboxes
heyvmd resolves image names under its own data directory. If app-lb builds or
pulls images, point both at the same directory: set MVM_DATA_DIR on both
processes and APP_LB_IMAGES_DIR=<MVM_DATA_DIR>/images/firecracker on app-lb,
or set APP_LB_HEYVM_HOME to heyvmd's home when app-lb can write it.
2. heyosecret
Create a PostgreSQL database and role, then install:
curl -fsSL https://get.us2.heyo.work/install-apps.sh | sudo sh -s -- heyosecret
sudo useradd --system --no-create-home --shell /usr/sbin/nologin heyosecret
sudo install -d -o heyosecret -g heyosecret /var/lib/heyosecret /var/log/heyosecret
The installer puts migrations in /var/lib/heyosecret/migrations, which is
where the shipped unit's HEYOSECRET_MIGRATIONS_DIR points. Edit
/etc/supervisor/conf.d/heyosecret.conf and replace every change-me:
| Variable | Meaning |
|---|---|
HEYOSECRET_DATABASE_URL |
PostgreSQL URL |
HEYOSECRET_INTERNAL_API_KEY |
Machine API key |
HEYOSECRET_MASTER_KEY |
At least 32 bytes; derives the value-encryption key. Losing it loses every stored value |
HEYOSECRET_ADMIN_PASSWORD |
Dashboard password. Mutually exclusive with HEYOSECRET_DASHBOARD_GATE=1 |
Instead of putting secrets in the unit, you can point
HEYOSECRET_CONFIG_PATH at a 0600 TOML file. See heyosecret.
3. art
curl -fsSL https://get.us2.heyo.work/install-apps.sh | sudo sh -s -- art
Every app-lb host needs the art binary, even if the store runs elsewhere:
app-lb runs it as a subprocess to restore and capture workspaces. Without it, a
deployment whose vm.workspace.store is a local path holds its pool at zero
replicas with workspace restore pending: could not run art.
To run a store, start art serve under your process manager:
| Variable | Default | Meaning |
|---|---|---|
ART_ROOT |
~/.artifacts |
Store root |
ART_LISTEN |
127.0.0.1:8080 |
Listen address |
ART_API_KEY |
(unset: every route open) | Bearer / X-Api-Key secret. /healthz is always open |
ART_READ_ONLY |
off | Refuse every mutating route |
ART_ADMIN_USER / ART_ADMIN_PASSWORD |
admin / unset |
Dashboard login. No password, no dashboard |
ART_DASHBOARD_GATE |
off | Trust identity forwarded by app-lb instead of a local login |
art ships no supervisor file. See artifacts for running it
as an app-lb deployment instead.
4. app-lb
curl -fsSL https://get.us2.heyo.work/install-apps.sh | sudo sh -s -- app-lb
sudo useradd --system --no-create-home --shell /usr/sbin/nologin app-lb
sudo install -d -o app-lb -g app-lb /var/lib/app-lb /var/log/app-lb
sudo install -d -m0700 -o app-lb -g app-lb /var/lib/app-lb/acme
This installs app-lb and heyctl. Edit /etc/supervisor/conf.d/app-lb.conf:
| Variable | Shipped value | Change it to |
|---|---|---|
APP_LB_DASHBOARD_PASSWORD |
change-me |
A real password. Required when APP_LB_ADMIN_AUTH=1 |
APP_LB_PROXY_ADDR |
0.0.0.0:6188 |
0.0.0.0:80 if app-lb is the public ingress |
APP_LB_ART_BIN |
(unset) | /usr/local/bin/art |
APP_LB_ACME_EMAIL |
(unset) | Your contact, to enable automatic certificates |
APP_LB_PROXY_TLS_ADDR |
(unset; default 0.0.0.0:6189) |
0.0.0.0:443 with ACME |
APP_LB_DAEMON_API_KEY |
(unset) | heyvmd's operator key, if it has one |
APP_LB_OBS_URL |
(unset) | app-obs ingest base URL, once app-obs is up |
Binding :80/:443 as a non-root user needs
sudo setcap 'cap_net_bind_service=+ep' /usr/local/bin/app-lb. ACME validates
HTTP-01 on port 80 only, so automatic certificates need the proxy on :80.
Test against Let's Encrypt staging first with
APP_LB_ACME_DIRECTORY=https://acme-staging-v02.api.letsencrypt.org/directory.
If the host builds images, add the service user to the docker group, give it
a real home directory (sudo install -d -o app-lb -g app-lb /home/app-lb), and
restart the program (not just reread) so it picks up the group.
Start it and log in:
sudo supervisorctl reread && sudo supervisorctl update
curl -s http://127.0.0.1:9090/healthz
heyctl login --server http://127.0.0.1:9090 --user admin --password-stdin --name local
heyctl status
The full configuration reference is in app-lb; sign-in options are in app-lb auth.
5. app-obs
curl -fsSL https://get.us2.heyo.work/install-apps.sh | sudo sh -s -- app-obs
sudo useradd --system --no-create-home --shell /usr/sbin/nologin app-obs
sudo install -d -o app-obs -g app-obs /var/lib/app-obs /var/log/app-obs
The shipped unit sets APP_OBS_DATA_DIR=/var/lib/app-obs/data and
APP_LB_URL=http://127.0.0.1:9090. If app-lb's admin API requires auth, add
APP_LB_USER and APP_LB_PASSWORD. Set APP_OBS_API_TOKEN to gate the query
API, and APP_OBS_INGEST_TOKEN to gate ingest.
Then point app-lb at it and restart app-lb:
APP_LB_OBS_URL="http://127.0.0.1:9500",
APP_LB_OBS_TOKEN="<same value as APP_OBS_INGEST_TOKEN, if set>"
app-lb appends /ingest itself. Leave stopwaitsecs above 30 so app-obs can
flush buffered records on shutdown. See app-obs.
6. ci
ci needs PostgreSQL, a NATS server with JetStream, and heyvm runner hosts that belong to a heyvm network.
curl -fsSL https://get.us2.heyo.work/install-apps.sh | sudo sh -s -- ci
sudo useradd --system --no-create-home --shell /usr/sbin/nologin ci
sudo install -d -o ci -g ci /var/lib/ci /var/lib/ci/logs /var/lib/ci/workspaces /var/lib/ci/artifacts
Replace every REPLACE-ME in /etc/supervisor/conf.d/ci.conf. ci refuses to
start without CI_HEYO_API_KEY, CI_NETWORK, CI_DATABASE_URL, and
CI_WEBHOOK_SECRET (at least 16 characters). Migrations are compiled into the
binary; leave CI_MIGRATIONS_DIR unset. Remember the port 9500 overlap with
app-obs. See ci.
7. Optional services
- pg-fc —
sudo sh .ci/install.sh pg-fc(from your own store) or build from source. The pooler listens onPG_VM_POOL_LISTEN(default127.0.0.1:6432) and drives heyvmd on the same host. The repo shipspg-fc/deploy/supervisor/pg-vm-pool.confand a systemd templatepg-fc/deploy/pg-fc@.service. See pg-fc. - queue — install only on the host that runs
nats-server. Defaults:QUEUE_NATS_MONITOR_URL=http://127.0.0.1:8222,QUEUE_API_ADDR=127.0.0.1:9700. See queue. - mcp — build
mcp/with npm and runnode dist/index.js. SetHEYO_MCP_HTTP_PORTfor HTTP mode;mcp/deploy/supervisor/heyo-mcp.conflists the service URLs and tokens it reads. See mcp.
Shipped supervisor files
| File | Program | Runs as | Directories to create |
|---|---|---|---|
app-lb/deploy/supervisor/app-lb.conf |
app-lb |
app-lb |
/var/lib/app-lb, /var/log/app-lb |
app-obs/deploy/supervisor/app-obs.conf |
app-obs |
app-obs |
/var/lib/app-obs, /var/log/app-obs |
ci/deploy/supervisor/ci.conf |
ci |
ci |
/var/lib/ci |
heyosecret/deploy/supervisor/heyosecret.conf |
heyosecret |
heyosecret |
/var/lib/heyosecret, /var/log/heyosecret |
queue/deploy/supervisor/queue.conf |
queue |
queue |
/var/lib/queue, /var/log/queue |
pg-fc/deploy/supervisor/pg-vm-pool.conf |
pg-vm-pool |
see file | see file |
pg-fc/deploy/supervisor/heyvmd.conf |
heyvmd |
see file | see file |
mcp/deploy/supervisor/heyo-mcp.conf |
heyo-mcp |
see file | /var/log/heyo-mcp |
All of them use autorestart=unexpected or true with bounded
startretries, so a startup misconfiguration ends in FATAL rather than a
crash loop. Read the reason with supervisorctl tail <program> stderr.
Firewall and tap interfaces
app-lb reaches each guest at its guest IP over the host's tap interface. A host
firewall that rejects forwarded or tap traffic makes every VM look permanently
unhealthy. ping may still work, because ufw allows ICMP echo while rejecting
TCP, which shows up as No route to host. If health checks never go green,
check the firewall first:
sudo ufw status
sudo ufw allow in on tap-fc-+ # or scope to the guest subnet
Open to the internet only what should be public: app-lb's proxy ports. Keep the app-lb admin API, heyvmd, art, heyosecret, and app-obs's query API on loopback or a private network, and expose them through app-lb deployments with auth when people need them.
First deployment
With heyvmd and app-lb running and heyctl logged in, register a managed VM
deployment built from a git repository that contains a Dockerfile. The service
in the image must listen on the port you give and answer the health path.
heyctl create deployment hello \
--host hello.example.com \
--repo https://github.com/<you>/hello.git --ref main \
--port 8080 --health-path / \
--min 1 --max 2
heyctl build hello --wait --logs # build the guest image and roll the pool onto it
heyctl rollout status hello # wait for the pool to be at size and healthy
heyctl describe hello # spec, pool, backends, traffic
--dry-run on create deployment prints the spec without sending it. For a
private repository, store a token first with heyctl create secret and pass
--secret NAME[/KEY].
Send a request through the proxy:
curl -H 'Host: hello.example.com' http://127.0.0.1:6188/
Once DNS for hello.example.com points at the host and ACME is configured,
the same request works over HTTPS with a Let's Encrypt certificate.
The same deployment as a spec file, which you can keep in git and apply with
heyctl apply -f hello.json:
{
"id": "hello",
"routes": [{ "host": "hello.example.com" }],
"vm": { "driver": "firecracker", "image": "hello", "port": 8080, "size_class": "mini" },
"build": { "repo": "https://github.com/<you>/hello.git", "ref": "main", "dockerfile": "Dockerfile" },
"scaling": { "min_replicas": 1, "max_replicas": 2 },
"health": { "path": "/", "timeout_secs": 2 }
}
app-lb/examples/ has specs for static sites, agent sandboxes, artifact
pulls, and the HWS services themselves. The spec reference is in
app-lb; the CLI is in heyctl.
heyctl on a workstation
To manage an app-lb from your own machine, install only heyctl:
curl -fsSL https://heyo.computer/heyctl/install.sh | sh
curl -fsSL https://heyo.computer/heyctl/install.sh | sh -s -- --prefix /usr/local
| Option / variable | Default | Meaning |
|---|---|---|
--prefix PATH / HEYCTL_PREFIX |
~/.local |
Install into PATH/bin |
--version VER / HEYCTL_VERSION |
manifest latest |
Version to install |
--digest SHA256 / HEYCTL_DIGEST |
Install this exact blob; skip the manifest | |
--list |
Show available versions | |
HEYCTL_BASE_URL |
https://heyo.computer |
Site serving heyctl/versions.json |
HEYCTL_MANIFEST_URL |
Full manifest URL; overrides HEYCTL_BASE_URL |
|
HEYCTL_STORE_URL |
manifest store |
Artifact store base |
Then heyctl login --server https://admin.<your-domain>.
Publishing your own releases
If you run your own CI and artifact store, publish keyless manifests for your
hosts with .ci/publish-releases.sh:
ART_URL=https://art.example.com ART_API_KEY=... \
sh .ci/publish-releases.sh --all --from-url https://get.example.com --push-tag releases-live
| Option | Meaning |
|---|---|
--all / app... |
Which apps to publish |
--out DIR |
Output directory. Default ./releases |
--from-url URL / --from DIR |
Merge into existing manifests so pinned versions keep installing |
--ref APP=TAG |
Publish this exact build |
--keep N |
Keep at most N versions per app and platform |
--push-tag TAG |
Upload the directory to the store as one public bundle and move TAG to it |
--dry-run |
Resolve and verify; write nothing |
The output holds one <app>.json per app, index.json, and copies of
install-apps.sh and bootstrap-host.sh. Serve it with an app-lb site
deployment that follows the pushed tag (app-lb/examples/releases-site.json),
then heyctl pull <deployment> to make it live. Anonymous downloads also need
the store's gate to leave /blobs/ public (app-lb/examples/artifacts-gated.json).
Upgrades and rollback
- Re-run the installer. Binaries are replaced by rename, so running processes keep the old inode until restarted.
- Supervisor files are never overwritten. Diff
<app>.conf.newagainst your file and merge new settings. - Restart explicitly (
supervisorctl restart <app>) or pass--restart. - Roll back with
install-apps.sh --version APP=VERor.ci/install.sh --ref <tag> <app>. APP_LB_STATE_PATHholds every registered deployment. Keep it on persistent disk and back it up.- Run only one app-lb per heyvmd. Two app-lbs sharing a daemon each see the
other's VMs as orphans. app-lb takes a host-wide instance lock by default
(
APP_LB_INSTANCE_LOCK; a path, oroff), so a second instance refuses to start. Leave it on.app-lbwith no arguments starts a full instance; only--versionand--helpare safe to run by hand on a live host.
Troubleshooting
| Symptom | Check |
|---|---|
/dev/kvm is missing |
Enable virtualisation in firmware, or nested virtualisation on the hypervisor |
app-lb FATAL right after start |
supervisorctl tail app-lb stderr. Common causes: only one of APP_LB_TLS_CERT/APP_LB_TLS_KEY, APP_LB_ADMIN_AUTH=1 with no password, or a listen address already in use |
Pool stays at zero with could not run art |
Set APP_LB_ART_BIN=/usr/local/bin/art and install art on the app-lb host |
| Build fails on the docker socket | Add the service user to docker, give it a home directory, restart the program |
| Build succeeds but the VM never boots | app-lb and heyvmd disagree on the image directory; share MVM_DATA_DIR and set APP_LB_IMAGES_DIR |
| VMs never go healthy | Firewall on the tap interfaces; the health path and port in the spec |
install-apps.sh: store refused an anonymous download |
The blob is not public, or a gate in front of the store requires login for /blobs/ |
install.sh: no builds found |
ART_URL/ART_API_KEY, and that CI has published under ci-<workflow>-... tags |
ci or app-obs fails to bind :9500 |
Both default to 9500; move one |