Stacks
A stack is one YAML file that describes a group of containers you want to run together, for example a web app and its database. You hand the file to Clouduler once. From then on the cluster keeps those containers running, puts them on nodes that can run them, and moves them if a node fails.
If you know Docker Compose, a stack file looks familiar on purpose: it is a subset of Compose v3 with an x-clouduler block for Clouduler-only features such as proxy routes and drive-backed volumes. Every field is listed in the stack spec reference.
How it works
- Deploy stores the YAML in the cluster and bumps the stack's revision. Config and secret files the stack references are bundled with it.
- The scheduler turns each service into one or more instances (named
STACK.SERVICE.INDEX, for examplevaultwarden.app.0) and picks a node for each. See Placement. - The node's daemon creates the container and keeps it running. If the node dies, the instance is placed somewhere else. See Failover.
You can deploy from the web UI or the CLI. Both do the same thing; the difference is how much they check first (see validation).
Deploy a stack
- Web UI
- CLI / config
Open Stacks. If you have none yet, the page shows an empty state with a Deploy stack button (admins only).
- Click Deploy stack (or go to
/stacks/new). - Type the Stack name. Lowercase letters, numbers and dashes are safe.
- Type or paste your YAML into the Spec editor, or use Load from file. The editor autocompletes keys and your cluster's real network, drive and node names.
- Watch the panels fill in as you type:
- Validation shows
Spec is validor a list of problems to fix. - What it needs lists the networks, drives, configs and secrets the spec uses.
- Bundled files appears if the spec references configs or secrets with
file:. Load each file or type its content here. - Where it can run shows, per service, which nodes can host it.
- Validation shows
- Click Deploy NAME. The button stays disabled until the spec is valid. You land on the stack page.
If a step fails you see a red Not deployed banner: The deploy failed while STEP: MESSAGE.
Save the file, then deploy it. The stack name is the file name without its extension unless you pass --name.
clouduler stack deploy ./vaultwarden.yaml
# deployed vaultwarden revision 1, 1 services, 0 bundled files
Files referenced with file: are read relative to the stack file's directory and bundled. Secrets are sealed with the cluster key on the machine you run the command on, so that machine needs the key file.
A minimal stack:
networks:
lan: {}
services:
app:
image: vaultwarden/server:1.32.0
restart: always
networks: [lan]
volumes:
- fast/vaultwarden:/data # drive/volume:/container/path
x-clouduler:
proxy:
- host: vault # becomes vault.<domain of the lan network>
network: lan
port: 80
Validation is the same in the UI and the CLI
The web UI, the HTTP API, the MCP tools and clouduler stack deploy all run the syntax checks and then the cluster checks. A typo like fats/vaultwarden:/data is refused with a message such as drive fats is not defined in cluster.yaml, both by Validate and on Deploy, before anything is stored.
Look at a running stack
- Web UI
- CLI / config
Click a stack in Stacks to open its page. The header shows the revision, number of services and nodes, and when it was deployed.
- Containers: each instance with its state and node, plus recent log lines.
- Placement: why each node can or cannot run each service.
- Spec: the stored YAML and Changes since last deploy.
- Settings: configs and secrets the stack uses, the update webhook, and Remove stack.
clouduler stack list
# vaultwarden revision=1 configs=0 secrets=0 instances=1
clouduler stack show vaultwarden # the stored YAML
clouduler stack unhealthy --all # anything not matching what you asked for
clouduler status # whole cluster at a glance
Update (redeploy)
Changing a stack means deploying a new revision of the same name. Clouduler stores the previous spec so you can see what changed.
- Web UI
- CLI / config
Open the stack and click Redeploy NAME (admins). The Deploy page opens pre-filled with the running spec and the name field disabled. Edit, check Changes to deploy, then click Deploy NAME. The revision goes up by one.
clouduler stack source vaultwarden > vaultwarden.yaml
$EDITOR vaultwarden.yaml
clouduler stack source vaultwarden set vaultwarden.yaml # the stack must already exist
Or run clouduler stack deploy vaultwarden.yaml again.
An identical redeploy still bumps the revision. To pull newer container images without changing the spec, use the Updates page or clouduler update; see Updates.
Stop, start, restart
- Web UI
- CLI / config
The UI controls individual containers. Open the Containers tab, or click an instance to open /instances/vaultwarden.app.0, and use the Restart, Stop and Start buttons there (each label includes the instance id, for example Restart vaultwarden.app.0). Stopping asks for confirmation and the container stays stopped until you start it again.
The stack page (tabs Containers, Placement, Spec, Settings) has no stack-wide stop or start button. To stop every instance at once, use clouduler stack stop NAME on the CLI.
clouduler stack stop vaultwarden # every instance goes to stopped, assignments are kept
clouduler stack start vaultwarden # same instances come back, no redeploy needed
clouduler stack restart vaultwarden # rebuilds each instance's container where it already runs
Remove
- Web UI
- CLI / config
Open the stack, go to Settings, find the Remove stack panel and click Remove NAME. You must type the stack name to confirm. It stops every container of the stack and deletes the stack.
clouduler stack remove vaultwarden
# removed vaultwarden
There is no confirmation prompt on the CLI.
Removing a stack keeps its volumes on the drives, but it also deletes the stack's configs and secrets that no other stack uses. The remove dialog does not mention volumes; it asks you to type the stack name.
Logs
- Web UI
- CLI / config
The Containers tab of a stack shows recent lines for each instance. For the full stream open the instance and go to its logs section (/instances/NAME#logs).
clouduler stack logs vaultwarden -f -n 100 # all instances, merged and ordered by time
clouduler logs vaultwarden.app.0 -f # one instance, exactly as the container wrote it
-n is the number of lines from the end of each container's log (default 200).
Exec and shell
Running a command inside a container is a CLI feature: the web UI does not offer a shell.
clouduler exec vaultwarden.app.0 # tries bash, falls back to sh
clouduler exec vaultwarden.app.0 -- ls -la /data # use -- before a command with flags
clouduler exec -u 1000:1000 vaultwarden.app.0 -- id
It works from any machine that holds the cluster key, wherever the container runs. To debug connectivity, clouduler capture vaultwarden.app.0 -- port 80 runs tcpdump on the right node. See the CLI reference.
Health
A stack is healthy when every instance runs as asked. Clouduler looks at the container state, the Docker healthcheck from your spec (healthcheck:), and the proxy's active check for routed services.
- In the UI, open the stack page. A failing instance shows a tag such as
Restart 3 of 5or a placement problem,. - On the CLI,
clouduler stack unhealthylists instances that are restarting, exited when they should run, failing a health check, stopped bystack stop, or waiting for placement. Add--placementfor the reason (thereason=part of the line below only appears with that flag) and--logs 10for the last lines.stack stop,start,restartandlogson a stack with no running instances fail withstack NAME has no running instances.
vaultwarden 1 unhealthy instance(s)
vaultwarden.app.0 state=pending_placement health=none reason=...
If a service has depends_on, its instance waits until each dependency has an instance running somewhere. A healthcheck block without test: is silently ignored.
Placement basics
Every instance runs on one node. The scheduler picks a node that can hold everything the service needs: the drives it mounts, the networks it uses, any ports it exposes, and any pin or constraint you wrote. If no node qualifies, the instance waits as pending_placement and the Placement tab says why for each node. The full list of reasons is on the Placement page.