Try Kibotos on a single machine
This page shows how to install ctrl and node on one Linux machine, together with the PostgreSQL database and object storage they depend on, then build a Template and create your first Workspace. Apart from the downloads, the steps take about fifteen minutes. Use it to evaluate Kibotos before a full deployment.
A deployment installed this way is only suitable for evaluation: all components listen only on the local machine, the object storage uses the administrator credential directly, and all data lives on this one machine. For a production deployment, see Installation overview.
Overview
After installation, this machine runs:
| Component | Source | Listens on |
|---|---|---|
| PostgreSQL | Distribution package | 127.0.0.1:5432 |
| Silo, an S3-compatible object storage | Debian package released by Silo | 127.0.0.1:9000 |
| ctrl | kibotos-ctrl from the release set | 127.0.0.1:18092 (API), 127.0.0.1:18101 (node access) |
| node, using the KiboVM backend | kibotos-node from the release set | 127.0.0.1:18091 (data plane) |
kibo and kibo-build | Release set | Does not listen |
Certificates for ctrl and node are issued for names. This page writes the two names ctrl.kibotos.test and node-a.nodes.kibotos.test into /etc/hosts, both pointing to 127.0.0.1. kibo also runs on this machine.
Prerequisites
- A Debian 13 amd64 machine, on which this page was verified. At least 4 CPUs, 8 GiB of memory, and 40 GiB of free disk space.
/dev/kvmand/dev/net/tunexist, cgroup v2 is in use, and time synchronization is on. To try it in a virtual machine, enable nested virtualization.- You can use
sudoand reach the public internet, to download the release set, Silo, and the container image for the Template. - The release set is downloaded from GitHub, which requires a GitHub account with read access to the Kibotos source repository.
- Docker is not running on this machine. Docker changes the default policy of the
FORWARDchain toDROP, and Workspaces then cannot reach the network. See Troubleshooting.
Run the steps below in order in the same terminal. Later steps use variables set in earlier ones.
Steps
1. Check the host
Confirm the virtualization devices, cgroup version, and time synchronization:
ls -l /dev/kvm /dev/net/tun
stat -fc %T /sys/fs/cgroup
timedatectl show -p NTPSynchronizedThe second command should print cgroup2fs, and the third should print NTPSynchronized=yes.
2. Download the release set
Install the tools you need, log in to GitHub, then download and verify the release set of one version. Replace version with the version you want to try:
sudo apt-get install -y gh jq curl openssl
version=1.2.3
gh auth login
gh api -H 'Accept: application/vnd.github.raw' \
"repos/felinics/kibotos/contents/scripts/fetch-release.sh?ref=v$version" > fetch-release.sh
bash fetch-release.sh "v$version"
cd "kibotos-releases/v$version"
sha256sum --check SHA256SUMSRun all later commands in this directory.
3. Install PostgreSQL and Silo
Install PostgreSQL and create an account and a database for ctrl:
sudo apt-get install -y postgresql
db_password=$(openssl rand -hex 16)
sudo -u postgres psql -c "CREATE ROLE kibotos LOGIN PASSWORD '$db_password'"
sudo -u postgres createdb -O kibotos kibotosDownload and install Silo, have it listen only on the local machine, and keep its data in /var/lib/silo:
silo_release=https://github.com/pgsty/silo/releases/download/RELEASE.2026-09-16T00-00-00Z
curl -fLO "$silo_release/silo_20260916000000.0.0-1PGSTY_amd64.deb"
curl -fLO "$silo_release/silo_20260916000000.0.0-1PGSTY_amd64.deb.sha256sum"
sha256sum --check silo_20260916000000.0.0-1PGSTY_amd64.deb.sha256sum
sudo apt-get install -y ./silo_20260916000000.0.0-1PGSTY_amd64.deb
silo_password=$(openssl rand -hex 16)
sudo install -d -o silo -g silo -m 0700 /var/lib/silo
sudo install -m 0600 /dev/null /etc/default/silo
sudo tee /etc/default/silo >/dev/null <<EOF
MINIO_VOLUMES="/var/lib/silo"
MINIO_OPTS="--address 127.0.0.1:9000 --console-address 127.0.0.1:9001"
MINIO_ROOT_USER="kibotos"
MINIO_ROOT_PASSWORD="$silo_password"
EOF
sudo systemctl enable --now silo.serviceCreate the bucket that ctrl uses. curl calls the Silo API directly with an S3 signature:
until curl -fsS http://127.0.0.1:9000/minio/health/live; do sleep 1; done
curl -fsS --aws-sigv4 'aws:amz:us-east-1:s3' --user "kibotos:$silo_password" \
-X PUT http://127.0.0.1:9000/kibotos-artifacts4. Prepare names
Point the ctrl and node names to the local machine:
printf '%s\n' '127.0.0.1 ctrl.kibotos.test node-a.nodes.kibotos.test' | sudo tee -a /etc/hosts >/dev/null
getent hosts ctrl.kibotos.test node-a.nodes.kibotos.test5. Install and start ctrl
Install the ctrl package and write the configuration:
sudo apt-get install -y "./kibotos-ctrl_${version}_amd64.deb"
sudo install -o kibotos-ctrl -g kibotos-ctrl -m 0600 /dev/null /etc/kibotos/ctrl/config.toml
sudo tee /etc/kibotos/ctrl/config.toml >/dev/null <<EOF
[database]
dsn = "postgresql://kibotos:$db_password@127.0.0.1:5432/kibotos"
[identity]
trust_domain = "kibotos.test"
host = "ctrl.kibotos.test"
[storage]
root = "/var/lib/kibotos/ctrl"
[api]
listen = "127.0.0.1:18092"
[node_api]
listen = "127.0.0.1:18101"
[data_plane]
host_suffix = "nodes.kibotos.test"
[template_artifact_store]
endpoint = "127.0.0.1:9000"
region = "us-east-1"
bucket = "kibotos-artifacts"
namespace = "trial"
secure = false
path_style = true
credential_source = "static"
access_key_id = "kibotos"
secret_access_key = "$silo_password"
EOFInitialize ctrl, issue the enrollment key for the first Operator, then start the service:
sudo -u kibotos-ctrl kibotos-ctrl init --config /etc/kibotos/ctrl/config.toml
sudo -u kibotos-ctrl kibotos-ctrl migrate --config /etc/kibotos/ctrl/config.toml
sudo -u kibotos-ctrl kibotos-ctrl enrollment create \
--config /etc/kibotos/ctrl/config.toml --operator admin \
--output /var/lib/kibotos/ctrl/operator-enrollment.key
sudo systemctl enable --now kibotos-ctrl.service6. Install kibo and enroll
Install kibo and create the Operator identity with the key from the previous step:
sudo install -m 0755 "kibo_${version}_linux_amd64" /usr/local/bin/kibo
(umask 077; sudo cat /var/lib/kibotos/ctrl/operator-enrollment.key > operator-enrollment.key)
sudo rm /var/lib/kibotos/ctrl/operator-enrollment.key
kibo context enroll --endpoint https://ctrl.kibotos.test:18092 --key-file operator-enrollment.key
rm operator-enrollment.key
kibo versionThe output of kibo version should contain Compatible yes.
7. Install node and join
Issue an enrollment key for the node, install the node package, and turn on IPv4 forwarding:
kibo enrollment create --node node-a --output node-enrollment.key
sudo apt-get install -y "./kibotos-node_${version}_amd64.deb"
printf '%s\n' 'net.ipv4.ip_forward = 1' | sudo tee /etc/sysctl.d/60-kibotos-forward.conf >/dev/null
sudo sysctl -p /etc/sysctl.d/60-kibotos-forward.confWrite the node configuration. It gives Workspaces 2 CPUs and 4 GiB of memory, and reaches the public internet through the network interface of the default route:
uplink=$(ip -4 route show default | awk '{print $5; exit}')
sudo install -m 0600 /dev/null /etc/kibotos/node/config.toml
sudo tee /etc/kibotos/node/config.toml >/dev/null <<EOF
[backend]
type = "kibovm"
[resources]
cpu_limit = 2
memory_limit = "4G"
[storage]
root = "/var/lib/kibotos/node"
template_cache_limit = "10G"
[[storage.pool]]
id = "node-a"
path = "/var/lib/kibotos/node"
[runtime]
socket_root = "/run/kibotos/node"
[data_plane]
listen = "127.0.0.1:18091"
advertise = "https://node-a.nodes.kibotos.test:18091"
[ctrl]
endpoint = "https://ctrl.kibotos.test:18101"
[host_network]
address_families = ["ipv4"]
ipv4_pool = "100.64.0.0/16"
[host_network.public_internet]
ipv4_upstream_interface = "$uplink"
resolvers = ["1.1.1.1"]
EOFInitialize the storage pool, join the cluster, and start the service:
sudo kibotos-node storage-pool init --id node-a --path /var/lib/kibotos/node
sudo kibotos-node join --config /etc/kibotos/node/config.toml --key-file node-enrollment.key
rm node-enrollment.key
sudo systemctl enable --now kibotos-node.serviceWait for the node to become READY, then set the capacity of its storage pool:
until kibo node get node-a | grep -q READY; do sleep 2; done
kibo storage-pool set-capacity node-a 20G
kibo node list8. Publish a Platform
A Platform is the kernel and guest programs that a Workspace boots with. The release set already contains a built one. Publish it, approve it, and set it as the default:
kibo platform publish "kibotos-platform-kibovm_v${version}_amd64.tar.zst" --json > platform.json
platform_revision=$(jq -er '.result.platform.revision' platform.json)
kibo platform approve "$platform_revision"
kibo platform set-default "$platform_revision"9. Build and publish a Template
A Template determines what is installed in a Workspace. Here you import a Debian system with curl from the official Docker Hub image buildpack-deps:trixie-curl. Install the build tool, look up the exact digest of the image, and write the definition file:
sudo apt-get install -y "./kibo-build_${version}_amd64.deb"
digest=$(skopeo inspect --format '{{.Digest}}' docker://docker.io/library/buildpack-deps:trixie-curl)
sudo install -d /srv/templates/debian
sudo tee /srv/templates/debian/template.json >/dev/null <<EOF
{
"schema": "kibotos.template-definition/v1",
"template_id": "debian",
"display_name": "Debian 13 with curl",
"description": "Imported from docker.io/library/buildpack-deps:trixie-curl",
"platform": "linux/amd64",
"architecture": "x86_64",
"source": {
"kind": "registry",
"reference": "docker.io/library/buildpack-deps@$digest"
},
"platform_requirements": {
"guest_protocol": 1,
"rootfs_contract": 2
},
"guest": {
"capabilities": ["filesystem.v1", "process.v1", "application-config.v1"],
"ready_semantics": "vsock-http-ready/v1"
},
"required_capabilities": {},
"rootfs": {
"size_mib": 1024
},
"process_defaults": {
"shell": "/bin/bash"
}
}
EOFBuild it, then publish, approve, and set it as the default:
template_result=$(sudo kibo-build template /srv/templates/debian/template.json)
kibo template publish "$template_result" --json > template.json
template_revision=$(jq -er '.result.template.revision' template.json)
kibo template approve debian --revision "$template_revision"
kibo template set-default debian --revision "$template_revision"
kibo template list10. Create your first Workspace
Create a Workspace, run a command in it, then delete it:
workspace_id=$(kibo workspace create --template debian -q)
kibo workspace exec "$workspace_id" -- cat /etc/debian_version
kibo workspace delete "$workspace_id" --yesThe first time a Template is used, the node must download and unpack the rootfs first, so creation takes a little longer.
The deployment is now ready to use. Continue from step 3 of the Quickstart, using the Template debian.
Notes
- All components listen only on
127.0.0.1, so you can usekiboonly on this machine. To access it from another machine, change the listen addresses in the configuration to0.0.0.0, and have that machine resolve the two names to this machine's address. Publishing a Template uploads straight to object storage, so also make Silo listen on a reachable address and set the storeendpointin the ctrl configuration to it. - The object storage uses the Silo administrator credential. In a production deployment, give ctrl an identity that can access only its own bucket. See Prepare the bucket and permissions.
- All data lives only on this machine, with no backup. The ctrl PKI is in
/var/lib/kibotos/ctrl. If you lose it, all nodes and Operators must enroll again. - A production deployment can put ctrl and node on different machines. Follow the order in Installation overview.
Troubleshooting
| Symptom | Cause | Resolution |
|---|---|---|
kibotos-ctrl.service restarts repeatedly | The database or object storage is unreachable, or the credentials are wrong | Look at sudo journalctl -u kibotos-ctrl.service -n 50. The reason field says which one |
The node never becomes READY | The node did not start, or cannot reach ctrl | Look at sudo journalctl -u kibotos-node.service -n 50 |
| Creating a Workspace fails | The storage pool capacity is not set yet, or the Platform or Template is not set as the default | Following the error message, redo the last part of step 7, or steps 8 and 9 |
The node log has node offers no public internet egress | IPv4 forwarding is not on, or the default policy of the FORWARD chain is DROP (for example, because Docker is installed) | Fix the cause stated in the log, then run sudo systemctl restart kibotos-node.service |
kibo-build fails to download the image | This machine cannot reach Docker Hub | Use a registry the machine can reach, and change reference in the definition file to the image there |
Uninstall
Stop the services, remove the packages, then delete the data created on this page:
sudo systemctl disable --now kibotos-node.service kibotos-ctrl.service silo.service
sudo apt-get purge -y kibotos-node kibotos-ctrl kibo-build silo
sudo rm -rf /etc/kibotos/node /etc/kibotos/ctrl /var/lib/kibotos/node /var/lib/kibotos/ctrl \
/var/lib/kibotos/build /var/lib/silo /etc/default/silo /srv/templates/debian \
/etc/sysctl.d/60-kibotos-forward.conf
sudo -u postgres dropdb kibotos
sudo -u postgres dropuser kibotos
sudo sed -i '/ctrl\.kibotos\.test/d' /etc/hosts
rm -rf ~/.config/kibo/contextNext steps
- Quickstart: run commands, transfer files, open a terminal, and access the network.
- Build your own Template: build from other images or a Containerfile.
- Installation overview: the machines, external dependencies, and prerequisites of a production deployment.