CLI
Every dockflow command, its arguments and its options, as the binary defines them.
This page lists every command of dockflow 1.0.0-alpha.6, with the options its --help prints. Start with the conventions and global options, which apply to every command, then look up a command by name. Every command also accepts -h, --help. Exit codes are on the exit codes page.
Conventions
<env>names an environment ofdockflow.yml. You can leave it out when the file has a single environment, or shorten it to a unique prefix (prodforproduction). An ambiguous prefix lists the candidates.<env>in CI.deploywithout<env>takes the environment from the tag.1.2.0selects the environment whoseci.tag_suffixis empty (productionby default);1.2.0-stagingselects the one whose suffix isstaging.- The project directory is the current directory, or
-C <path>. - The server of an environment comes from
--connection, then the<ENV>_CONNECTIONsecret, then the environment'sserverblock. - What is read.
deploy,plan,build,rollback,run,validate,config showandlist servicesreaddockflow.ymland the Compose files, so they need every variable these files use. The commands that act on what the server already runs (status,ps,logs,exec,cp,ssh,restart,stop,scale,destroy,cancel,releases,details,diagnose,images,secrets revokeand theservercommands) readdockflow.ymlalone. On your machine,<ENV>_CONNECTIONis enough for them. - Prompts. On a terminal,
deployshows its plan and asks for confirmation, anddestroyasks before removing anything. With--yes,--jsonor without a terminal, they never prompt. Declining exits with code 130 (run.declined) and changes nothing. - Output. Commands that change a server print events, as JSON Lines with
--json. Read commands print a table, or one JSON document with--json. The fields of these documents may change in a minor release, and human output is not stable either. Scripts should rely on the event stream and the exit codes, which are stable for all of 1.x. - Masking. Secret values are masked in every output, except the output of
exec,runandssh, which is the command's own. - Ctrl+C cancels a command, except while the agent runs on the server. There, the first Ctrl+C asks the agent to stop and roll back; a second one detaches and leaves the run going.
dockflow attachfollows it again.
Global options
| Option | Default | Description |
|---|---|---|
--connection string | none | Use this connection string instead of the environment's secret. @<file> reads it from a file and - from the first line of standard input (not with mcp). Prefer these, or the <ENV>_CONNECTION variable: a string given as is sits on the command line, where other users of the machine can read it, and Dockflow warns about it. |
-C, --dir string | "." | The project directory. |
--json | false | Machine-readable output. |
--no-color | false | No colours. The NO_COLOR environment variable has the same effect. |
-v, --verbose | false | Show debug events. |
-y, --yes | false | Never prompt. |
-h, --help | Help for any command. |
init
dockflow init [flags]Start a project in the current directory (or -C <dir>). It writes:
dockflow.yml, with the app's name and aproductionenvironment whoseDOMAINis--domain;compose.yml, when the directory has no Compose file: awebservice with a route to${DOMAIN}. The service is built from theDockerfile, on the port itsEXPOSEgives (80 without one), or runsnginxwhen there is noDockerfile;.env.dockflowin.gitignore, which is created if needed;- with
--ci github,.github/workflows/deploy.yml; with--ci gitlab,.gitlab-ci.yml. The workflow builds on every branch, deploys on tags, and backs upproductionon a schedule (every night on GitHub; on GitLab, when a pipeline schedule runs it). It pins the CLI to the version that wrote it. Workflows for other providers are in Deploying from CI.
On a terminal, it asks for the name, the domain and the CI provider, unless the flags give them. It replaces no file without --force (init.exists, exit code 2). Check the result with dockflow validate.
| Option | Default | Description |
|---|---|---|
--app string | the directory's name | The app's name: lower case letters, digits and hyphens, at most 24 characters. |
--domain string | <app>.example.com | The domain the app is served at. |
--ci string | none | Write a CI workflow: github or gitlab. |
--force | false | Replace the files that exist. .gitignore only ever gets the lines it lacks. |
validate
dockflow validate [<env>] [flags]Check everything that can be checked without a server, for one environment: dockflow.yml, the Compose files, the x-dockflow settings and every variable they use. Warnings, such as ignored Compose keys, are printed first. It exits with code 0 when the environment is valid and 3 when it is not.
It does not contact the server, render templates or build images.
No options besides the global ones.
config
config show
dockflow config show [<env>] [flags]Print the resolved configuration of an environment, with secrets masked: the app, the environment, the version label, releases.keep, on_failure, where each secret comes from, and the services, networks and volumes as Dockflow will deploy them. The output is YAML, or JSON with --json. It does not contact the server.
No options besides the global ones.
list
list envs
dockflow list envs [flags]The environments of dockflow.yml, with the CI tags that select each one (x.y.z or x.y.z-<suffix>).
No options besides the global ones.
list services
dockflow list services [<env>] [flags]The services of an environment, as Dockflow will deploy them: image, replicas, rollout strategy and routes. It does not contact the server.
No options besides the global ones.
list images
dockflow list images [<env>] [flags]The app's images on the server; with -a, every image of the server.
| Option | Default | Description |
|---|---|---|
-a, --all | false | Every image of the server. |
build
dockflow build [<env>] [flags]Build the images of the services that have build, without deploying.
- Without
--push, images are built on this machine for--platform, and the result is discarded. It only checks that they build, and runs no hook. - With
--push, they are built for the server's architecture and pushed where a deploy would push them. Thebefore_buildandafter_buildhooks run around the build. - With
build.builder: remote, the build runs on the server, and--pushis implied.
A failed build exits with code 7.
| Option | Default | Description |
|---|---|---|
--only strings | all | Build these services only. |
--platform string | linux/<this machine's architecture> | The platform to build for, without --push. |
--push | false | Also push the images to the registry the environment deploys from. |
--skip-hooks | false | Do not run the before_build and after_build hooks. |
plan
dockflow plan [<env>] [flags]Print what a deploy would change, without changing any container. The plan is computed on the server, from what really runs there.
To compare images by content, plan builds and pushes the images first, as a deploy would. With --no-build, built services show as changed. A plan with nothing to do exits with code 0.
| Option | Default | Description |
|---|---|---|
--markdown string | none | Also write the plan to this file as Markdown, for a pull request's comment. |
--no-build | false | Plan without building: built services show as changed. |
--only strings | all | Plan these services only, as deploy --only would deploy them. |
--out string | none | Also write the plan to this file, for dockflow deploy --plan. Not with --no-build. |
--render | false | Also print the service specs that would be sent. |
deploy
dockflow deploy [<env>] [flags]Plan, confirm and apply. The steps, in order:
- the
before_buildhooks, the build and push of images, theafter_buildhooks, thebefore_deployhooks, then the plan. On a terminal, the plan is shown for confirmation, and the agent applies exactly that plan; - on the server, the agent applies the uploads, the jobs, the rollouts, the switch of traffic and the checks;
- once the release is live, the
after_deployhooks run.
If the run fails, the previous release is restored and the after_failure hooks run. on_failure or --no-rollback can keep the failed release in place instead. See how it works and releases and rollbacks.
--only web,worker moves only those services to the new version. Every other service stays as the current release has it, even when compose.yml changed it: it is neither updated nor removed. The new release still records the whole app, so a later full deploy updates the services --only left out. Jobs come from the deployed version and run as on a full deploy. A named service that depends on a service the server does not run is refused (plan.only_dependency).
--skip-build builds nothing: each built service uses the image dockflow build --push pushed for the same version. A CI pipeline can then build in one job and deploy in another. The build hooks do not run. A version that was never pushed fails with build.not_pushed (exit code 7). Images built on the server (build.builder: remote) without an external registry are named after their content, so --skip-build cannot find them.
--plan plan.json applies a plan written by dockflow plan --out plan.json, exactly as it was reviewed. It builds nothing (the plan pins the built images) and asks for no confirmation. It is refused with plan.stale (exit code 6) if anything changed since, on the server or in the project, secrets included. The file holds no secret value, and is readable by its owner only.
--detach returns as soon as the run has started on the server, and prints its run ID; dockflow attach <env> <run> follows it. after_deploy and after_failure hooks that run on your machine or over SSH need the CLI until the end, so --detach refuses them. Webhooks are sent by the CLI, so they are not sent for a detached run.
Exit codes: 5 when another run holds the lock, 7 when the build fails, 8 when the run failed and was rolled back, 9 when it failed and was left in place, 11 when a fatal before_* hook failed. See exit codes.
| Option | Default | Description |
|---|---|---|
--branch string | from git or the CI | The git branch recorded in the release and given to hooks as DOCKFLOW_GIT_BRANCH. |
--detach | false | Return once the run started on the server; follow it with dockflow attach. |
--force | false | Deploy despite a manual lock. |
--no-rollback | false | Leave a failed deploy in place instead of rolling back. It applies to failed HTTP checks; a failed rollout always rolls back. |
--only strings | all | Deploy these services only: the others stay as the current release has them. |
--plan string | none | Apply this plan, written by dockflow plan --out, or fail if anything changed since. |
--skip-build | false | Use the images dockflow build --push pushed for this version instead of building. |
--version string | the git commit | The version label of the release. In CI, a tag's version is used. |
--wait-lock duration | 0 | Wait up to this long for another run's lock instead of failing, like --wait-lock 10m. For CI runs that may overlap. |
rollback
dockflow rollback [<env>] [flags]Re-apply a recorded release, by default the previous one. The rollback becomes a new release in the history, applied with the same rollouts and checks as a deploy. Jobs and hooks do not run. It takes the environment's lock.
| Option | Default | Description |
|---|---|---|
--service string | all | Restore this service only, as the release has it; the other services stay as they are. The new release keeps the current version label. |
--to string | the previous release | The release to restore: its number (see dockflow releases), or a version label such as 1.4.0, for the newest release of that version that went live. |
attach
dockflow attach [<env>] [<run-id>] [flags]Follow a run in progress, or replay a finished one. Without <run-id>, the environment's last run. It exits with the run's exit code.
No options besides the global ones.
cancel
dockflow cancel [<env>] [flags]Ask the running agent to stop and roll back, and follow it until it finishes. It fails with code 2 when no run of the environment is in progress.
No options besides the global ones.
status
dockflow status [<env>] [flags]The current release (number, version, date, author), the services with their running and desired containers, the release each one serves from, its strategy and routes, a degraded flag, the manual lock, and the watchdog's latest restarts. Without <env>, every environment of dockflow.yml.
No options besides the global ones.
releases
dockflow releases [<env>] [flags]The release history of an environment: number, version, status, date and author, with the current release marked. Rollbacks, restarts, stops and scales appear as releases too.
| Option | Default | Description |
|---|---|---|
-n, --count int | 0, all kept releases | Show the n most recent releases. |
--stats | false | Add durations and the success rate. |
version
dockflow version [<env>] [flags]The deployed version of an environment; without <env>, the CLI's own version. An environment that was never deployed exits with code 6.
No options besides the global ones.
ps
dockflow ps [<env>] [flags]The app's containers: name, service, release, state and health.
| Option | Default | Description |
|---|---|---|
-a, --all | false | Include stopped containers and one-off ones. |
details
dockflow details [<env>] [flags]Every service of the current release: strategy, replicas, image, routes, ports, networks, mounts, resources and restart policy, and the names of its environment variables (never their values, with --json too, where each reads KEY=***: they may hold secrets).
No options besides the global ones.
diagnose
dockflow diagnose [<env>] [flags]Why containers don't run: containers that exited, crash loops, failed health checks with their last output, OOM kills, ports in use, services missing containers, and low disk space. It exits with code 9 when it finds a problem, 0 otherwise.
No options besides the global ones.
logs
dockflow logs [<env>] [<service>] [flags]The logs of the app's serving containers, or of one service, with secrets masked. Each line is prefixed with its container when several are shown.
| Option | Default | Description |
|---|---|---|
--all | false | Include the previous release's and stopped containers. |
-f, --follow | false | Keep following the logs. |
-n, --lines string | 100, 20 with -f | Lines per container from the end, or all. |
--no-prefix | false | No container prefix on each line. |
--pick | false | Choose one container. |
--since string | none | Only logs since a timestamp (2026-10-26T14:00:00Z) or a duration (10m). |
--timestamps | false | Show timestamps. |
exec
dockflow exec [<env>] <service> [-- <command>…] [flags]Run a command in a running container of a service; without a command, a shell (bash when the image has it, sh otherwise). It uses the first running container unless --pick is given. It exits with the command's own exit code.
| Option | Default | Description |
|---|---|---|
-e, --env stringArray | none | Set an environment variable, K=V. Repeatable. |
-T, --no-tty | false | No terminal, for scripts. |
--pick | false | Choose the container, when the service has several. |
--sh | false | Open sh, not bash. |
-u, --user string | the container's user | Run as this user. |
-w, --workdir string | the container's directory | Run in this directory. |
run
dockflow run [<env>] <service> [-e K=V]… -- <command>… [flags]Start a one-off container with the service's spec and the image it currently runs, for a console or a script, and remove it when the command ends. It publishes no ports, has no network aliases, and is never restarted. It exits with the command's own exit code.
| Option | Default | Description |
|---|---|---|
-e, --env stringArray | none | Set an environment variable, K=V. Repeatable. |
cp
dockflow cp [<env>] <src> <dest> [flags]Copy files or directories between this machine and a container, either way. The container side is written service:/path; the other side is a local path.
dockflow cp production web:/app/storage/logs ./logs
dockflow cp production ./seed.sql postgres:/tmp/Copying from a container writes inside the local destination only. Symlinks whose target is absolute or leaves the destination are not created, and are reported as warnings (cp.symlink_outside). A file never writes through a symlink in its place: it replaces it.
| Option | Default | Description |
|---|---|---|
--pick | false | Choose the container, when the service has several. |
ssh
dockflow ssh [<env>] [-- <command>…] [flags]Open a shell on the server, or run a command there, with the environment's connection. It exits with the command's own exit code.
No options besides the global ones.
restart
dockflow restart [<env>] [<service>…] [flags]Restart services with their rollout strategy, so routed services restart without downtime. Without a service, it restarts every service except jobs.
It restarts the current release as recorded, and does not read your Compose files. It takes the environment's lock. The first argument is taken as the environment only when it is an environment's exact name.
No options besides the global ones.
stop
dockflow stop [<env>] [<service>…] [flags]Stop services until the next deploy or restart. Without a service, it stops every service except jobs. It takes the environment's lock. The first argument is taken as the environment only when it is an environment's exact name.
No options besides the global ones.
scale
dockflow scale [<env>] <service> <replicas> [flags]Change a service's number of containers until the next deploy, which restores the count of the Compose file. <replicas> is at least 1; to stop a service, use dockflow stop. A stateful service, or one with container_name, cannot run more than once. It takes the environment's lock.
No options besides the global ones.
destroy
dockflow destroy [<env>] [flags]Remove an environment from the server: its containers, routes, networks and state. Volumes are kept unless --volumes is given. It asks for confirmation on a terminal.
With --only, it removes these services only. A remaining service that depends on one of them is an error.
| Option | Default | Description |
|---|---|---|
--only strings | none | Destroy these services only. |
--volumes | false | Also delete the environment's volumes and their data. Only with the whole environment. On a terminal, you type the environment's name to confirm; without a terminal, it needs --yes. |
dockflow destroy --volumes deletes the data of every volume of the environment. There is no undo.
prune
dockflow prune [<env>] [flags]Remove what the server no longer needs. Without a kind option, it removes stopped containers, untagged images and networks that Dockflow does not manage, and runs the registry's garbage collection.
Images of the releases in retention and app volumes are always kept; --volumes removes unused anonymous volumes only. See the cleanup guide.
| Option | Default | Description |
|---|---|---|
-a, --all | false | Every unused image, not only untagged ones. |
--containers | false | Stopped containers. |
--images | false | Untagged images. |
--networks | false | Unused networks. |
--registry | false | The layers of the server's registry that no kept release uses; run it outside deploys. |
--volumes | false | Unused anonymous volumes. |
backup
backup run
dockflow backup run [<env>] [<service>] [--server] [--wait-lock <duration>]Back up the services of the current release that declare x-dockflow.backup, or the one named, to the environment's restic repository. It then applies each service's retention and checks a sample of the repository.
It takes the environment's lock; --wait-lock 10m waits for a deploy to finish. When a service's backup fails, the other services are still backed up, and the command exits with code 12.
--server backs up the server's state instead: /var/lib/dockflow without the backups' passwords, with no lock. See backups and the server's state.
| Option | Default | Description |
|---|---|---|
--server | false | Back up the server's state, /var/lib/dockflow, to the environment's repository. |
--wait-lock duration | 0 | Wait up to this long for a deploy or another run to release the lock, like --wait-lock 10m. |
backup list
dockflow backup list [<env>] [<service>] [--server]The environment's snapshots, or one service's, oldest first: id, time, service, release and size. --server lists the snapshots of the server's state. --json prints them as one document.
| Option | Default | Description |
|---|---|---|
--server | false | List the snapshots of the server's state. |
backup restore
dockflow backup restore [<env>] <service> [--snapshot <id|latest|date>] [--from <env>] [--wait-lock <duration>]Restore a snapshot of the service into the current release, under the environment's lock. A dump is restored with pg_restore --single-transaction --exit-on-error (or the restore command); volumes are restored with the service stopped. It asks for confirmation on a terminal, and needs --yes without one. A failed restore exits with code 12. See restoring.
| Option | Default | Description |
|---|---|---|
--snapshot string | latest | A snapshot id or its beginning, latest, or a date (2026-10-27) or time (RFC 3339) for the newest snapshot taken by then. |
--from string | this environment | Restore a snapshot of another environment, read from its repository. |
--wait-lock duration | 0 | Wait up to this long for the environment's lock. |
backup prune
dockflow backup prune [<env>] [<service>] [--server] [--keep-last n] [--keep-hourly n] [--keep-daily n] [--keep-weekly n] [--keep-monthly n]Apply the retention of the services, or of the one given, and reclaim the space of the forgotten snapshots. --server applies it to the snapshots of the server's state.
With any --keep-* option, the options given replace the whole retention for this run: a rule not given keeps nothing.
| Option | Default | Description |
|---|---|---|
--keep-last int | the service's retention | Keep the n most recent snapshots. |
--keep-hourly int | the service's retention | Keep the most recent snapshot of the n last hours that have one. |
--keep-daily int | the service's retention | Keep the most recent snapshot of the n last days that have one. |
--keep-weekly int | the service's retention | Keep the most recent snapshot of the n last weeks that have one. |
--keep-monthly int | the service's retention | Keep the most recent snapshot of the n last months that have one. |
--server | false | Prune the snapshots of the server's state. |
lock
dockflow lock status|acquire|release [<env>] [flags]Hold an environment's lock by hand, for a maintenance window.
acquiresets a manual lock, which never expires. Untilrelease, every command that takes the lock (deploy,rollback,restart,stop,scale,destroy) is refused with exit code 5, exceptdeploy --force.acquirefails with code 5 when a manual lock is already set, unless--forceis given.releaseremoves the manual lock. Releasing a lock someone else set needs--force.statusshows the manual lock: who set it, when and why.
| Option | Default | Description |
|---|---|---|
--force | false | Take over (acquire) or release (release) someone else's manual lock. |
-m, --message string | none | Why the environment is locked. |
maintenance
dockflow maintenance on|off [<env>] [flags]Answer every route of an environment with a maintenance page, without stopping anything.
onmakes the switch answer the environment's domains with503 Service Unavailableand a maintenance page. The services keep running, and adeploy,rollbackorrestartkeeps the page up. Runningonagain replaces the page and the allowed addresses.offsends the traffic back to the services at once, without a deploy.dockflow statusshows the maintenance mode, since when and who turned it on.
It changes the switch's configuration, which is reloaded, and takes the server's lock rather than the environment's, so it works while a deploy hangs. The other apps of the server are not affected. An environment without routes cannot be put under maintenance.
| Option | Default | Description |
|---|---|---|
--page file | Dockflow's page | An HTML file to show instead, up to 256 KiB. Its assets must be inline or hosted elsewhere: every request of the environment's domains gets the page. |
--allow address | none | An address or CIDR range that still reaches the app, like 203.0.113.7 or 10.0.0.0/8. Repeatable. Behind Cloudflare or an external proxy, it is the client's address the edge vouches for. |
mcp
dockflow mcp [--allow-apply]An MCP server over stdio, for AI assistants: the tools validate, status, releases, logs and plan, each running the command of the same name with --json. See AI agents.
| Option | Default | Description |
|---|---|---|
--allow-apply | false | Also offer deploy, which applies a plan the plan tool computed, by its fingerprint, and rollback, which takes a release number. |
plugins
plugins list
dockflow plugins list [--json]The built-in plugins, and the plugins of the project that dockflow.yml uses, each with its source, description and inputs: type, whether it is required, its default. It needs no server. See plugins.
secrets
secrets list
dockflow secrets list [<env>]Every secret key the environment sees, with its source: CI (the process environment and DOCKFLOW_SECRETS), .env.dockflow, or the SOPS file. Never the values. It needs no server, and lists the keys even when a Compose file uses one that is missing.
secrets set
echo -n "$VALUE" | dockflow secrets set [<env>] <KEY> [--age <recipient>…]Sets KEY in the environment's SOPS file (secrets_file, default secrets/<env>.sops.yaml), and encrypts the file again for the same recipients. The value is read from stdin; on a terminal, it is asked without echo. A file that does not exist yet is created for the --age recipients, or those .sops.yaml's creation_rules give its path. Commit the file: it is encrypted.
| Option | Default | Description |
|---|---|---|
--age strings | .sops.yaml's creation_rules | For a new file: the age recipients to encrypt for. Ignored when the file exists. |
secrets edit
dockflow secrets edit [<env>] [--age <recipient>…]Opens the environment's secrets, decrypted, as KEY: value lines in $VISUAL or $EDITOR (default vi), from a temporary file readable by you only and deleted afterwards, then encrypts the result. Comments of the file are not kept.
| Option | Default | Description |
|---|---|---|
--age strings | .sops.yaml's creation_rules | For a new file: the age recipients to encrypt for. Ignored when the file exists. |
secrets revoke
dockflow secrets revoke [<env>] <name>Deletes from the server every file of the Compose secret <name> that the current release does not use: the old values of a leaked secret leave the server at once. Releases that used them can no longer be rolled back to: their rollback fails with secret.missing.
server
server init
dockflow server init <admin>@<host>[:port] [flags]
sudo dockflow server init [flags] # on the server, outside a project
dockflow server init [<env>] [flags]Prepare a server, or update one. The command has three forms, described below.
With <admin>@<host>, it prepares a server from an administrator's account (root, or a user with passwordless sudo), then prints the connection string for your CI. The steps:
- installs Docker from Docker's repository when it is missing (Debian and Ubuntu; elsewhere, install Docker Engine 27 or later first, or pass
--skip-docker-installto be told so); - creates the deploy user (
dockflow), adds it to thedockergroup, and installs a key generated on this machine, withrestrict,port-forwarding,pty, andfrom=with--from; - with
--harden-ssh, hardens SSH: a drop-in, read before the providers' ones, that refuses passwords and lets root in by key only. Passwords stay allowed while the administrator's account has no key, and nothing is written when that account is root without a key, so you are never locked out. It then checks the values sshd uses, and warns about each one that did not take effect. Without it, SSH is left alone, as is the rest of the server's administration (fail2ban, automatic updates, time synchronisation): see Security model; - with
--nginx, installs nginx, which refuses the host names no vhost serves, with the sudo rules of the nginx plugin; - installs the boot units of the port filter and of Cloudflare's ranges;
- reconnects as the deploy user and installs the switch, the server-local registry and the watchdog.
On a terminal, without --edge or --nginx, it asks how traffic reaches the server's apps. Enter keeps the server's choice, or builtin for a new server. With --yes or --json, it never asks.
The server's host key must be known: in your ~/.ssh/known_hosts, or given with --host-key. Every step can be run again; a new run adds a new key. <host> may be a Host alias of your ~/.ssh/config. Its HostName, Port, User and IdentityFile apply where the target sets none, and the connection string gets the real address.
Without an argument, in a directory without dockflow.yml, it prepares the server it runs on, which must be Linux, as root. The steps are the same, with the key generated in memory and never written to disk. The connection string gives:
- the server's public address: the source address of its route to the internet. A private address is refused; give
--hostinstead; - the SSH port of
sshd_config, following itsIncludelines (22 when it sets none); - the fingerprint of
/etc/ssh/ssh_host_ed25519_key.pub(ecdsa, thenrsa, when there is no ed25519 key).
The deploy user is then checked through the SSH server on 127.0.0.1, as the CI will reach it.
With an environment, it installs or updates the switch and the registry on the server of that environment, reached as for a deploy.
Running it again updates the server, and the switch keeps every app's routes. An option you don't give keeps what the server has. For example, sudo dockflow server init alone, after a new Dockflow is installed, upgrades the watchdog and keeps the edge, its address, the registry and the filter as they were. Give an option to change it. --no-registry=false, --no-port-filter=false and --no-watchdog=false install again what an earlier run left out. See the switch and edges.
| Edge | Effect |
|---|---|
builtin | The switch listens on ports 80 and 443 and obtains certificates. |
cloudflare | As builtin, with ports 80 and 443 open to Cloudflare's ranges only, and the client's address from CF-Connecting-IP. See the cloudflare edge. |
external | The switch listens on --switch-listen (127.0.0.1:8080) in plain HTTP, behind your own proxy, which terminates TLS. See behind nginx. |
none | No switch. Apps publish their own ports; routes are refused. |
| Option | Default | Description |
|---|---|---|
--edge string | the server's, or builtin | How traffic reaches the switch: builtin, cloudflare, external or none. |
--acme-email string | the server's, or none | The address Let's Encrypt writes to about the switch's certificates (expiry, revocation). --acme-email "" removes it. |
--acme-ca string | the server's, or Let's Encrypt then ZeroSSL | The ACME directory the switch gets its certificates from, such as Let's Encrypt's staging, https://acme-staging-v02.api.letsencrypt.org/directory, for a test server. --acme-ca "" goes back to the default. |
--no-registry | false | No server-local registry: every built image goes to registry.url. |
--registry-image string | the registry:3.x.y this version pins, by digest | The image of the server-local registry. |
--switch-image string | the caddy:2.x.y this version pins, by digest | The Caddy image of the switch. |
--no-watchdog | false | No watchdog: unhealthy containers are not restarted, and apps with Compose secrets wait for a deploy after a reboot. |
--no-port-filter | false | No port filter: every port Docker publishes on a public address is open. |
--switch-listen string | 127.0.0.1:8080 | With --edge external: the address the switch listens on. |
--trusted-proxy strings | private ranges | With --edge external: CIDRs whose X-Forwarded-For is trusted. |
-k, --key string | ssh-agent, ~/.ssh | With <admin>@<host>: the administrator's private key. |
--password-file string | none | With <admin>@<host>: a file holding the administrator's password. |
--host-key string | known_hosts | With <admin>@<host>: the server's host key fingerprint (SHA256:…). |
--user string | dockflow | When preparing a server: the deploy user to create. |
--deploy-key string | a new key | When preparing a server: a private key to use for the deploy user instead of generating one. |
--name string | main | When preparing a server: its name in the connection string. |
--skip-docker-install | false | When preparing a server: refuse one without Docker instead of installing it. |
--harden-ssh | false | When preparing a server: write an SSH drop-in that refuses passwords and lets root in by key only, once the administrator has a key. |
--nginx | false | When preparing a server: install nginx in front of the switch (--edge external unless given), refusing unknown host names, with the sudo rules of the nginx plugin. |
--from strings | none | When preparing a server: the addresses or CIDRs the deploy key is accepted from (from= of authorized_keys). Keep it off with hosted CI runners, whose addresses change. |
--host string | its public address | On the server itself: the address or domain name the CI reaches it at. |
--port int | Port of sshd_config, or 22 | On the server itself: the SSH port the CI uses. |
dockflow server init [email protected] --edge externalserver status
dockflow server status [<env>]The server as a whole:
- its settings: edge, port filter, the Dockflow version that last ran
server init; - the Docker version;
- the switch, the registry and the watchdog, with their state and image;
- every app environment on the server, with its current release and how many of its containers run;
- the free disk space.
--json prints it as one document. Without <env>, it shows the server of the only environment of dockflow.yml, or of --connection.
server check
dockflow server check [<env>]Checks what Dockflow needs on the server, each check ok, a warning or a failure, with what to do:
- Docker 27 or newer;
/run/dockflowon a tmpfs, for Compose secrets;/var/lib/dockflowreadable by root only;- the free disk space;
- whether
server initran, and the switch, the registry and the watchdog are running; - the port filter, applied or off;
- ports 80 and 443, when the edge needs them and the switch is not running: free, or held by another program.
It exits with code 0 when no check failed, and 9 (check.failed) when one did. Warnings do not change the exit code.
server edge
dockflow server edge [<env>] builtin|cloudflare|external|none [--switch-listen <addr:port>] [--trusted-proxy <cidr>…]Changes how traffic reaches the server's switch, and keeps every other setting. It is the same as server init <env> --edge <mode>. The switch container is replaced, which interrupts traffic for a moment, and every app's routes are loaded into the new one. none is refused while routes go through the switch. See the switch and edges.
| Option | Default | Description |
|---|---|---|
--switch-listen string | the server's, or 127.0.0.1:8080 | With external: the address the switch listens on. |
--trusted-proxy strings | the server's | With external: CIDRs whose X-Forwarded-For is trusted. |
server upgrade
dockflow server upgrade [<env>]Moves the switch and the registry to the images this version of Dockflow pins, and replaces their containers when the image changed. Each release of Dockflow pins one release of Caddy and of the registry, by digest, so every server upgraded with the same version runs the same images; dockflow server upgrade --help names them. An image you chose with --switch-image or --registry-image, from another repository, is pulled again by its tag instead. The watchdog runs this CLI's agent. Every setting stays.
When the server cannot pull an image, it keeps the one it has and warns (upgrade.pull). Run it after installing a new Dockflow: Caddy's fixes come with Dockflow's releases.
server uninstall
dockflow server uninstall [<env>] [--volumes]Removes Dockflow from the server:
- every app environment: their containers, networks, Compose secrets and releases, and with
--volumes, their volumes and data; - the switch with its certificates, the registry with its images, and the watchdog;
- the shared networks, the port filter's rules, the finished agents and
/var/lib/dockflow.
The backups stay, with their passwords in /var/lib/dockflow/backups/, unless --volumes is given. The deploy user, Docker, the containers Dockflow did not create and Docker's volume plugins always stay.
On a terminal, it asks you to type the server's name. Without a terminal, it needs --yes. Running server init afterwards installs Dockflow again, on an empty server.
| Option | Default | Description |
|---|---|---|
--volumes | false | Also delete the volumes of the app environments, with their data, and the backups on the server. |
server cloud-init
dockflow server cloud-init --host <address> [flags] > user-data.ymlPrints the cloud-init user-data of a new server, to give your provider (DigitalOcean, Hetzner, Scaleway, AWS) when you create it. On its first boot, the server does what server init does before reconnecting: Docker, the deploy user and its key, --harden-ssh, --nginx. The command then prints the connection string on the standard error.
- The deploy key is generated here; only its public part is in the user-data.
- The server's SSH host key is generated here too, and is in the user-data: the connection string pins it before the server exists. Keep the user-data as you would the server's disk, or write it with
-o user-data.yml(mode 600). --hostis required: the address the CI will reach the server at, a reserved IP or a domain name.
The first boot takes a few minutes, mostly to install Docker. cloud-init status --wait on the server returns when it is done; before that, the deploy user does not exist yet. Once it has finished, install the switch, the registry and the watchdog with dockflow server init <env>.
| Option | Default | Description |
|---|---|---|
--host string | required | The address or domain name the CI reaches the server at. |
--port int | 22 | The SSH port the CI uses. |
--user string | dockflow | The deploy user to create. |
--deploy-key string | a new key | A private key to use for the deploy user instead of generating one. |
--name string | main | The server's name in the connection string. |
--from strings | none | The source addresses or CIDRs the deploy key accepts. |
--nginx | false | Install nginx, with the sudo rules of the nginx plugin. |
--harden-ssh | false | Write an SSH drop-in that refuses passwords and lets root in by key only, once root has a key. |
--no-port-filter | false | Do not install the published-port filter's boot unit. |
--skip-docker-install | false | For an image that has Docker: refuse to install it. |
-o, --output string | the standard output | Write the user-data to this file, mode 600. |
server network
dockflow server network create|list|remove [<env>] [<name>]Manage networks shared between the apps of a server, which their Compose files join as external networks. create makes a bridge network owned by the server. remove refuses while containers use it. list shows each one with its containers. See several apps on one server.
server plugin
dockflow server plugin install [<env>] <plugin> [--alias <name>] [<key>=<value>…]
dockflow server plugin list|remove [<env>] [<plugin>]Manage Docker volume plugins, which Compose volumes use with driver. install pulls the plugin, grants the privileges it asks for and prints them, applies its settings and enables it; --alias is its name on the server. remove refuses while volumes use it. Setting values are masked, and list shows only their names. See several apps on one server.
| Option | Default | Description |
|---|---|---|
--alias string | the plugin | With install: the plugin's name on the server, which Compose volumes give as their driver. |
server connection
dockflow server connection [<user@host[:port]>] [flags]Connects to the server, verifying its host key against --host-key or known_hosts, and checks that the user can use Docker. It then prints the connection string: the server, its host key and the private key. Store it in the <ENV>_CONNECTION secret of your CI.
The target's user defaults to dockflow and its port to 22. Without a target, it uses the server of --env, as a deploy would.
dockflow server connection [email protected] -k ~/.ssh/dockflow_ed25519| Option | Default | Description |
|---|---|---|
--env string | none | Without a target: the environment whose server to use. |
--host-key string | none | The server's host key fingerprint (SHA256:…), when known_hosts does not have it. |
-k, --key string | DOCKFLOW_SSH_KEY | The private key file the connection string holds. |
--name string | main | The server's name. |
The connection string holds the private key. Store it as a CI secret, never in the repository.
completion
dockflow completion [command]Generate the autocompletion script of dockflow for a shell: bash, fish, powershell or zsh. Each subcommand prints how to load the script in its --help.
completion bash
dockflow completion bashRequires the bash-completion package. Load it in the current shell with source <(dockflow completion bash).
| Option | Default | Description |
|---|---|---|
--no-descriptions | false | Disable completion descriptions. |
completion fish
dockflow completion fish [flags]Load it in the current shell with dockflow completion fish | source.
| Option | Default | Description |
|---|---|---|
--no-descriptions | false | Disable completion descriptions. |
completion powershell
dockflow completion powershell [flags]Load it in the current shell with dockflow completion powershell | Out-String | Invoke-Expression.
| Option | Default | Description |
|---|---|---|
--no-descriptions | false | Disable completion descriptions. |
completion zsh
dockflow completion zsh [flags]Load it in the current shell with source <(dockflow completion zsh). Completion must be enabled in zsh (autoload -U compinit; compinit).
| Option | Default | Description |
|---|---|---|
--no-descriptions | false | Disable completion descriptions. |
help
dockflow help [command] [flags]Help about any command, the same as dockflow <command> --help.
Not available yet
This version has no ui command. A local web UI may come after 1.0.0. See the roadmap.