Skip to main content

Quickstart

The shortest path from nothing to a running app: install the CLI, sign in, get a cluster, deploy from your project directory, get the URL. Every command below is real.

Install the CLI

Install the RunOS CLI, then pull the command manifest:

curl -fsSL https://get.runos.com/cli.sh | bash
runos manifest update

runos manifest update downloads the latest command set from the API. The CLI is manifest-driven, so do this once after install and after upgrades.

Sign in

A personal access token (PAT) and every command are scoped to one account id (aid), for example rjwrn. Sign in with the browser flow:

runos login --account-id rjwrn

For CI or headless use, pass a PAT instead of the browser flow:

runos login --api-key runos_pat_<keyId>.<secret> --account-id rjwrn

--account-id is required with --api-key. Credentials are stored in ~/.runos/config.json. The RUNOS_API_KEY environment variable overrides the stored key (setting it to an empty value is a hard error, not a fallback).

Pick a default cluster so you can drop --cid from later commands:

runos config set cid ky3

Get a cluster (provision a cloud node OR install your own server)

A RunOS cluster is one or more Linux nodes running Kubernetes. You need at least one node. Create the cluster first:

runos clusters add --name my-cluster

This gives the cluster a cluster id (cid): 3 to 16 lowercase alphanumeric characters (for example ky3). Run runos clusters list to see it. You pass it to later commands as --cid. Then get a node into it one of two ways.

Option A: provision a cloud node

RunOS can provision a node on hetzner, digitalocean, or scaleway. Each needs an integration (your provider API token) added once:

runos integrations add hetzner
runos integrations list

Then provision the node and auto-configure the cluster for app deployment in one step:

runos integrations hetzner add-server \
--cid ky3 \
--integration-id <integration-id> \
--request-as-cp \
--auto-configuration configureForDeployment \
--follow

--auto-configuration configureForDeployment installs the full deployment stack (MinIO, PostgreSQL, Valkey, Harbor, plus build config) once the server joins. Use --provider-config.instance-type and --provider-config.location to size and place it (see runos integrations info).

Option B: install RunOS on your own server

Have an Ubuntu 22.04, 24.04, or 26.04 server with a public IP? Generate a join command and run it on that server:

runos nodes join-command ssh-remote --cid ky3 --request-as-cp

Run the printed command on your server. After it joins, install the deployment stack:

runos clusters configure-for-deployment --cid ky3

One node is fine to start, but a single node is not highly available. Add more nodes later with the same commands.

Confirm the node is ready:

runos nodes list --cid ky3
NAME         HOSTNAME       STATUS  ISCP  ISWORKER  PUBLICIP        PROVIDER
web-01 node-1 ready true true 203.0.113.10 hetzner

Write runos.yaml

runos.yaml is the desired state for your app: name, ports, resources. RunOS reads it from the current directory at deploy time. The minimum is a name, one port, and a resource class:

app: hello-runos
servicePortMappings:
- port: 8080
standardHttps: true
resourceRequirementClassId: app.sl1.beff

port must match the port your container listens on. standardHttps: true puts the app behind the cluster's HTTPS ingress with a default domain. app.sl1.beff is the standard small app resource class (grammar is service.tier.size); leave cpu, memory, and replicas unset to use the class defaults.

Add a Dockerfile

RunOS builds your image from a Dockerfile in the project directory. RunOS clusters run every container as non-root, so the contract is:

  • Run as a non-root user: USER 10001.
  • Listen on a port above 1024 that matches servicePortMappings.port (here, 8080).
  • Keep the build reproducible (pin a base image tag, install from a lockfile).

A minimal Node example:

FROM node:22-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --omit=dev
COPY . .
USER 10001
EXPOSE 8080
CMD ["node", "server.js"]

For a static site, use nginxinc/nginx-unprivileged:1.27-alpine (it listens on 8080 as a non-root user) instead of nginx:alpine, which binds port 80 and needs root.

Deploy

From the project directory (the one holding runos.yaml and your Dockerfile):

runos deploy --follow

runos deploy tarballs the project, uploads it, and RunOS builds the image in-cluster. No local Docker, no git push required. --follow streams the build and rollout until done; without it, deploy prints a job id and returns immediately. Add --cid <cid> to target a cluster other than your default.

Check status and get the URL

List your apps to get the 5-character app id and status:

runos apps list --cid ky3

Watch deploy jobs:

runos jobs list --cid ky3

Once rolled out, get the live URL:

runos apps network-access <app-id> --cid ky3

That command prints the HTTPS URL serving your app. Open it and you are live.

Next steps

  • Add a managed service (PostgreSQL, Valkey, MinIO, Kafka, and more) with runos services and wire it into your app via requires:.
  • Deploy from GitHub or GitLab by commit SHA: runos deploy --sha <sha> --app <id>.
  • Run a one-off task (database migration or seed) against a deployed image: runos run.
  • Drive RunOS from an AI assistant: runos mcp bootstrap first, then runos mcp configure <claude|codex|gemini|opencode>.