Skip to main content
levelrail-cli is a scriptable client for the control plane’s HTTP API. Everything it does goes through /api/v1, with the same tokens and permissions as the dashboard, so you need no SSH key and no open port on your servers. This page lists every command group with its subcommands and the flags you will use most. Run levelrail-cli with no arguments for the command list, or levelrail-cli <command> <subcommand> -h for any command’s own flags. Commands are shown as levelrail-cli .... If you rename the binary, the command name follows it (the CLI reads its name from os.Args[0]). The server is a separate binary, levelrail, which has a few maintenance commands of its own, such as setup-token, restore-snapshot, restore-db, recover-admin, upgrade-note (record who swapped the binary by hand), and healthcheck. Those are in Installing and Disaster recovery.

Install and sign in

curl -fsSL https://levelrail.com/install-cli.sh | sh
--device prints a short code that you approve in the dashboard, the same model as gh auth login. Credentials are saved to ~/.config/levelrail-cli/credentials. For CI, create an API token under Settings, API tokens and pass it with --token or APP_API_TOKEN. Each command resolves its target in this order, and an explicit flag always wins: Manage more than one control plane with named profiles: levelrail-cli auth login --profile staging, then --profile staging on any command. levelrail-cli profile list shows them.

Scripting: --json and exit codes

Every command that returns data or a result supports --json (shorthand for --output json), and --query takes a JMESPath expression. With --json, stdout carries only the JSON result. The exceptions are completion bash|zsh|fish (a shell script) and control-plane-backups help-dr (a static runbook). A test walks the command tree and fails when a new command has no --json and is not on that exempt list. On failure, --json also prints an error object to stdout (the message still goes to stderr):
error is the original field. code is one of validation, network, unauthorized, forbidden, not_found, conflict, rate_limited, invalid_request, server_error, api_error. http_status, retry_after (rate limits) and hint appear when they apply. Exit codes are stable and shared by every command: Codes 3 and 4 are broad on purpose so existing scripts keep working; the JSON error object carries the finer distinction.

Scripting: --debug

--debug works anywhere on the command line (before or after the subcommand) and traces every outgoing request this invocation makes to stderr: method, URL, and the response status and timing, one line per call. It never prints request or response headers or bodies, so Authorization and any token value never appear, even in debug mode; a token that somehow ended up in a URL’s query string is also redacted. stdout is untouched, so --debug composes with --json/--query for scripting.

Experimental command groups

Some groups are off by default and stay hidden from --help and shell completion until the shell you run the CLI from sets APP_EXPERIMENTAL. This page marks them. The keys are ai-chat (ai, settings ai-assistant), ai-models (models), load-balancer (lb), iac (apply, diff, export) and cloudflare-tunnel (cloudflare-tunnel). See Experimental features.

Web CLI console: host diagnostics

The dashboard’s CLI console (experimental key cli-console) runs the commands on this page against the control plane. It also answers a small host namespace itself, inside the control plane process, without starting the CLI or any other program. It is read only and is not a shell. None of them take arguments: paths, process names, container names and flags are refused. Each line goes through the same step-up, one-command-at-a-time, idle timeout, output cap and audit log (cli_console.run) as any other console command. Linux only; other platforms reply “not supported on this platform”. Set APP_CLI_CONSOLE_HOST=off on the server to turn the namespace off while keeping the rest of the console.

Top-level convenience aliases

Alias for apps deploy; deploy an image to an existing app.
Alias for apps rollback; redeploy an older image.

Apps

apps list prints every app the caller can read as a bare JSON array. On a fleet large enough that matters, add --max-items N to cap the page size; the response becomes {"items": [...], "next_token": "...", "total_count": N} instead, and an empty next_token means there is no further page. Pass that next_token back in as --starting-token to fetch the next page (requires --max-items, since the server only pages a result when a limit is set):
Run levelrail-cli apps <subcommand> -h for the full flag list of any command below. Deploy lifecycle is covered in Deploying and managing apps.

Create, inspect and list

  • apps create registers an existing image or triggers a real build from a git repository; --file reads an app spec, --interactive runs a step-by-step wizard. Required flags missing outside --interactive fail with an error instead of prompting.
  • apps status shows an app’s current reconcile conditions; apps overview shows CPU, memory, traffic and errors for every app (or the names given) in one request; apps network shows the live traffic path (container port, host port, running).
  • apps validate parses and validates an app.yaml or a Docker Compose file locally, with no API call and no deploy. It prints the detected format, service count, and every non-blocking notices entry a real deploy would also surface.
  • apps delete removes an app and stops its containers; if the node is unreachable the delete is reported as pending and retried.

Deploy, roll back and scale

  • apps wait polls until a deploy attempt converges and exits 0 on success, 5 if it converged as a failure, 6 on timeout. On success it says what happened: rolled out, already up to date (the deploy changed nothing) or restarted; --json carries the same as outcome.
  • apps deploy-spec fans an app.yaml’s services: map out into independent builds under one app; apps group shows a service’s siblings under the same multi-service app.
  • apps builds trigger builds an image from a git source and deploys it to an existing app.
  • apps promote promotes the app’s image onto a sibling app in another environment.
  • apps apply restarts an app so saved env, secret and config changes reach the running container; it does nothing when nothing is pending.
  • apps scale changes the replica count and/or the deploy strategy.
  • apps hook-runs shows the most recent outcome of an app’s pre and post deploy hooks; apps images lists the locally present image tags under the app’s current image repo.
  • apps set-node and apps clear-node move an app to another node, or back to the control plane’s own local node. With --with-volumes the named volumes move too, and apps moves shows the history of those moves.

Deploy history, approvals and automation

  • apps deploys list is real, row per attempt deploy history, newest first. apps deploys show prints one attempt (the newest by default) with its structured failure: code, cause, failing step, redacted log excerpt, suggested fix, docs link and retryable. See Deploy failures.
  • apps deploys wait blocks until one deploy is healthy, failed, canceled, superseded or blocked (a freeze window or approval) and prints the result with its failure. Exit 0 healthy, 7 failed, canceled, superseded or blocked, 6 timeout. Without a deploy id it resolves the newest deploy once and follows it by id.
  • apps deploys compare diffs two deploy attempts, or one against the current live state. apps deploys logs prints one attempt’s full build and log output to stdout. apps deploys steps streams the pipeline steps (detecting, building, pushing, deploying) until the attempt ends and exits non-zero if a step failed; an already finished attempt replays only a short summary.
  • apps deploys failed lists every app’s latest failed deploy in the window (default set by the server), with the image of its newest good deploy as a rollback target.
  • apps deploys cancel cancels a queued or in-progress deploy before it cuts traffic. apps deploys rollback-to redeploys a past succeeded deploy’s exact image, pinned by digest or rollback pin, with that deploy’s config; --watch follows it through the readiness gate.
  • apps deploys gate (alias deploy status) prints a release’s gate timeline: readiness passes, stable window, cutover, drain, rollback pin and post-deploy watch. --watch follows it until the release clears its watch, fails, is rolled back or is replaced. Exit 0 healthy or in progress, 7 failed or rolled back. apps deploy-safety shows and overrides the per-app thresholds (set web --stable-window 20s --auto-rollback false, default clears one) and lists pinned rollback targets. See Deploy safety.
  • apps timeline shows what happened to an app, newest first: deploys, rollbacks, restarts, env, secret and config changes (key names only, never values), scaling, stop and start.
  • apps diagnose explains a failed deploy or crashloop and can apply a suggested fix with --apply-fix N. apps preflight runs pre-deploy checks (DNS, ports, disk, image, env).
  • apps freeze manages deploy freeze windows: a window starts at every match of a 5 field cron expression, evaluated in --timezone (default UTC), and lasts --duration. While one is active, webhook, pipeline and released deploys are held and run when the window ends; a manual deploy needs apps deploy --override-freeze --override-reason TEXT. set replaces the app’s windows with the one given. Fleet-wide windows are under settings deploy-freeze.
  • apps schedule configures a recurring redeploy of a branch’s latest commit on a cron schedule.
  • apps cancel-superseded lets a newer queued deploy replace older queued ones of the same branch. Only queued deploys are replaced; a deploy that already started building is never canceled automatically.
  • jobs manages an app’s scheduled jobs: fresh-container or exec cron jobs with run history, logs, retries and catch-up (see Scheduled jobs). apps scheduled-tasks is the older exec-only form of the same resource.
  • functions runs an image as a function: it sleeps when idle, and a request to a sleeping one waits through the cold start (see Functions).
  • apps sleep stops an app after it has had no requests for a set time and wakes it on the next request (see Sleep when idle).
  • apps canary runs a new image beside the app and sends it a share of traffic until you promote or abort it (see Canary deploys).
  • apps auto-update redeploys an app automatically when its image tag moves to a new digest (see Image auto-update).
  • apps auto-rollback opts an app into or out of automatic rollback when a crashloop alert fires. apps auto-rollback-slo-burn sets how the app reacts when an SLO burn rate alert fires.
Deploys across every app you can read: a filterable newest first list (page size default 50, max 200, with --cursor paging), counts by status with failure rate and duration percentiles, and a live event stream (--json prints one object per event).
A deploy or promote into an environment tagged protected becomes a pending approval that a different, sufficiently privileged user must approve first; the same user or token that requested it cannot decide it. list defaults to pending. approve runs the gated deploy or promote now; reject leaves the app’s desired state untouched.
Attach an already connected notification channel (see Channels) so a deploy success or failure sends a message there.

Domains, ports and traffic

  • apps domains add creates the DNS record when a provider is connected (--dns off skips it, --dns preview shows it); --wait prints the go-live steps and exits non-zero when the domain is not live within --timeout. See Add a domain and go live.
  • apps domains shows or changes an app’s domains; a domain already used by another app is refused and nothing is changed. Per-domain TLS, redirects, WAF and the like are under Domains.
  • apps streams forwards a host port to one container port as raw TCP (only tcp is supported). A stream change takes effect on the app’s next container recreation, such as an image change or apps restart.
  • apps egress restricts an app’s outbound traffic to the declared host:port pairs; with nothing configured, egress is unrestricted. DNS and loopback traffic stay open regardless.
  • apps exec-access is on by default. When disabled, apps exec and the interactive terminal are refused whatever abilities the token has.

Run, logs and metrics

  • apps exec runs a command in the app’s container and exits with its real exit code.
  • apps logs searches an app’s stored log entries, or streams live with --follow. For a capped excerpt see logs query under Logs.
  • apps requests shows request rate, errors and latency from the ingress; apps resource-usage ranks every app by latest CPU, memory and network usage.
  • apps resource-recommendation suggests memory and CPU limits from historical usage; apps cost estimates what the app’s CPU and memory would cost under reference providers (not a real bill).
  • usage report|settings|budgets shows cost showback and manages prices and budgets, see usage and cost. usage report --csv prints the export.
  • advisor findings|summary|apply|dismiss|snooze|restore|enable|disable drives the beta resource advisor. advisor apply ID only previews; add --yes to apply.
  • apps health-score gives a synthesized pass, warn or fail readiness verdict across deploy health, security, resilience and observability.
  • apps log-drain forwards container logs to an external HTTP or syslog sink, in addition to the built-in node-local log store.
  • apps scheduled-tasks runs a command inside the app’s running container on a cron schedule. The command is a real argv with no shell; put -- before it when the command takes flags.

Health probes, volumes and storage

  • apps health set sets one probe and keeps the other. A probe is an HTTP(S) check or a command run inside the container (exit 0 is healthy). --preset fills path, interval, timeout and failures from a shortcut (healthz, health, api-health, ping, status); explicit flags win. apps health discover probes well-known paths and reports what each one did.
  • apps volumes manages named Docker volumes outside a redeploy. The name is lowercase letters, numbers and hyphens starting with a letter; the path is where it mounts in the container.
  • apps storage set attaches a connected bucket as object storage and injects its credentials as S3_* env vars at container create time. See Object storage.
  • apps build-cache configures the BuildKit remote cache on a storage destination. --global applies to every app without its own setting. clear is bounded per call; run it again while it reports more to delete. A cache problem never fails a build.

Environment, secrets and Vault

  • apps env import merges a .env file into an app’s plain env vars and prints which keys are new, changed or unchanged. Keys that are already secrets are skipped. It reports how many changes are pending, or restarts the app right away with --apply.
  • apps env diff compares two apps’ env vars, for example staging against production. Secret values are never read: secrets are compared by key only, and the dashboard has the same comparison on an app’s Environment page.
  • apps env export writes env vars as .env text; sensitive and secret keys are written empty with a comment unless --reveal is given. apps env get prints one variable, masked when sensitive. --reveal asks for your password (and authenticator code) at the prompt, never from flags or the environment, and needs a token with read:sensitive and secrets:reveal plus APP_SECRET_REVEAL_TOKENS=on on the server. See Environment variables and secrets.
  • apps secrets set sets or rotates one secret’s encrypted value and declares the key as secret backed so it is injected; --apply restarts the app now. With --env-file it bulk imports every key in a .env format file as its own secret. Values are never returned: list shows key names and locked state only. lock toggles a secret’s overwrite guard.
  • apps vault-env declares an env var resolved live from the configured external Vault (see Vault); only the reference is stored.
  • apps preview-env and apps branch-env override an env var for previews only. A branch override applies when the preview’s own branch matches PATTERN (an exact name or a glob such as release/*); --secret stores it envelope encrypted. Neither affects the app’s own running deploy.

Source, previews and webhooks

  • apps git-source connects a repo for auto deploy on push; settings sets push path filters and forge status reporting; rotate-secret mints a fresh webhook secret, shown once.
  • apps webhook-deliveries lists recent inbound webhook requests, verified or not. replay re-runs a stored delivery’s payload and can trigger a real build and deploy.
  • apps previews manages preview environments per pull request, see Preview environments per pull request. previews is the same command at the top level. extend keeps one preview past its TTL; settings shows or changes the lifecycle, resource, database and exposure policy. limits shows or changes preview caps, fork policy and TTL; approve deploys a held fork pull request once; teardown removes one PR’s preview now; sweep tears down every stale preview across all apps now; pr-status toggles the PR comment and commit status per preview deploy.

Supply chain

apps sbom shows a deploy’s software bill of materials (newest deploy with one by default), or prints or saves the raw SPDX or CycloneDX document. Scanning is off by default and needs APP_BUILD_ATTEST=true on the server so builds produce an SBOM; a server can refuse every scan with APP_SCAN_ENABLED=false. gate block_on_critical keeps the previous release serving; override lets the next blocked release through once, with a recorded reason. See Supply chain.

Alerts, connections and templates

apps alerts create takes one of these kinds: threshold (needs --metric, --comparator, --threshold), crashloop (--restart-count-threshold, --restart-window), cert_expiry, patch_status, scheduled_task_failure (--scheduled-task-id, --restart-count-threshold), node_disk_space, node_resource_usage, node_offline, domain_health, control_plane_backup_stale, log_archive_stale, backup_missing (--backup-resource-kind database with --backup-database-name, or volume with --backup-volume-name) and slo_burn (--slo, optional --slo-latency-ms). Mute, schedule and review alerts with the top-level Alerts commands.
  • apps connect connects an app to a managed database and injects its resolved connection value as an env var; unlike apps database, an app can have any number of these. connections list shows each connection, including whether it resolves to a mesh DNS name (cross node capable) or a container name; connections suggest lists databases the app could connect to. apps disconnect removes one connection by its env var name.
  • apps database set attaches one already created managed database as the app’s connection env var source (default DATABASE_URL, field url); clear detaches it.
  • apps save-as-template derives a compose.yaml from the app’s current desired state and saves it as a reusable template. No secret, database or vault backed env value is captured, only the key name.
  • apps tag attaches a tag by name, creating it if new; apps untag detaches it. See Tags.

Projects, environments and organizations

  • A project groups apps and databases; an organization groups projects. Deleting either leaves its members running, simply ungrouped again.
  • Shared env vars layer in this order: organization, then project, then environment, then the app’s own env, each overriding the one before. env-set replaces that scope’s shared env vars. For per scope secrets see Shared env.
  • A protected environment requires --confirm (or an interactive yes) on apps deploy, apps rollback and apps promote targeting an app tagged with it, and routes the deploy through deploy approvals.
  • apps environments clone-preview shows what cloning would create without applying it; env-diff diffs two environments’ resolved effective env vars.
  • apps projects topology prints a diagram ready graph of a project’s apps, databases and volumes. See Projects and organizations.

Tags

Tags are arbitrary labels for organizing and filtering apps, always identified by name. delete detaches the tag from every app. apps lists every app attached to a tag. Attach one to an app with apps tag.

Pipelines

  • validate checks a pipeline file locally with no API call and exits 2 when it has problems.
  • save creates or updates pipelines from one file, or from every file in a repository’s pipeline directory.
  • runs lists runs, or shows one run’s jobs, steps and approval gates; --all lists runs across every app.
  • approve decides approval gates, or releases a run held for approval.
  • sync syncs pipeline files from the repository now, or sets the repository as source of truth.
  • triggers shows why recent git events did or did not start runs.
  • oidc shows whether pipeline jobs can mint OIDC tokens and the JWKS URL to wire to a cloud provider; oidc rotate-key rotates the signing key, and the old key stays published until it retires.
See Pipelines and Pipeline OIDC.

Load balancers

Experimental: requires APP_EXPERIMENTAL=load-balancer. See Load balancing.
  • list shows every load balancer across apps with upstream health. set creates or changes the load balancer and only the flags you pass change; clear removes it, back to a single upstream.
  • status is the live upstream table; check probes every upstream once, right now; history shows recent checks and state changes per upstream; upstream sets an upstream active, draining or disabled.
  • export generates an infrastructure as code definition with no cloud API calls; import loads the loadbalancer: block of an app.yaml.

Preview

Deploy previews are the screenshot or metadata card captured after a deploy, not pull request previews (those are apps previews). See Deploy previews.
enable turns deploy previews on: metadata reads the page title and social image with one small request (no browser), screenshot (the default here) runs a browser container per deploy and pulls a large image once. capture recaptures the current release now; prune deletes old previews now, or every preview of the app with --all. Previews need the server to run with APP_PREVIEW_ENABLED=true (the default).

Databases

  • status shows a database’s current reconcile conditions (useful when it exists but is not running yet).
  • delete stops and removes a database but keeps its data volume; --force is needed if apps use it.
  • slow-queries lists a Postgres or MySQL database’s slow query log.
  • schema lists a SQL database’s tables with row estimates and sizes; query runs one statement through the control plane, read-only by default. See Database viewer. db is a short alias for databases.
  • set-resources applies memory and CPU limits to an already created database, replacing whatever was set before (a full replace, not a patch).
  • public-access set exposes a database on a host port; --bind-address is private (the default), public, or a literal IP.
  • set-version is a minor or patch image change on the same data. major-upgrade is a guarded Postgres major upgrade with a rollback snapshot; major-upgrades lists the attempts, major-upgrade-rollback restores the pre upgrade data, and major-upgrade-discard deletes a rollback snapshot to free disk.
See Managing databases.

AI models

Experimental: requires APP_EXPERIMENTAL=ai-models. See AI models.
  • deploy runs a model as a container on a GPU node and prints its API key once. Flags: --engine (ollama, vllm or llamacpp), --model, --node, --gpus (a count or all), --gpu-devices, --context, --quantization, --domain, --hf-token-from-env, --residency (always or on_demand), --idle-ttl, --swap-group.
  • logs searches a model engine’s logs, or --follow streams download and load progress live. delete keeps the downloaded weights volume. restart recreates the engine container.
  • rotate-key issues a new API key, printed once; keys manages named API keys with limits, expiry and rotation grace; usage shows gateway requests, tokens, errors and latency per key.
  • residency sets a model always resident or on_demand (stopped when idle, started on first request); wake and sleep start or stop an on demand engine now; swap-group lets models share a GPU (--clear removes it).
  • fit estimates VRAM fit on each GPU node; gpus lists GPU nodes with VRAM and usage; preflight checks a Hugging Face repo (access, size, quantizations, fit, disk); metrics shows engine metrics.
  • cache list shows cached model weights per node; cache prune removes unused, unreferenced weights (use --dry-run first).

Auth

  • login authenticates and persists a new API token; with --profile NAME it saves under a named profile instead of overwriting default.
  • login --device --json prints one JSON line first (verification_url, user_code, expires_in, expires_at) so an agent can relay it, then the token resource once approved. See Attention center.
  • session-link mints a short lived (about 2 minutes), single use login link that signs in as whoever minted it, meant for browser automation. It needs a token with the root ability.
  • code prints the sign-in codes waiting for your account with the requester’s IP address, browser and time, plus password sign-ins from new browsers waiting for approval; approve and deny decide one of those (approve needs --match with the two digit number the waiting browser shows, typed in; a wrong number denies it, and the number is never printed by code), and devices lists or revokes browsers trusted for password sign-in. They need a token that belongs to your user. Listing and devices accept write:sensitive; showing a code and approve or deny need signin:approve, which no device login, root or write:sensitive token carries. Mint one from a signed-in session with levelrail-cli tokens create --name approver --abilities signin:approve --expires-in-days 30 (it must expire within 30 days by default, cannot be an agent token, and is revoked when you change or reset your password or sign out your other sessions), or use the dashboard. code-login shows or changes who may sign in with a code (changing it needs root). See Identity and access.
  • Every 2fa subcommand needs a live session: --username and --password (prompted if omitted), never the CLI’s saved bearer token. setup starts enrollment and returns a secret and provisioning URI; enable confirms it and returns recovery codes once; recovery-codes regenerates them and invalidates the old set.

Auth engine

Shows which auth engine is active, the areas served by the library, and the shadow comparison counters with the most recent mismatches. Needs a root token.

Profile

List configured credentials profiles and their API URLs.

Tokens

Every tokens subcommand requires a username and password (prompted if omitted), because these routes are session only server side and a bearer token cannot call them. create mints a new API token; --agent labels it as issued to an AI agent so audit entries record the agent name. list never shows a secret.

Domains

Per domain settings take <app> <domain>, and the domain must already be one of the app’s configured domains. Domain TLS and ingress behavior is covered in Domains and ingress.
  • standalone manages standalone domains: domains with no app that proxy to PORT, HOST:PORT, an http(s):// URL, app:NAME[:PORT] or container:NAME:PORT. Options are --upstream-tls, --insecure-skip-verify, --tls-server-name, --host-header preserve|upstream|NAME, --no-websocket, --connect-timeout, --read-timeout, --strip-prefix and --description. Loopback, private, container and control-port targets need --confirm. update sends only the flags you pass. Per-domain commands take _standalone as the app name, for example domains waf set _standalone tools.example.com.
  • list shows every app’s domains in one call. check runs a real DNS lookup and reports whether the domain reaches this control plane. certificates lists every certificate in certmagic storage, healthy or not.
  • basic-auth set takes --username and --password. maintenance set serves a fixed maintenance response instead of proxying, without stopping the container. redirect set --target URL redirects every request for the domain; maintenance mode takes precedence if both are set.
  • tls-cert uploads an operator supplied certificate and key; clear reverts to automatic issuance and renew forces re-issuance of an automatic certificate.
  • waf configures the opt-in Web Application Firewall and rate limiting. --mode defaults to detect (matches are logged, never rejected) rather than block.
  • error-pages sets custom HTML for status code 404, 500, 502 or 503; clear removes one mapping, or all if --code is omitted.
  • dns reads and writes the real A, AAAA, CNAME, TXT, MX, SRV and CAA records in the domain’s zone through whichever DNS-01 provider is configured. remove must match an existing record exactly.
  • cloudflare-dns set --cf-api-token TOKEN and route53-dns set --aws-access-key-id ID --aws-secret-access-key KEY configure the ACME DNS-01 credentials needed for wildcard domains. A domain is wildcard eligible by having a leading *. label; if both providers are enabled, Cloudflare takes precedence.

DNS

See DNS zones and records.
  • zones verify compares the NS set the system resolver, 1.1.1.1 and 8.8.8.8 return with the zone’s assigned name servers.
  • records import and records template print a plan and change nothing until --apply. --replace deletes sets missing from the file and needs --confirm.

Backups

See Backups and storage.
  • list-all lists backup history across every database and app volume instance wide.
  • delete removes one archived backup (destructive). download streams a succeeded backup’s object to stdout.
  • restore restores in place and is destructive; --confirm takes the database name. restore-as-new restores into a brand new database and is non destructive. restores and clone-restores list the attempt history of each.
  • verify checks a backup is intact without a live restore; verifications lists past attempts.
  • health shows every backed up resource with its last backup and last verified restore. protection shows bucket object lock and versioning.
  • drill run restores a backup into a scratch resource, validates and destroys it, and exits non zero when it fails. See Prove your backups work.
  • volumes restore restores into a new volume only, optionally named for another app or on another node.

App volume backups

The same verbs as backups, for a named volume declared in the app’s app.yaml (apps volumes get <app> lists them). restore is destructive and its --confirm takes APP/VOLUME; restore-as-new creates a standalone volume.

Point-in-time restore

Postgres only. Recovery covers the time range from when pitr enable was called, forward; use backups restore for anything older.
enable turns on continuous WAL archiving going forward; status shows whether PITR is enabled and the current recoverable window; restores lists point in time restore attempts (base backup, target time, status, error). restore is destructive.

Build

Both work against a public repository and need no existing app. detect shows which framework the builder detects without running a build, and prints no framework detected (exit 0) when nothing matches. branches lists the branches a repo advertises; private or unreachable repos fail with an API error.

Cloudflare Tunnel

Experimental: requires APP_EXPERIMENTAL=cloudflare-tunnel.
Runs the cloudflared container with a tunnel token from your own Cloudflare Zero Trust dashboard, exposing the control plane without an inbound port. This is a different credential from domains cloudflare-dns.

Vault

Configures resolving app secrets live from an external HashiCorp Vault, as an alternative to the platform’s own envelope encrypted storage. The credential is stored encrypted and never shown back; role_id is echoed on get. disconnect disables and forgets the stored credential.

Channels

Valid --kind values: generic, slack, discord, telegram, email, pushover, pagerduty, teams, resend, ntfy, gotify, mattermost, lark, rocketchat, opsgenie, webex, googlechat. update fully replaces a channel’s configuration. --notify-device-login opts a channel into a link-only notice when a CLI login is waiting. test sends a real test message; deliveries lists a channel’s recorded send history, newest first. See Email notifications.

Push subscriptions

Lists or revokes the browser push subscriptions registered for the caller’s own account. There is no register subcommand: a subscription’s endpoint and keys only come from a real browser. See Observability.

Alerts

Top-level commands for muting, scheduling and reviewing alerts. The rules themselves are managed under apps alerts. See Observability.
  • A silence keeps matching alerts evaluating and recorded in history but stops them notifying. Every filter given must match; repeat a flag to accept any of several values. silences delete ends a silence now and keeps it in history (silences list --all).
  • silence is the quick action: silence one rule, --for defaults to 1h.
  • A maintenance window is a recurring silence: a 5 field cron expression for each start, a --duration, and --tz (default UTC). --scope is all (default), app or node, with --target naming the apps or nodes.
  • history lists firings and resolutions, newest first (--limit defaults to 50). --outcome is one of sent, silenced, grouped, inhibited, failed, ratelimited, flapping or skipped; --event is fired, resolved, flapping or flap_ended; --since takes an RFC 3339 timestamp. --changes adds what changed on the app before each firing, with the most likely cause tagged.

Status page

The opt-in public status page. It stays off until set --enable. Only public component names, statuses and operator written announcements are published; targets (app names, hostnames, check URLs) stay private. See Status page.
  • --enable and --disable are mutually exclusive. --domain serves the page on a hostname that the ingress must route to the control plane.
  • incidents create: --kind defaults to incident, --impact to none. A maintenance kind requires --starts and --ends (RFC 3339). --body is markdown-lite.
  • incidents update --status takes investigating, identified, monitoring or resolved for an incident, and scheduled, in_progress or completed for maintenance.

Shared env

Environment variables shared at project, organization or environment scope, plain or secret. See Projects and organizations.
SCOPE is project, organization or environment, and --id is that resource’s id. A plain value is stored as is. --secret encrypts it the same way an app’s { secret: true } env vars are, and its value is never shown again, only its key. list shows plain and secret marked entries alike; pass --secret to delete when the key is secret marked.

Registry

Runs the platform’s own built-in image registry (registry:2). The first enable generates a username and password; the password is printed once and never shown again. disable forgets the generated credentials. This is distinct from registry-credentials, which stores credentials for an external registry.

Registry credentials

Private container registry pull credentials. update can rotate the password. test authenticates against the registry without pulling anything; repositories and tags browse the external registry.

Backup targets

S3 compatible backup destinations. Valid --provider values are aws, r2 and custom; --endpoint is required for r2 and custom. test probes the bucket over its stored credentials without uploading or deleting anything.

Storage

S3 compatible storage destinations. providers lists the presets (aws, r2, b2, minio, wasabi, custom). add also takes --account-id (r2), --region (aws, b2, wasabi), --endpoint (minio, custom), --virtual-hosted and --skip-verify. test writes, reads back and deletes a probe object.

Data export

See Data export.

Logs

See Log archive.
TIME is an RFC 3339 timestamp or a duration back from now such as 24h. Without --app, a policy or dump covers every app. fetch downloads one archived object (gzip NDJSON). query returns a capped excerpt of an app’s newest matching log lines with match counts and a truncation notice; the byte cap defaults to 8 KB or APP_MCP_LOG_MAX_BYTES.

Network shares

NFS and CIFS network share mounts, the same shares an app’s volume mount can reference by name. See Network shares.
--name, --protocol, --host and --remote-path are required on create and update. A CIFS share also needs --username and --password; on update, omit --password to keep the existing one. test checks that the share’s host is reachable on its protocol’s standard port.

Firewall

Declarative host firewall rules, reconciled onto the control plane’s local ufw. See Host firewall. exposure, restrict and unrestrict are covered in Exposure audit.
--port is required (1 to 65535); --protocol defaults to tcp and --source-cidr to any source. A deny rule, or an allow rule scoped to a source CIDR, that targets a port the control plane itself needs (the management API, agent connections or ingress) is refused rather than applied.

Security center

The security score, sessions and devices, and the platform security policy. See Security center.
posture prints the score for anyone with read; the item list needs root. The sessions commands act on your own account; --user names another account and needs root. A token used for them must belong to a user and hold write:sensitive or signin:approve. policy set needs root and changes only the flags you pass.

Feature flags

A boolean, plus an optional gradual rollout percentage, that the app’s own code reads live through GET /api/v1/flags/evaluate/{key} with a read scoped API token. Changes take effect immediately with no redeploy. The key is globally unique across the control plane and cannot change after create.

Apply, diff and export

Experimental: requires APP_EXPERIMENTAL=iac. See Platform as code for the document format, secrets handling, prune rules and CI use.
Validates resource files, prints the plan, and applies it through the API with your own permissions. Exit 0 no changes or applied, 1 error, 2 changes pending (with --dry-run --exit-code). ${{ env.NAME }} placeholders are filled only from --var, --var-file or the names listed with --allow-env (a trailing * allows a prefix, but never covers credential looking names such as AWS_*, GITHUB_TOKEN or anything containing TOKEN, SECRET, PASSW or _KEY, which must be named exactly). An unresolved placeholder fails before anything is sent.
Drift between the files and live state; exits 2 when they differ.
Writes live state as stable resource files, never containing secret values. Secret looking values become ${{ env.NAME }} placeholders; supply them at apply time with --var, --var-file or --allow-env. Callers without read:sensitive always get placeholders for every env value.

Nodes

See Multi-node.
  • delete fails while the node still has placements; drain it first. join-token mints a one-time enrollment token, shown once. reenroll-token mints a one-time token that re-issues a node’s agent certificate, keeping its identity, and prints the command to run on the node. revoke-cert revokes the certificate and closes the node’s session; only a re-enroll token brings it back.
  • cordon marks a node unschedulable without evacuating it; uncordon reverses that; drain moves every service and database off a node.
  • list shows each node’s certificate state and days left (CERT) and agent version (AGENT); get adds expiry, last renewal, key origin, platform and commit.
  • resource-usage shows every node’s latest CPU, memory and disk usage plus a fleet rollup; capacity-forecast projects disk and memory usage forward, roughly how many days until full.
  • mesh shows the live WireGuard mesh state and peers; rotate-key rotates a node’s WireGuard key; rejoin-mesh forces an immediate resync for a stuck peer.
  • providers manages cloud provider credentials (Hetzner, DigitalOcean) and provision creates a server at a provider and enrolls it as a node; ssh-provision adopts a machine you already have over SSH. provisions and ssh-provisions track either through to enrollment. See Multi-cloud provisioning.
  • topology is a whole mesh summary (nodes, apps, databases, load balancers, connections); traffic shows per domain ingress reachability and TLS status.

Status

Shows the control plane’s own configured and not configured signals, including whether its local Docker daemon is reachable.

Upgrade

Compares the running version with the latest release, runs the preflight checks (release signature, Docker Engine, free disk, backup), takes a control plane backup and prints the command that upgrades. It never upgrades by itself unless you pass --apply. See Installing.
backup-now takes a control plane backup and re-runs the preflight. schedule queues the upgrade for a time or the next maintenance window; the preflight re-runs at that time and nothing is applied if it fails. auto reads and sets the automatic upgrade policy, which is off by default; set changes only the flags you pass. All of these need a root token. See Upgrade safely. --plan shows the breaking changes between the running version and the target (default: latest on the channel). --apply asks the control plane to run the safe self-update on its host: verified download, snapshot, migration dry run, swap, health check and automatic rollback. Breaking changes flagged as needing acknowledgement are refused until you list their ids with --ack-breaking. It follows the attempt to its outcome unless --no-wait, and exits non-zero when the upgrade was rolled back or failed. --attempts lists every attempt with its step timeline. See Upgrade safely.

System restart

Restarts the control plane process through its supervisor, for example after enabling the mesh. It asks for confirmation unless --yes; without a terminal, --yes is required. With --wait it polls until the control plane answers from a new process (its boot_id changes), tolerating connection errors while it is down, and gives up after --timeout. status prints the current boot_id, whether restart is supported and whether one is pending. If no process supervisor was detected, the command prints the reason and the command to run on the server (for example sudo systemctl restart levelrail) and exits non-zero. The API is GET and POST /api/v1/system/restart.

Readiness

Checks whether the server is ready: who holds ports 80 and 443, Docker version and rootless mode, exposed Docker API, disk, memory, firewall and the DNS of the domain. Prints the recommended install mode (own ports or behind your existing proxy) and the exact next step. Exits 1 when a check fails. Before anything is installed use install.sh --check instead, see Installing.

Version

Shows the control plane’s running version, and whether a newer release has been published to the project’s GitHub repository.

Changelog

Prints recent release notes, newest first, from the running control plane’s own CHANGELOG.md. Without --limit the server default applies. The dashboard shows the same notes in the What’s new panel.

Init

Detects the project’s stack (Dockerfile, compose file, package.json, go.mod, Python, Java, static site) and writes three files into the directory: app.yaml (the app spec, validated with the platform’s own validator), AGENTS.md (how an AI agent deploys, checks and rolls back the app) and .mcp.json (MCP server config; the token is an env var reference, never a value).
  • Existing files are never overwritten unless --force is given. A diff of what would change is shown either way.
  • Without --yes, a terminal is asked to confirm; a script must pass --yes or --dry-run.
  • --mode selects the tool exposure written to .mcp.json: agent-core (the default, a small profile for deploy and debug work), read-only (every read tool, no mutations), standard (read and mutating tools, no destructive ones) or full.
  • --api-url or the active profile is written into AGENTS.md and .mcp.json when known. --mcp-binary overrides the MCP server binary name.
See Agents.

API docs

Prints every HTTP route registered on the control plane: method, path, required ability and resource group, followed by a count of routes and how many have a worked request and response example. It is the same data as Settings, API explorer in the dashboard, without the interactive try-it. Supports --json, --output and --query. See API explorer.
Prints a “Deploy with” link and the README Markdown for it, after validating the image reference, DNS label name, port range, uppercase env names and health path. Env values are never part of a link. Without --launcher, the launcher is APP_BRAND_DOCS_URL plus /deploy.html. --server also prints the direct https://<server>/apps/new?deploy=1&... link. Supports --json, --output and --query. See Deploy links and badge.

AI assistant

Experimental: requires APP_EXPERIMENTAL=ai-chat, and a provider, model and key set with settings ai-assistant set. The assistant is read and suggest only: a tool call that would change state pauses for an explicit confirmation. See In-app AI assistant chat.
  • ai chat sends one message and streams the reply to stdout. Without --session it starts a new session and prints its id to stderr; pass that id back with --session to continue the conversation. --json prints one JSON object per stream event.
  • ai sessions resolve approves or rejects a mutating tool call the assistant proposed (shown by ai chat as a pending confirmation), then streams the continuation.

AI control

Control what AI agents can do on your platform.
  • status shows the current mode, allowed environment kinds, and when it was last changed.
  • set changes the mode or allowed environment kinds. Agent tokens cannot approve deploy or pipeline approvals, and cannot change this setting.
  • revoke-agents revokes every labeled agent token.
See AI control.

Audit log

audit-log lists every recorded write, deploy and root tier request plus automatic certificate renewals, newest first. Read only requests are not recorded. It needs an admin or root scoped token. Flags: --limit N, --before RFC3339, --path, --method, --client-kind cli|dashboard|mcp|api, --agent <name> (entries made with a token labeled with that agent name), --search <text> (case-insensitive substring across actor, ability, method, path and remote address), --resource domain:<name>|zone:<name>|app:<name> (one resource’s own trail), --actions <prefixes> (comma separated action prefixes such as dns_record.,proxy_route.,domain.), --failed (status 400 or higher), --format csv with --output-file FILE. --agent, --search and --failed are applied server side and carry into csv exports. audit-purge deletes every entry older than the retention window (APP_AUDIT_LOG_RETENTION_DAYS, default 90 days) right now instead of waiting for the automatic sweep. It needs an admin or root scoped token.

Attention

Lists everything that needs attention right now: failing apps, failed deploys from the last 24 hours, low disk space (warn under 10 percent free, critical under 5), offline nodes, expired or expiring certificates, and doctor warnings or failures, critical first. It is the CLI side of the dashboard’s Status page (/status). Exit code is 1 if any item is critical, 0 otherwise, so it works as a script gate. Supports --json, --output json|table|text, and --query.

TUI

Opens an interactive terminal UI over the same API: live apps, databases, deploys, nodes, domains, alerts and backups, a log tail, and confirm-gated restart, deploy, rollback, stop and start. Needs a TTY. See Terminal UI for the key map.

Doctor

Runs a local preflight health check: Docker daemon reachability, disk space and write latency, write access on the data directory, port 80 and 443 availability for the embedded ingress, control plane database reachability, RAM and CPU against the recommended minimums, firewall status, outbound network reachability (public IP, external port reachability, ACME, clock skew, the agent advertise host, image registries), and GPU attach checks. Exit code is 0 if every check is ok or warn, 1 if any check fails.

Setup

The dashboard’s Get started checklist from a terminal. status prints every step with its state, time estimate and note, plus the “ready for production” percentage. next prints the one step to do next and where to do it. skip and undo record or clear an operator override for a step id such as teammate; reset clears every override and shows the guide again. The three writes need a root scoped token. Steps and their rules: Getting started. Supports --json, --output json|table|text, and --query.

Proxy

Without a subcommand: shows which container publishes ports 80 and 443 and the configuration to paste into that proxy, for the dashboard (--domain) or an app’s domain (--app, upstream is the ingress HTTP port). setup detects a Traefik (Coolify’s included) and, with --confirm, turns on tls_terminated_upstream, saves the detected entrypoints, certificate resolver, directory and upstream host, writes one route file per domain and verifies each over HTTPS; without --confirm it is a dry run. It exits with an API error and the precise gap (detection_incomplete, upstream_unreachable with the drop-in fix, not_writable) when it cannot proceed. status prints detection, per-domain state (missing, written, stale, error), certificate issuer and expiry, and the checklist. apply rewrites the files now, verify probes again, disable removes the files it wrote. Writes need a root scoped token. Details: Run behind an existing proxy.

Containers

list shows every container on this node, managed or not. stop, remove and claim only act on a container the platform does not already manage (409 otherwise); for a managed app use apps stop, apps start, apps restart or apps delete. claim adopts an orphaned container into a new app. orphans lists leftover containers, volumes and certificates that no app or database accounts for, with where each stands against its grace period. reap runs one removal pass now (--dry-run reports without removing; exit 1 if anything could not be removed). Details and the APP_ORPHAN_* settings are in Delete and clean up.

System address

Shows this server’s public IPv4 and IPv6, where they came from, and a note when the server is behind NAT or a TLS-terminating proxy. --domain adds the exact DNS records to create for that name. --ipv4 and --ipv6 set a manual override (root), --clear goes back to detection. See Standalone domains.

System maintenance

Fleet wide cleanup. These commands need an admin or root scoped token.

System prune

Removes every stopped container, dangling image, and unused anonymous volume or build cache not part of the reconciler’s current desired state, fleet wide. It never touches a named volume (an app’s storage attachment, a database’s data volume), even one that is actually orphaned: see Orphaned volumes for those.

Control plane backups

Snapshots of the control plane’s own database, stored under <data dir>/control-plane-backups/. create takes one now (manual snapshots are never auto-deleted), download saves one to --out FILE (or raw bytes to stdout), verify re-checks the checksum, SQLite integrity and schema version without restoring (exit 1 if any check fails), delete removes one. Snapshots never contain the master key. Restore is an offline server command, levelrail restore-db <file>; see Control plane backup and restore. The --offbox, schedule, run-now, drill, escrow and keys subcommands drive encrypted off-box backups. keys generate makes an age key pair on your machine (private key to a 0600 file, public key to stdout). schedule set changes only the flags you pass (--enable, --disable, --destination, --recipient, --schedule, --drill-schedule, --retain-daily, --retain-weekly, --retain-monthly, --escrow-destination). run-now and drill run wait for the run and exit 1 if it failed; drill status exits 1 when the last drill failed or none has run. escrow writes the master key and agent CA key encrypted to your recipients (never uploaded unless --upload, and never to the backup bucket). help-dr prints a static runbook. Restore an off-box backup on the server with levelrail restore --from <s3://... | file> --identity FILE [--dry-run]. See Disaster recovery.

Orphaned volumes

Named Docker volumes (an app’s storage attachment, a database’s data volume) survive system-prune even after the app or database that created them is deleted, since Docker never removes a named volume on its own. volumes-orphaned lists every one this instance created that no current app, database or storage attachment references any more. volumes-orphaned-cleanup removes exactly the volumes named with --names (comma separated), after the control plane re-confirms each one is still genuinely orphaned. There is no flag that deletes every orphaned volume unseen; review the list first.

Users

--role is a curated preset (admin, operator, viewer, guest, or a custom role by name; users roles lists the curated presets and roles list lists every stored role); --abilities is a comma separated list from read, read:sensitive, write, write:sensitive, deploy, root. users role set changes a user’s role; users grants manages which environments a guest can see. invites create invites a teammate by email; invites list and invites revoke manage pending invites. See Access control for details.

Roles

Custom roles are presets over an ability list. Updating a role applies the new abilities to every user holding it, immediately. A role cannot be deleted if any user holds it. See Access control.

IAM

Resource scoped Allow and Deny policies, additive on top of --abilities. DOC is a policy document JSON string, passed inline or as file://path/to/policy.json:
update replaces the policy’s name, description and document. attachments lists a policy’s attached principals. templates shows built-in policy templates and apply instantiates one, optionally attaching it to a principal. See Access control.

Environments

Global environments exist across the entire instance (Development, Test, UAT, Production). Kinds control which environment a resource has and what policies apply. Moving into or out of a protected environment requires confirmation and approval from another user. See Environments.

Secrets

generate-master-key writes a new master key to a file (mode 0600, never overwrites), locally, without contacting the control plane. rotate-master-key re-wraps every stored data encryption key under a new master key in one atomic step, live, then binds any legacy values. binding-status counts stored secret values not yet bound to their slot, and rebind binds them (safe to rerun). Read Master key rotation before running these in production.

Migrate

One way migration from a live instance. By default it writes app.yaml files plus a migration report into --out-dir (default ./migrated); --apply creates the apps directly on a target instance instead, using --target-token, --target-api-url and --target-profile. --include-secret-values also fetches real env var values. For Coolify, --token is an API bearer token (with the read:sensitive ability if you want secret values); for Dokploy it is an API key; for CapRover it is the login password.

Import

import classifies its input (a GitHub, GitLab, Gitea or Bitbucket repo URL, a docker run command, an image reference, a docker-compose.yml or a Dockerfile) and prints a deployment plan. Nothing is created unless --deploy is given. --file - reads from stdin. --env KEY=VALUE is repeatable, and a required variable with no value blocks --deploy. import <repo-url> --analyze prints what the New app wizard would suggest (stack, build, port, health path, env variable names, databases) with the evidence for each, and creates nothing. --apply creates the suggested databases, the app, the connections, the repository link and the first build; --base-directory, --dockerfile, --build-type, --name, --port and --env override suggestions. See New app wizard. import platform reads apps, databases and settings from another platform (read only) and creates them here. Use --dry-run first. Databases and volumes are created empty; data is not migrated. Re-running skips what was already imported. The source token is read from APP_IMPORT_SOURCE_TOKEN, --token-stdin or --token (which lands in shell history). Other flags: --only, --collision suffix|skip, --insecure-tls, --allow-private, --allow-loopback. See migrating from Coolify, Dokploy or CapRover. import cutover moves one staged app’s traffic in a reversible flow. plan prints the readiness checklist, run --dry-run exercises everything except the switch, run --confirm NAME switches and verifies (rolling back on its own if verification fails), status shows the timeline, and rollback restores the previous DNS value and stops the staged app. Other flags: --run ID, --accept-warnings, --no-wait, --wait DURATION, --json. See guided cutover.

Completion

Prints a shell completion script for command and subcommand names and the global flags. It does not complete flag values or positional arguments like app names. For bash, source <(levelrail-cli completion bash); run levelrail-cli completion -h for the zsh and fish install lines.

Settings

Instance wide configuration, gated at the root ability server side on every write.
  • oauth set <provider> enables, configures or disables one sign in provider; <provider> is google, github or oidc.
  • ingress get shows the primary domain, ACME settings, the automatic hostname toggle and the detected public address. ingress set changes them (--primary-domain, --acme-enabled, --acme-email, --acme-directory-url, --fallback-domains=false, --hsts-enabled, --apps-base-domain, --dns-cname-target, --dns-ttl, --dns-proxied); flags you leave out keep their current value.
  • ingress https status shows whether the dashboard’s free sslip.io HTTPS is off, pending, issued or failed. ingress https enable points the dashboard at <dashed-ip>.sslip.io and issues a real Let’s Encrypt certificate for it, with no DNS setup.
  • dashboard-url set sets the public dashboard URL; once it is https://, sign in over plain HTTP is refused (--url "" clears it).
  • updates configures the release channel and auto update checking. deploy-freeze manages fleet wide freeze windows; per app windows are under apps freeze.
  • ai-assistant is experimental (APP_EXPERIMENTAL=ai-chat): get shows the current settings (the key itself is never returned, only whether one is stored), set --model NAME --api-key KEY configures the assistant, and clear clears the stored key and resets provider and model.

Git integrations

  • git-providers shows connection status and capabilities (list branches, register a webhook, authenticated clone) for GitHub, GitLab, Bitbucket and Gitea in one call.
  • Connecting a provider is dashboard only, because it is a browser redirect through the provider’s own OAuth or manifest flow. Once connected, these commands browse its repos and branches, connect one as an app’s git source with use-as-source, or check and forget the connection.
  • disconnect forgets the stored connection locally; it does not uninstall the App or revoke the token on the provider’s side.
  • github-app register-url prints the dashboard link that starts GitHub App registration, for your personal account or, with --owner, an organization. --public lets other accounts and organizations install the App. It makes no request; open the link in a signed-in browser.
  • github-app installations add prints the URL to install the App on another account or org; it does not open a browser. installations remove is refused (409) while a git source still points at a repo under it.

Templates

list browses the curated service catalog, or --custom for your own saved templates. get shows one entry including its full compose.yaml. deploy deploys a template’s compose.yaml as an app, and the app name defaults to the template id; pass --name to use another. A custom template works with every verb the same as a built-in one, except delete: only a custom template can be deleted (see apps save-as-template). See Templates. install is for manifest templates (the ones get shows with settings): it fills each ${KEY} setting from --env, a generated secret or its default, puts the listed services behind --domain hosts, and deploys the result as a compose app that is not a trial. See Compose apps.

Compose

  • deploy deploys or updates a stack and records a numbered revision; -f - reads stdin. --profile-name enables services behind compose profiles:.
  • preview asks the server to parse and check a file without saving anything, lists each service with its generated and required env vars, and exits with code 2 when the file would be rejected.
  • status prints the stack phase and each service’s ready state with the reconciler’s reason.
  • logs merges recent lines from every service, or hands one service to apps logs with --service, where -f follows it.
  • redeploy recreates every service’s containers, or one service’s.
  • rollback re-applies an earlier compose file (default: the one before the latest) as a new revision.
  • down removes every service and its containers; named volumes and generated secrets are kept unless you pass --volumes.
See Compose apps.

Static sites

Lists every build.type: static app served directly through the embedded Caddy ingress, with no container involved.

Getting started

Install the control plane and deploy a first app.

Deploying and managing apps

The app lifecycle, command by command.

App spec reference

Every field of app.yaml.

Feature catalog

The complete feature overview.
Last modified on October 12, 2026