Appearance
Commands
managed init
Initialize a new managed project. Walks you through an interactive wizard to set up cloud providers, validate credentials, and pick defaults.
bash
managed initThe wizard:
- Asks which cloud providers to configure (DigitalOcean, Hetzner, Linode, OVH)
- Prompts for each provider's credentials and verifies them against the API
- Lets you pick a default region and server size
- Writes
managed.yaml(with${VAR}references) andmanaged.env(with actual secrets) - Adds
managed.envto.gitignoreif you're in a git repo
After init, add services to managed.yaml and run managed apply.
managed plan
Preview what managed apply would change, without touching anything.
bash
managed planReads managed.yaml and your saved state only, it never contacts a cloud provider and never changes anything. Each line shows an action (create, install, configure, firewall, schedule, destroy, remove, keep) and a plain-language reason, so you can sanity-check a config edit before applying it. Run it any time.
It's an intended diff (what your config asks for), not a drift check, the verify step during apply is what catches a service that has actually drifted on a box.
managed apply
Create or update infrastructure to match your managed.yaml.
bash
managed applyThis is the main command. It runs through all apply phases in order: provision storage, create servers, install, configure, firewall, schedules, fleet placement, scale down, and reconcile removals. Every phase is idempotent, re-running skips completed steps.
It shows the plan first. Before making changes, apply prints the same plan as managed plan. If the plan would destroy any server (for example because you removed a service or reduced its replicas), it stops and asks you to confirm, type yes, or pass a flag below. Servers marked protect: true are never destroyed, even with these flags (see Configuration).
| Flag | Description |
|---|---|
--allow-destroy | Permit scale-down to destroy servers that are no longer in managed.yaml (skips the prompt) |
--allow-adopt | Permit locking down adopted/BYOB boxes (base-os: disables root SSH login, enables the firewall) |
--allow-migrate | Permit moving a stranded, rebuild-safe instance (e.g. a replica) to an eligible server |
-f, --force | Skip the confirmation prompt (implies --allow-destroy, --allow-adopt and --allow-migrate) |
--rollback | Restore the bookkeeping from before the last apply (see below) |
--expose | Show generated passwords in the printed connection strings |
--skip-verify | Skip the SSH drift-check of existing servers |
--ignore-unreachable | Continue past servers that fail SSH during verify |
--only <phase> | Run a single phase only (network, install, firewall, configure, verify), see below |
--servers <names> | Limit the run to specific servers (comma-separated) |
External/BYOB boxes you adopt are only locked down (root SSH login disabled, packages upgraded, firewall enabled) when you pass --allow-adopt, and that lock-down runs last, after the private network and all firewall rules are in place, so turning the firewall on can't cut off a service that was working a moment ago. Without --allow-adopt the box is added and managed, but left un-hardened with a warning. See Adopting an existing fleet.
While an apply is running, managed.yaml's state is locked (.managed/state.lock) so a second apply in the same project can't corrupt it. A stale lock from a crashed run is broken automatically.
managed apply --rollback
bash
managed apply --rollbackapply snapshots your state before each run. --rollback restores that snapshot, it rewinds managed's bookkeeping only. It does not recreate or destroy any servers; use it to undo a state change, not infrastructure changes.
managed apply --only <phase>
Run a single phase of apply instead of the whole pipeline:
bash
managed apply --only network # just stand up the private network
managed apply --only firewall --servers web-1 # just (re)apply firewall rules on web-1Valid phases: network, install, firewall, configure, verify. A scoped run never locks down a box, scales anything down, or runs the destroy/adopt confirmation, it does exactly the one phase you named, and --servers narrows it to specific boxes (peer and firewall-source resolution still consider the whole fleet, so a scoped firewall run still allows the right siblings).
This is how you bring an existing fleet under management one careful step at a time. See Adopting an existing fleet.
managed firewall diff
Preview what managed would change about your servers' firewalls, without touching anything, and find out whether turning the firewall on would break something that's working today.
bash
managed firewall diff # check the whole fleet
managed firewall diff web-1 web-2 # check specific servers
managed firewall diff --json # machine-readable output (used by the dashboard)The command was previously called
managed fw;fwstill works as an alias.
It connects to each server read-only and reports, per box:
- open, rules managed would add
- remove, rules managed would take away (for example, narrowing a port that's currently open to the whole internet down to your private network)
- would close, a port that is in use right now but that no rule would keep open. Turning the firewall on would cut it off. This is the important one.
It ends with a verdict and a matching exit code, so a script or the dashboard can gate on it:
| Verdict | Exit code | Meaning |
|---|---|---|
clean | 0 | Safe, nothing in use today would be cut off |
warn | 2 | Allowed, but review the changes (e.g. a public port is being tightened) |
blocked | 3 | Not safe yet, a port in use would be closed; fix it first |
Example:
Firewall preview
web-1 (firewall currently off)
✓ open from 10.100.0.5 to any port 4949 proto tcp
! remove 3306/tcp
✗ port 13337 would be closed, it's in use right now
✗ Not safe yet, turning on the firewall would close a port that's in use
hint: Run 'managed firewall import <server>' to keep those ports open, then check againRun this before you let managed take over a server's firewall (the --allow-adopt lock-down). It's the safety check that answers "is it safe to flip the firewall on yet?".
managed firewall import
Look at the ports a server is using right now and suggest rules to keep them open, so turning managed's firewall on doesn't cut them off. This is the fix for a blocked result from managed firewall diff. It reads the server read-only and changes nothing.
bash
managed firewall import crawler-1 # suggest rules for a server
managed firewall import crawler-1 --json # machine-readable (used by the dashboard)It prints a firewall.allow block you can paste under the server in managed.yaml:
servers:
crawler-1:
firewall:
allow:
- port: 13337
from: privateEach suggested rule is scoped to your private network, the safe default that keeps a port reachable from your own servers without exposing it to the internet. Change from: to public for a port that genuinely serves the internet, overlay for the encrypted mesh only, or a specific IP/CIDR. Then run managed firewall diff <server> to confirm it's clean.
The dashboard's Adopt wizard does this for you with a one-click "keep these ports open".
managed status
Show the current state of all servers and services.
bash
managed statusDisplays server names, IPs (both private and public), status, uptime, and generated credentials.
managed refresh
Check every server against its cloud provider and update what changed.
bash
managed refresh # report and save what changed
managed refresh --prune # also remove servers that are gone
managed refresh --json # machine-readable outputmanaged plan shows what your config asks for; refresh checks the other direction — what happened at the provider outside managed (in the cloud console, for example). It asks each provider about every server managed ordered and reconciles:
- Changes are saved. A new address, a resize, a different region, or a server powered off in the console is written back to managed's records, so later commands work with reality.
- Gone servers are surfaced. A server that was deleted at the provider is reported as no longer existing. With
--pruneit's removed from the project (along with its service records). A server is only treated as gone when the provider definitively says so — a network hiccup or API error just skips that server, so a bad connection can never remove anything. - Unknown servers are listed. Servers running at the provider that this project doesn't track are listed, with a hint to bring one under management via
managed server add.
Servers managed didn't order (imported/BYOB and adopted boxes) have nothing to check at a provider and are skipped with a note.
| Flag | Description |
|---|---|
--prune | Remove servers from the project when they no longer exist at the provider |
--json | Output the result as JSON |
managed server
Manage individual servers (VPS instances).
managed server create
Create a new server at your provider, outside of any service.
bash
managed server create --name worker-1 --region ams3 --size s-1vcpu-1gbmanaged server add
Import an existing server (one managed didn't create) into the managed pool.
bash
managed server add --name legacy-web --ip 203.0.113.7The server is probed over SSH, recorded, and from then on managed like any other box. Nothing is installed or changed until an apply targets it.
managed server scan
List servers at your cloud providers that aren't part of this project yet. Read-only — nothing is changed anywhere.
bash
managed server scan # ask every provider
managed server scan --provider do_prod # ask one providermanaged server import
Import many existing servers at once — everything server scan found, a hand-picked set, or a pasted list of addresses. Each server is probed over SSH and added to the pool exactly like server add adds one; an unreachable box never stops the rest.
bash
managed server import --provider do_prod --all # everything scan finds
managed server import --provider do_prod web-1 web-2 # pick by name, ID, or IP
managed server import [email protected] [email protected]
managed server import --file hosts.txt # one user@ip per lineAfterwards, put the new servers on your private network:
bash
managed apply --only networkmanaged server discover
Probe an existing server's specs over SSH without saving it — a dry run of server add.
bash
managed server discover --ip 203.0.113.7managed server list
List every server in the project with its addresses and status.
bash
managed server listmanaged server bootstrap
Run (or re-run) the base setup on a server — users, SSH hardening, the managed agent.
bash
managed server bootstrap web-1managed server destroy
Destroy one server at its provider.
bash
managed server destroy web-1 # asks for confirmation first
managed server destroy web-1 -f # --force skips the promptSee managed destroy for what is destroyed vs. kept — external/BYOB boxes are removed from the project but never deleted.
managed server trust
Accept a server's new SSH identity after you rebuilt or replaced it.
bash
managed server trust database-1managed remembers each server's SSH identity from the first time it connects (see SSH keys — server identity) and refuses to connect when that identity changes, because a changed identity can mean someone is intercepting the connection.
If you changed the server on purpose — rebuilt it, restored it from an image, or reinstalled its operating system — run this command to forget the old identity. The next connection (for example managed apply) records the new one.
managed server sudo-password
Set, change, or clear the password a server's login user needs for sudo, so managed can run privileged steps on it. Boxes that log in as root or already have passwordless sudo need none.
bash
managed server sudo-password web-1 # prompts, hidden input
MANAGED_SUDO_PASSWORD=… managed server sudo-password web-1
managed server sudo-password web-1 --verify # set, then test that sudo works
managed server sudo-password web-1 --clear # box has passwordless sudoThe password is stored encrypted in the state file (never in managed.yaml). Prefer the MANAGED_SUDO_PASSWORD environment variable over --sudo-password to keep it out of your shell history. You can also set it when importing (managed server add/import --sudo-password, or the same env var), or declare it per-server in managed.yaml as an ${ENV} reference:
yaml
servers:
web-1:
ip: 203.0.113.7
ssh_user: deploy
sudo_password: ${WEB1_SUDO_PW} # resolved from the environment; stored sealedmanaged sudo-password
Set the project-wide default sudo password — a fallback used on any server that has no sudo password of its own. A per-server password (managed server sudo-password) and the MANAGED_SUDO_PASSWORD environment variable both take precedence over it.
bash
managed sudo-password # prompts, hidden input
MANAGED_SUDO_PASSWORD=… managed sudo-password
managed sudo-password --clear # remove the project defaultStored encrypted in the state file (never in managed.yaml). It's optional: leave it unset and servers with no password of their own just use passwordless sudo — which is what managed configures on every box it provisions (SSH-key login, NOPASSWD sudo, the account password locked), so a default is only useful for bring-your-own boxes whose login user needs a sudo password. The resolution order for any server is: its own password → MANAGED_SUDO_PASSWORD → this project default → passwordless.
managed destroy
Tear down infrastructure.
bash
managed destroy # destroy everything
managed service destroy production-db # remove a single service
managed server destroy web-1 # destroy a single serverDestroys servers and cleans up state. managed destroy targets everything; managed service destroy <name> removes one service; managed server destroy <name> removes one server (after a confirmation that tells you exactly what will happen).
Removing a single service handles two kinds of server differently:
- Servers the service owns (it provisioned them) are destroyed,
managed service destroylists them and warns the data is lost. - Servers it only runs on but doesn't own, a
scope: fleetservice on a shared box, or a co-located service, are uninstalled in place: the service is stopped and removed, but the box keeps running. These are listed separately as "uninstalled, box kept".
External servers (defined with ip in managed.yaml) are removed from state but never destroyed, managed never deletes servers it didn't create. Servers with protect: true are never destroyed by scale-down either (an explicit managed destroy still removes them).
Removing a service from managed.yaml and re-running apply has the same effect for the uninstall-in-place case: a removed fleet/co-located service is cleaned off every box automatically. Owned servers are left running and apply tells you to run managed service destroy to tear them down.
managed service migrate
Move a service's instances off a server that's no longer in its placement.
bash
managed service migrate production-db # move stranded instances to eligible serversWhen you edit a service's placement (or remove a server it was on), existing instances stay where they are by default — apply keeps placement sticky so re-runs don't churn, and shows the strand as a migrate action in the plan. To actually move them, run this command (or apply --allow-migrate):
- A rebuild-safe node — any replica — is moved automatically: managed builds it on the new server (a replica reseeds from the primary), then retires the old node (drained in place for a BYOB box, destroyed for a provider-owned one).
- A stateful primary is never moved automatically — that would lose data. The command prints the safe seed → promote → retire steps instead (mysql has the
verify-parity/promoteprimitives to do it; other databases need a manual cutover).
managed service
Inspect installed services and run the commands their packages define.
managed service list
List installed services across all servers.
bash
managed service listmanaged service run
Run a command a service package defines (backups, restores, deploys, …).
bash
managed service run production-db backup
managed service db backup # the two-word shorthand works too
managed service run mysql create-db --server my-db-server --arg db-name=mydbThe name is your configured service from managed.yaml or the package name. The target server is auto-detected when the service runs on exactly one box; use --server (or --service <instance-id>) to pick one otherwise. --arg k=v passes per-invocation arguments to the script.
managed service remove
Remove a service but keep the servers you brought yourself (BYOB/adopted boxes are uninstalled in place, never destroyed).
bash
managed service remove cachemanaged service destroy (see managed destroy) also tears down the servers the service provisioned; managed service migrate is documented below.
managed repl
Open an interactive client (mysql CLI, psql, redis-cli, …) connected to a service.
bash
managed repl production-db # connect to the service's primary
managed repl mysql-a3f2 # or a specific instance by ID
managed repl production-db --role replicaLooks up the service's connection details and credentials, picks the address you can actually reach (public, or the private/overlay address for a firewalled database), and starts the client. The password is handed to the client through its environment — it never appears on a command line, so it can't be read from your shell history or by other users of your machine in the process list.
managed providers
Work with cloud providers and their catalogs.
bash
managed providers verify # test the credentials in managed.yaml
managed providers regions <provider> # list available regions
managed providers sizes <provider> # list sizes (optionally per region)
managed providers catalog <provider> # full provisioning catalog as JSON
managed providers schema # provider auth schemas as JSON (used by the dashboard)managed catalog
List every service package available from your configured repositories (or the official repository when none are configured). With --json it emits each package's full config-form schema.
bash
managed catalogmanaged reserved-ip
Manage retained reputation/egress IPs — provider reserved/floating IPs that outlive a server, so a box can be replaced without losing its sending or crawling reputation. Declare one with reserved_ip: in managed.yaml; managed apply attaches it automatically.
bash
managed reserved-ip list # retained IPs managed knows about
managed reserved-ip attach web-1 # attach the server's configured reputation IP
managed reserved-ip detach web-1 # detach it (the IP is kept, never released)managed export
Reconstruct a managed.yaml from the project's current state — the cloud project, if connected — so a setup edited in the web UI can be checked back into git.
bash
managed exportmanaged lock
View the cloud project lock that prevents concurrent applies on a connected project. managed lock release force-releases a lock left behind by a crashed run — only do this when you're sure no apply is still running.
bash
managed lock
managed lock releasemanaged key
Manage the key that encrypts this project's secrets. Service passwords, storage credentials, and other secrets are stored encrypted inside .managed/state.json (and in the dashboard's copy of it); the key lives outside the project at ~/.config/managed/keys/, so a committed or leaked state file contains only ciphertext. The key is created automatically the first time a secret is saved.
Projects connected to managed.works share the key automatically: the CLI uploads it to the dashboard (protected by the dashboard's own encryption) when it syncs, and managed ui connect downloads it when you adopt the project on a new machine — so teammates and CI usually never handle it by hand.
For a local-only project, print the key with managed key export --reveal, store it in a password manager, and install it on the other machine with managed key import <key>. Without the key, a machine refuses to use the project's encrypted secrets and says so.
bash
managed key export --reveal # print the key once (store it in a password manager)
managed key import <key> # install the key on this machinemanaged login / managed logout
Log this machine in to (or out of) your managed.works account. Login opens a browser; once logged in you can create hosted package repositories, publish to them, and connect projects to the web dashboard.
bash
managed login
managed logoutmanaged ui
Connect or disconnect this project from the managed.works web dashboard.
bash
managed ui connect # link the project (adopts the cloud copy by default)
managed ui disconnect # unlink itmanaged agent
Manage the on-box agent that answers dashboard queries. managed agent start runs the agent server — it's what the systemd unit on a managed box executes; you rarely run it by hand.
managed agent update
Update the managed agent on your servers without redeploying services. Downloads the latest agent binary, restarts the agent process, and leaves everything else untouched.
bash
managed agent update # update all servers
managed agent update --server my-server # update a specific serverUseful when you've made changes to the agent and want to roll them out quickly. All servers are updated in parallel by default.
| Flag | Description |
|---|---|
--server | Target a single server by name (default: all servers) |
managed backup
Trigger an immediate backup for all services that have backup schedules configured.
bash
managed backupmanaged ssh
SSH keys and connections to managed servers.
managed ssh connect
Open an interactive SSH session to a managed server by name.
bash
managed ssh connect --name web-1managed ssh generate-key
Generate a new Ed25519 SSH key pair on this machine.
bash
managed ssh generate-key
managed ssh generate-key --name my-do-key --dir ~/.sshThe key is saved locally — in --dir, or the ssh_key_directory default from managed.yaml, or .managed/ssh_keys in the project. Nothing is uploaded anywhere by this command; managed apply installs the public key on servers it creates when the key is configured as the project's SSH key. An existing key file is never overwritten.
managed repo
Manage service repositories.
managed repo add
Add a remote service repository.
bash
managed repo add managed.works # official repo
managed repo add github.com/my-org/my-services # git repo
managed repo add github.com/my-org/my-services --ref v2 # pin to tagClones the repo, validates it contains service definitions, and adds it to your managed.yaml.
managed repo remove
Remove a previously added repository.
bash
managed repo remove my-servicesmanaged repo list
Show configured repos, their URLs, pinned refs, and available services.
bash
managed repo listmanaged repo update
Fetch the latest version for all repos (or a specific one).
bash
managed repo update # update all
managed repo update my-services # update onemanaged repo pull
Pull the registry repositories configured in managed.yaml (used by fresh workspaces — e.g. the dashboard — before resolving packages).
bash
managed repo pullmanaged repo create
Create a hosted package repository on managed.works (requires managed login).
bash
managed repo create my-packagesmanaged repo link
Add a hosted managed.works repository to this project.
bash
managed repo link my-packagesmanaged repo keygen
Generate an Ed25519 signing keypair for publishing packages. Published packages are signed with it; boxes verify the signature before installing.
bash
managed repo keygenmanaged repo push
Publish a package to your hosted repository. Versions are immutable — bump the version: in service.yaml before publishing a change.
bash
managed repo push services/mysqlmanaged repo reindex
Rebuild the hosted repository's index from the bucket's contents (repair tool — normally push maintains the index).
bash
managed repo reindex my-packagesmanaged project
Register named project directories so managed commands can be run from anywhere. See the Projects guide for the full picture.
managed project save
Register the current directory as a named project.
bash
managed project save feeder # register cwd as "feeder"
managed project save feeder --default # also make it the default
managed -C ~/code/feeder project save feeder # register without cd-ingmanaged project switch
Print export MANAGED_PROJECT=<name> so the surrounding shell can apply it with eval. Every following managed command in that shell uses the named project.
bash
eval $(managed project switch feeder)managed project default
Set the default project. Used when nothing else picks a project (no --project, no MANAGED_PROJECT, no managed.yaml in the current directory).
bash
managed project default feedermanaged project list
List every registered project, mark the default, and show which project is active in the current shell.
bash
managed project listmanaged project remove
Forget about a project. The directory and its files are not touched.
bash
managed project remove feedermanaged version
Print the managed version.
bash
managed versionGlobal flags
These flags work on every managed command:
-v,--verbose, print debug logs.-C <path>,--directory <path>, change to<path>before running.-P <name>,--project <name>, use a registered project for this command. Equivalent to-Cwith the project's saved path.