Skip to content

Command line

Clicking through the web UI is nice until you do the same thing for the fifth time, or need it in a CI pipeline. That’s what the CLI is for. It’s the same envoryx binary that runs the server: envoryx project …, envoryx backup …, envoryx db …, envoryx worker …, envoryx cron …, envoryx git …, envoryx import and envoryx up talk to a running Envoryx over the REST API, with an API token. It works the same in an SSH session, a cron job or a pipeline.

On the Docker host itself there’s nothing to install - the binary inside the container does the job, and all it needs there is a token:

Terminal window
docker exec -it envoryx envoryx project list

From your laptop or a build agent you tell it once which server to talk to:

Terminal window
envoryx login --url https://envoryx.example.com # asks for the token
envoryx login --url https://envoryx.example.com --token "$ENVORYX_TOKEN"
envoryx whoami # account, scope, projects
envoryx logout

login checks the token and keeps it in ~/.config/envoryx/cli.json (mode 0600). In CI you’ll usually set ENVORYX_URL and ENVORYX_TOKEN instead, which works just as well. If your Envoryx uses the local CA, hand the certificate over once with --ca-cert ~/envoryx-ca.crt (or ENVORYX_CA_CERT); --insecure skips the check altogether.

A token can’t create other tokens, so a leaked one can’t mint its successors. If a script sets up a CI job or an assistant and needs a token for it, it creates one from a shell in the container:

Terminal window
docker exec envoryx envoryx admin create-token --name ci --scope read --project shop --quiet
docker exec envoryx envoryx admin tokens # owner, scope, projects, last use
docker exec envoryx envoryx admin revoke-token ci # by name, id or prefix (stq_…)

create-token acts for the only account unless --user NAME names another, and never gives a token more than that account’s role allows. Without --scope you get operate, --project (repeatable) limits the token to projects, and --quiet prints nothing but the token.

Here’s what’s there, grouped roughly by what you’ll use it for:

Terminal window
envoryx project list # name, slug, state, URL
envoryx project show shop # services, versions, ports, git
envoryx project create "Shop" --php 8.4 --database mariadb --template laravel --start
envoryx project duplicate shop "Shop Test" # config, files and database
envoryx project rename shop "Acme Blog" --yes
envoryx project start|stop|restart shop
envoryx project delete shop --yes [--delete-files]
envoryx project logs shop --service php --tail 200 --follow
envoryx project exec shop -- composer install # any command, any container
envoryx project run shop artisan:migrate # a catalogue action
envoryx project share shop --for 2h # a temporary public address
envoryx project branches shop # its branch environments
envoryx project branch shop feature/login # a copy of shop on that branch
envoryx project deploy shop-feature-login [--no-pull] # pull it and run the deploy commands
envoryx import ./old-site "Old Site" --db dump.sql # an existing website as a project
envoryx import shop-20261010-084321-4ed7a89e.tar # a downloaded backup as a new project
envoryx backup list|create|restore|download|delete shop
envoryx backup offsite|remote|fetch shop … # offsite copies
envoryx backup recover [blog[/<backup>]] [name] # any project on the target, as a new project
envoryx instance backups # Envoryx itself, needs an admin token
envoryx instance backup|download|upload|delete …
envoryx instance restore <backup> --yes --wait # restarts Envoryx, waits for it
envoryx instance offsite|remote|fetch …
envoryx diagnostics [--all] [--strict] # the set-up check, exit code 1 on errors
envoryx audit --project shop --since 2026-10-01 # --user, --action, --search, --export csv
envoryx docker images # Envoryx images no project uses
envoryx docker prune --yes # remove them
envoryx docker orphans [--refresh] # what projects left behind
envoryx docker remove volume <name> --yes
envoryx settings # the instance settings
envoryx settings set public-host=192.168.1.5 force-https=on
envoryx domain list|add|remove shop [api.shop.test] # a project's extra domains
envoryx db snapshot shop --note "before a migration"
envoryx db snapshots shop
envoryx db restore shop <snapshot> --yes
envoryx db clone local --from staging --yes # every db command takes --db NAME
envoryx worker list shop # its workers and their state
envoryx worker presets shop # what a worker can run
envoryx worker add shop queue --preset laravel:queue --arg default,emails
envoryx worker edit|enable|disable|restart shop queue
envoryx worker remove shop queue --yes
envoryx cron list shop # next and last run of each job
envoryx cron add shop backup --schedule "0 3 * * *" -- php artisan backup:run
envoryx cron edit shop backup --schedule @hourly # or a new command after --
envoryx cron run shop backup --wait # now, with output and exit code
envoryx cron runs shop backup [--output] # the recent runs
envoryx cron enable|disable shop backup
envoryx cron remove shop backup --yes
envoryx git status|clone|pull shop
envoryx git checkout shop main

You can name a project by its name, its slug or its id, whatever is at hand. --json gives you the API’s JSON instead of a table, which is what you want in scripts. --service picks a container other than the application container (php, python, go, ruby, node, web, database, redis, … worker:<id>). The URL that project list and project show print is the full one, with the proxy’s port when it doesn’t listen on 443 (https://shop.test:18443), so you can open it as it is.

Workers and cron jobs go by their name or their id. worker edit and cron edit change only what you give them and keep the rest. A cron job runs in the project’s application runtime unless --runtime names another one, and --max-time stops a run after that long (10 minutes if you don’t say). cron run --wait waits for the run, prints its output and ends with the command’s exit code, so a pipeline can run a job and react to how it went. The logs of a worker need its id, which worker list --json shows:

Terminal window
envoryx worker list shop --json | jq -r '.[] | "\(.name) \(.id)"'
envoryx project logs shop --service worker:<id> --follow

envoryx settings lists the instance settings the CLI can change, and settings set takes several NAME=VALUE at once: public-host, base-domain, force-https, projects-follow-envoryx, shared-ide-backends, shared-package-cache, xdebug-client-host, folderview-folder, log-history, log-history-days, log-history-max-mb, metrics-days and ssh-keys. On/off settings take on or off, an empty value clears a text setting, and ssh-keys=@keys.pub reads the keys from a file (they replace all keys there were).

The branch commands work on copies of a project on other branches of its repository. project branch copies the project and deploys the copy once, which takes as long as the project is big. An environment is a project of its own, so project deploy (and every other command) takes its slug as project branches lists it, shop-feature-login for the branch feature/login.

For scripts it also matters how a command ends: 0 means success, 1 failure and 2 a usage error. A missing --yes on a command that deletes or overwrites something counts as a usage error, so it ends with 2 as well. project exec passes on the exit code of the command you ran, so a failing composer install fails your pipeline too. When the server fails, the CLI prints the cause the server sends along, not just “an internal error occurred”.

envoryx project create --help lists every flag. The runtimes are what you’ll look up most:

Flag Meaning
--php VERSION PHP version, e.g. 8.4
--node VERSION Node.js; --node-dev-server, --node-preset vite|next|nuxt|generic
--python VERSION Python; --python-server, --python-preset django|flask|asgi|wsgi|module, --python-app NAME
--go VERSION Go; --go-server builds and runs the server, --go-package ./cmd/server
--ruby VERSION Ruby; --ruby-server runs the server (bundle install first), --ruby-preset rails|rack
--java VERSION Java (17, 21, 25); --java-server runs the server, --java-preset spring-boot|quarkus|jar
--dotnet VERSION .NET SDK (8, 10); --dotnet-server runs the server, --dotnet-preset aspnetcore|dll

For services there are --database TYPE[:VERSION], --expose-database, --add-database NAME=TYPE[:VERSION], --redis, --memcached, --mailpit, --rabbitmq, --storage, --meilisearch, --typesense, --opensearch, --opensearch-dashboards, --ollama and --ollama-gpu. Files and repository come with --path, --docroot, --template, --starter, --git, --branch, --git-username and --git-token. And then there’s --env KEY=VALUE, --secret-env, --start, and --from-json FILE if you’d rather pass the whole create request as JSON.

The CLI can do exactly what its token may do. A read token lists projects and follows logs, an operate token can also start, stop and run commands (restart a worker, run a cron job and read its output), and creating, changing or deleting projects, workers and cron jobs needs admin. Every command shows up in the audit log under the token’s name, so give tokens names you’ll recognise later.

This is what makes the CLI more than a remote control. envoryx.yml describes a project inside its own repository - runtimes, services, domains, environment, workers and cron jobs. Commit it with the code, and anyone with access to Envoryx gets the same environment from a fresh clone with one command:

Terminal window
git clone git@github.com:acme/shop.git && cd shop
envoryx up # creates "shop" on the server, or brings it in line
envoryx up --dry-run # only show what would change
envoryx project manifest shop -o envoryx.yml # write the file for an existing project

If the server doesn’t have a project of that name yet, up clones the repository itself (the origin remote and the branch you have checked out), creates the project exactly as described and starts it. If the project already exists, up applies the differences with a single restart. It never removes anything unless you add --prune.

A manifest looks like this:

version: 1
name: shop
docroot: public
web: {server: nginx}
php:
version: "8.4"
extensions: [bcmath, intl, pdo_mysql, redis, zip]
database: {type: mariadb, version: "11.4"}
databases:
analytics: {type: postgres}
redis: true
mailpit: true
domains: [api.shop.example.com]
env:
APP_ENV: local
secrets: [STRIPE_SECRET] # names only - values never go into the repository
workers:
- {name: queue, preset: "laravel:queue", arg: default}
cron:
- {name: prune, schedule: "0 3 * * *", command: php artisan model:prune, timeout: 5m}
healthcheck: /health

node:, python:, go: and ruby: take the same fields as the wizard (for Ruby: version, server, mode, preset, port, debug, debugPort). Unknown keys are errors - that sounds strict, but it means a typo can never quietly drop a service. Host ports, generated credentials, backup schedules and the values of secrets stay out of the file on purpose; envoryx up asks for missing secrets, or you pass one with --secret KEY=VALUE.

In the web UI, the Git section shows the project as envoryx.yml and applies a changed file after a git pull.