Install with packages
The control plane and each data node as apt or dnf packages, from the files we send you or from the signed repository.
Two packages, runlot-cp and runlot-node, and a third, runlot-eval, that pulls both onto one machine with PostgreSQL and MinIO beside them. Every package carries the same install core, runlot-admin, which checks the machine, writes the configuration, and starts the services. The postinstall is that command; nothing happens in shell that you could not run yourself.
The repository
curl -fsSL https://packages.runlot.io/gpg/runlot-archive-keyring.gpg \
| sudo tee /usr/share/keyrings/runlot.gpg >/dev/null
echo "deb [signed-by=/usr/share/keyrings/runlot.gpg] https://<token>@packages.runlot.io/deb stable main" \
| sudo tee /etc/apt/sources.list.d/runlot.list
sudo apt updatesudo tee /etc/yum.repos.d/runlot.repo <<'EOF'
[runlot]
name=Runlot
baseurl=https://<token>@packages.runlot.io/rpm/el/x86_64
gpgcheck=1
gpgkey=https://packages.runlot.io/gpg/runlot-archive-keyring.gpg
EOF<token> comes with your licence. It decides who may download and nothing else: a package copied to a machine with no token installs the same way. Until the repository host is in service, we send the packages as a signed bundle instead, and the steps below are the same from the install line on. See Air-gap for checking the bundle.
The control plane
Put your values in site.env
sudo mkdir -p /etc/runlot/license
sudo cp license /etc/runlot/license/license
sudo apt download runlot-cp && sudo dpkg --unpack runlot-cp_*.deb # unpacks the example without configuring
sudo cp /usr/share/runlot/site.env.cp-example /etc/runlot/site.env
sudo chmod 0640 /etc/runlot/site.env
sudoedit /etc/runlot/site.envThe example is annotated. These are the keys with no default, and the only ones you must set:
| Key | What it is |
|---|---|
RUNLOT_MASTER_KEY | openssl rand -hex 32. We have no copy. |
RUNLOT_DATABASE_URL | your PostgreSQL 18, as the role that owns the database |
RUNLOT_OBJSTORE_ENDPOINT, _BUCKET, _ACCESS_KEY_ID, _SECRET_ACCESS_KEY | your object store |
RUNLOT_CP_PRIVATE_ADDR | the private address the nodes reach the control plane at |
RUNLOT_PUBLIC_URL, RUNLOT_ADMIN_HOST | the dashboard's origin and host |
RUNLOT_ADMIN_EMAILS | the platform operators. The first address is also the only one allowed to sign up without an invitation. |
RUNLOT_APP_DOMAIN, RUNLOT_WIRE_DOMAIN, RUNLOT_GIT_DOMAIN | your names from Requirements |
Install
sudo apt install runlot-cpsudo dnf install runlot-cpThe postinstall runs runlot-admin preflight cp, then runlot-admin install cp, then starts the services. It prints the dashboard URL and the join token for the nodes.
If a check fails, it fails before anything is changed and names the value. Fix site.env and resume:
sudo dpkg --configure -asudo /opt/runlot/bin/runlot-admin install cp --etc /etc/runlot --state /var/lib/runlotThe two differ because a failing rpm postinstall does not abort the transaction. On RHEL the package is installed and nothing is running, and the install core is run again by hand.
Each data node
Put your values in site.env
sudo cp /usr/share/runlot/site.env.node-example /etc/runlot/site.env
sudoedit /etc/runlot/site.env| Key | What it is |
|---|---|
RUNLOT_NODE_ID | unique in the installation; the certificate and the lease carry it |
RUNLOT_CP_PRIVATE_ADDR | the control plane's private address |
RUNLOT_NODE_JOIN_TOKEN | printed by the control plane's postinstall |
RUNLOT_PRIVATE_ADDR | this machine's private address |
RUNLOT_FRONT_TLS_CERT, _KEY | your *.apps certificate, or leave RUNLOT_FRONT_TLS_ADDR empty and terminate in your own proxy |
RUNLOT_WIRE_HOSTS | the names on the wire certificate: *.wire.acme.example,*.apps.acme.example |
Install
sudo apt install runlot-node # or: sudo dnf install runlot-nodeThe join token authenticates exactly two calls: one that fetches the CA certificate and the shared values a node cannot derive, and one that enrols the node's own certificate from a key generated on the node. The CA private key never leaves the control plane, and nothing is copied between machines by hand.
The runtime artifact, the sandbox every project runs in, is inside the package. It is about 1 GB, which is why the node package is large.
Declare where the node is
A node never asserts its own region or country: registration is authenticated by the node, so a node declaring its own jurisdiction would be asserting the fact that constrains it. You declare it from the control plane once the node has registered:
sudo /opt/runlot/bin/runlot-admin bootstrap --nodes node-1=icn/KR/do,node-2=fsn/DEdo marks a node able to hold Durable Objects. A project's first Durable Object deploy is refused until every active node is declared.
The eval machine
sudo cp /usr/share/runlot/eval-site.env /etc/runlot/site.env
sudoedit /etc/runlot/site.env # the master key; the join token after the control-plane half installs
sudo apt install runlot-evalIt depends on runlot-cp, runlot-node and the distribution's postgresql-18, and ships a MinIO unit. The MinIO binary is not redistributed: it is AGPL and the download is yours. Put it at /opt/runlot/bin/minio and systemctl enable --now minio; the postinstall says this when the file is absent.
One machine, one disk, loopback everything. It is not a production shape.
First login
- An address in
RUNLOT_ADMIN_EMAILSsigns up with email and password at the dashboard URL. Under the defaultRUNLOT_SIGNUP=invite, that is the only sign-up allowed; everyone else is invited from the dashboard. - The operations console is the same origin split by Host,
RUNLOT_ADMIN_HOST. There is no second address. - Point the CLI at your installation and deploy something:
runlot login --api https://runlot.acme.example
npm create runlot@latest hello && cd hello && runlot deployThe project limits of the public plans do not apply. The only project ceiling on a self-hosted installation is the licence's max_projects, and the default is none.