CLI Commands Reference

This is the canonical reference for the portoser command, generated from the script's own --help output and verified against the running code at bin/portoser (the entry-point shim) and the top-level portoser script.

The CLI is a single Bash script that dispatches to handlers under lib/. There is no daemon, no agent, and no client/server protocol — every subcommand runs in the local shell and SSHes (or docker execs) where it needs to.

Global flags

Flag Purpose
-h, --help Show top-level help and exit.
-v, --version Print version and exit.
--debug Enable bash trace + debug logging for the run.
--json-output Where supported, emit machine-readable JSON instead of human-formatted output. Used by the web UI and downstream scripts. Note: the canonical flag is --json-output; a few subcommands also accept --json as a shortcut.

CADDY_REGISTRY_PATH overrides which registry.yml is read. The script defaults to $SCRIPT_DIR/registry.yml, so a clone-anywhere checkout works out of the box.

Service lifecycle

deploy

portoser deploy MACHINE SERVICE [SERVICE...] [OPTIONS]

Deploy one or more services to a target machine through the full observation → diagnosis → solving → learning loop. Auto-heal is on by default.

Option Purpose
--dry-run Print what the loop would do; don't apply anything.
--no-auto-heal Run observation + diagnosis only; skip solver actions.
--json-output Structured JSON output (used by the web UI).

Examples:

portoser deploy m1 my-api                 # standard deploy
portoser deploy mini1 kag requirements    # multiple services, same host
portoser deploy m4 kag --dry-run          # plan without applying
portoser deploy mini1 kag --no-auto-heal  # diagnose only

start / stop

portoser start <service|machine> [service...]
portoser stop  <service|machine> [--force] [service...]

Start or stop services. The first arg is interpreted as a machine name if it matches one in the registry, otherwise as a service. --force on stop skips dependency checking (useful when you know dependents will be brought down separately).

portoser start requirements
portoser start mini2                  # start everything on mini2
portoser stop  requirements --force

move

portoser move SERVICE FROM TO

Migrate a single service from one machine to another. Updates current_host in the registry, redeploys on the target, and tears down on the source.

docker (advanced)

Bypass the loop and operate on Docker directly. Useful when you've already diagnosed a problem and want to run the precise step yourself.

portoser docker build   SERVICE [MACHINE]
portoser docker deploy  SERVICE  MACHINE
portoser docker stop    SERVICE  MACHINE
portoser docker restart SERVICE  MACHINE

local (advanced)

Same idea, but for deployment_type: local services (uv-managed Python apps).

portoser local start   SERVICE [MACHINE]
portoser local stop    SERVICE [MACHINE]
portoser local restart SERVICE [MACHINE]
portoser local logs    SERVICE [LINES]   # default 50 lines

Diagnostics & health

status

portoser status

Print every service in the registry with its host, type, and current status. Read-only — no SSH chatter.

verify

portoser verify

Verify every HTTP service is reachable via its .internal domain. Useful after a Caddy regenerate.

diagnose

portoser diagnose SERVICE [MACHINE] [--json-output]

Walks the same observation pipeline a deploy uses, but in read-only mode. Produces an analyzer fingerprint (e.g. PROBLEM_PORT_CONFLICT), a health score, and a frequency count from the knowledge base.

Diagnostic reports are saved to ~/.portoser/diagnostics/ for later inspection. The --json-output form is what the web UI calls.

health

portoser health check       SERVICE                          # single service
portoser health check-all                                    # all services
portoser health status      SERVICE                          # detailed status
portoser health             SERVICE MACHINE [--json-output]  # quick health score
portoser health --all       [--json-output]                  # all-services scores

The "score" form is the JSON-friendly entry point used by the web UI's Health Dashboard.

Knowledge base & history

learn

portoser learn summary                          # human-readable summary
portoser learn stats     [--json-output]        # numbers only
portoser learn playbooks [--json-output]
portoser learn playbook  NAME    [--json-output]
portoser learn insights  SERVICE [--json-output]

learn summary is the friendliest entry point — total problems, unique fingerprints, generated playbooks, on-disk path. learn insights <service> is what you'd hand a colleague when they ask "what fails most for this service?".

history

portoser history list      [SERVICE] [--json-output]
portoser history show      DEPLOYMENT_ID [--json-output]
portoser history rollback  DEPLOYMENT_ID [--force]
portoser history preview   DEPLOYMENT_ID
portoser history compare   ID1 ID2
portoser history stats     [SERVICE] [DAYS]
portoser history cleanup   [KEEP_COUNT] [KEEP_DAYS]

History is stored in the backend Postgres database (running the web stack), so the CLI sees an empty list when run against a machine that isn't connected to that database.

Dependencies

portoser dependencies list    [--json-output]
portoser dependencies graph   [--json-output]
portoser dependencies check   [--json-output]
portoser dependencies order   SERVICE  [--json-output]
portoser dependencies impact  SERVICE  [--json-output]
portoser dependencies info    SERVICE  [--json-output]
portoser dependencies add     SERVICE DEPENDENCY
portoser dependencies remove  SERVICE DEPENDENCY

dependencies check runs both validation passes (no missing services + no circular deps) and exits non-zero if it finds either. impact shows blast radius — what would break if SERVICE went down. order returns a topologically valid deploy sequence for a service plus its dependencies.

Metrics & uptime

portoser metrics service SERVICE MACHINE [--json-output]
portoser metrics machine MACHINE         [--json-output]
portoser metrics all                     [--json-output]
portoser metrics test                                   # platform compat probe

portoser uptime service SERVICE MACHINE [--json-output]
portoser uptime all                     [--json-output]
portoser uptime history SERVICE MACHINE [--days N] [--json-output]
portoser uptime status  SERVICE MACHINE

metrics test is a useful first call on a fresh host — it tells you which CPU / memory / disk probes work on that platform.

Networking

dns

portoser dns status
portoser dns config
portoser dns check       SERVICE
portoser dns check-all
portoser dns test        HOSTNAME
portoser dns verify-all

caddy

portoser caddy sync                  # regenerate Caddyfile + reload
portoser caddy update     SERVICE
portoser caddy reload
portoser caddy validate              # `caddy validate` against generated config
portoser caddy regenerate
portoser caddy proxy      SERVICE

network

portoser network update-ips MACHINE IP ...
portoser network migrate    MACHINE IP ...

Security

certs

portoser certs init-ca
portoser certs generate            SERVICE
portoser certs generate-all
portoser certs generate-server     SERVICE
portoser certs generate-all-servers
portoser certs update-registry
portoser certs deploy-servers      [SERVICE]
portoser certs list
portoser certs deploy              SERVICE MACHINE

keycloak

portoser keycloak create-client SERVICE
portoser keycloak create-all
portoser keycloak list-clients  [REALM]
portoser keycloak get-secret    CLIENT_ID

vault

portoser vault init
portoser vault unseal      [KEY1] [KEY2]
portoser vault status
portoser vault setup-approles
portoser vault migrate      SERVICE
portoser vault migrate-all
portoser vault get          SERVICE
portoser vault put          SERVICE KEY VALUE
portoser vault list

Registry & remote

registry

portoser registry list-services
portoser registry list-machines
portoser registry info         SERVICE
portoser registry machine-info MACHINE
portoser registry validate

remote

portoser remote test-connections
portoser remote exec        MACHINE COMMAND
portoser remote system-info MACHINE

Cluster (Raspberry Pi-focused)

portoser cluster build         [--all|SERVICE]
portoser cluster deploy        [--all|--pi PI]
portoser cluster sync          [PI...]
portoser cluster clean         [PI...]
portoser cluster health        [--watch]
portoser cluster setup-buildx
portoser cluster scan          [PI...]
portoser cluster status        [--json]

These are tuned for arm64 cluster nodes and assume cluster.conf describes them. They overlap with the generic deploy flow but bake in some Pi-specific defaults (rsync sync directories, multi-platform buildx, cleanup of cached layers).

Onboarding & devices

portoser onboard generate-token [--expires HOURS] [--description DESC]

portoser device list
portoser device status HOSTNAME

onboard generate-token is what you hand a fresh machine so it can call the device-registration endpoint. device list / device status show what has registered.

Templates

portoser template list      [--category CAT]
portoser template show      NAME
portoser template use       NAME OUTPUT [--var KEY=VALUE ...] [--interactive]
portoser template create    NAME [--category C] [--description D]
portoser template validate  NAME
portoser template export    NAME
portoser template import    FILE
portoser template status

Categories: backend, frontend, database, infrastructure, plugin. The bundled templates (e.g. fastapi-rest) live under templates/; exported tarballs preserve template metadata so they can be re-imported on another machine.

Exit codes

Code Meaning
0 Success.
1 Generic failure. Most user errors (missing args, unknown service) exit 1 with a human message on stderr.
2 Invalid usage (caught by argument validation before any side-effect).

--json-output mode never prefixes errors with ANSI colors so it's safe to pipe into jq.

See also