Two command groups do most of the work from a terminal. doctor checks the server and explains what is wrong. import turns a repository, an image or a config folder into an app. The dashboard versions are on Doctor and Import a repository. This page covers the CLI flags, output and exit codes.
Run the checks
This runs the same checks as the Doctor page in the dashboard. The checks cover Docker, disk and inodes, ports, firewall, clock, DNS, certificates, backups and restore drills, node agents, the WireGuard mesh, orphaned Docker data and dashboard HTTPS.
Each check has a status, a message and, when there is a problem, a fix ID and fix kind. --output json returns ok (true when no check fails) and the checks list.
Exit codes depend on the output format:
- With the default table output, the command exits
1 when any check fails and 0 otherwise.
- With
--json, --output json or --output text, the command exits 0 even when checks fail. Read the ok field instead.
Apply safe fixes
--fix builds a plan from the failing and warning checks that offer an automatic fix. It prints the plan and asks Apply N fix(es)? [y/N]. --yes applies without asking.
- Only fixes that are automatic and marked
safe are applied.
- Any other fix is listed as skipped with the reason. A fix with a higher risk is applied on purpose with
levelrail-cli fixes apply <fix-id>, which can also take --param k=v.
- A fix the server reports as rate limited or demoted is skipped with the server’s reason.
- Without a terminal,
--fix refuses to run unless you pass --yes.
- After applying, the report runs again and the result is printed.
--fix needs a control plane. With none configured, it stops with an error.
Explain one check
The second command lists the IDs of failing checks, so you can pass one to explain.
doctor explain <check-id> prints what is wrong, why it matters and the next step, plus the fix ID when one exists. The check ID is the check_id field in the report. The explanation is a fixed table, so the command does not contact the network.
Local checks without a control plane
--local runs only the Docker, disk and port checks on this host and never contacts a control plane. The same happens automatically when no server is configured (no --api-url, no token, no profile). In table mode, the CLI says on stderr that it is running local checks only.
The local disk warning threshold is 1 GiB free. Set APP_DOCTOR_DISK_WARNING_BYTES to change it, in bytes.
Disk only
This is read-only. It shows the disk checks only: disk_space, docker_root_disk, disk_hygiene, inodes and docker_orphans. It lists the largest consumers and a cleanup command it suggests but never runs. The control plane warning level for free space is set by APP_DOCTOR_DISK_WARN_FREE_PCT (percent free).
Network, firewall and paths
reachability lists the listening ports. When the dial-back setting is on, it also shows which ports the internet cannot reach.
cloud (also doctor --cloud) prints the provider firewall rules this host needs, with the console link for each provider. It runs offline.
paths runs offline. It prints the binary, releases directory, data directory and systemd unit locations, and the address the unit binds (APP_HTTP_ADDR).
Domain checks
domains doctor runs every check for one domain: DNS per resolver, CAA, ports 80 and 443, the TLS certificate, the HTTP status, redirects, HSTS, proxy ownership, app state and certificate renewal. It prints a fix list in priority order. It only connects to the domain when the domain resolves to this server. Otherwise it runs the DNS checks and says why it stopped there.
domains summary counts domains by status and certificates that are expiring or failing to renew.
App failures
This explains why the latest deploy failed or why the app is crash looping. It applies fixed rules to signals the platform already collected, such as the deploy error, reconcile reasons and recent log lines. When no rule matches, it says so. Nothing changes unless you pass --apply-fix N.
The plan, analyze and apply commands need a control plane. import config is offline.
Plan a source
Give exactly one source: a repository URL or image argument, -f with a file (or - for stdin), or --docker-run with a command. The input is classified as a GitHub, GitLab, Gitea or Bitbucket repository URL, a docker run command, an image reference, a docker-compose.yml or a Dockerfile. The command prints the plan. Nothing is created.
Useful flags: --name (default derived from the source), --ref (branch for a repository), --port (container port override) and --json.
Create the app
--deploy creates the app and deploys it after the plan prints.
If the plan lists required variables with no value:
- In a terminal, the CLI prompts for each one. Secret values are read without echo.
- Without a terminal, the command stops and lists the keys. Pass each one with
--env KEY=VALUE.
Analyze or apply a repository
--analyze shows the detected stack, build, port, health check, environment keys and databases, each with its evidence. It creates nothing.
--apply creates the suggested databases, the app, the repository link and the first build. --no-database skips the databases.
- Overrides for both:
--base-directory DIR for a monorepo app, --dockerfile PATH, and --build-type dockerfile|railpack|static.
Preview a config folder
import config reads Procfile, app.json and vercel.json from a folder and prints a proposed app.yaml. Findings go to stderr, blockers first, each with a fix. It needs no token and creates nothing.
--out FILE writes the proposed file instead of printing it.
--strict exits 2 when any finding is a blocker.
--json prints detected, spec and findings as JSON.
--emit stack --out DIR writes Stack, Project, Database, App and Domain documents, a SECRETS.md listing secret names only, and a MIGRATION.md. Review them in a pull request. --force overwrites existing files.
Monorepo packages
import repo plan lists one proposed app per workspace package: name, directory, port, build kind, dependencies and warnings. It creates nothing. --branch picks the branch to inspect, and --dir plans only the packages under one directory.
import repo apply plans the repository, then creates one app per package:
--packages a,b limits the packages. --project and --environment place the apps.
--set PACKAGE.KEY=VALUE sets an environment value. --secret PACKAGE.KEY=VALUE sets a secret one.
--dry-run checks everything and creates nothing.
- When the import creates more apps than the server’s confirmation limit, the command stops and asks for
--yes.
- A failed app does not stop independent ones. Apps that depend on a failed app are skipped. Running the command again skips apps that already track the same package.
--deploy starts the first build of each app.
Exit codes
Not yet
- A
doctor exit code of 1 for failed checks in JSON and text output. Today those formats exit 0, so scripts must read the ok field.
- A way to run
doctor --fix for risky fixes without fixes apply.
Last modified on November 8, 2026