Nearly all of it lives under one directory
With the daemon running as root, everything shc keeps sits under the state home, /var/lib/shc. Six places inside it, one outside. Here is what you would lose if each one vanished — and then the one row that may not be on this box at all.
- shc.db every app, tenant and secret you have
- deployments/<tenant>/<stack>/<env>/mounts/deployments/<tenant>/…/mounts/ your apps' actual files 3 homes ↓3 homes
- backups/ every restore point you have taken
- snapshots/control-plane/ rollback for the database above
- certs/ the trust between your nodes
- node.id which cluster this box belongs to
- config.yaml + config.d/*.yaml the settings you wrote by hand
/var/lib/shc the state home — six locations inside it, one outside at /etc/shc
One of those rows has three possible homes
The control plane above is pinned to this box. An app's mount is not. It can be a directory on this disk, a shared filesystem every node can read, or a real cloud disk that attaches to one node at a time and moves. Pick one and see where the bytes sit — and what a dead node costs you.
Three buttons and the theme. Nothing on this page moves on its own.
# in the app's compose file — the whole opt-in x-shc-volumes: pgdata: # Ki/Mi/Gi/Ti, K/M/G/T, or a bare count size: 10Gi # rwo = one writer (default) # rox = read-only, many access: rwo
No x-shc-volumes key means an empty map and the plain host-bind path, byte for byte — that is the stated Phase-0 invariant in internal/core/volume/binding.go. So this block is the only thing standing between a directory and a real disk. An rwo volume attaches to exactly one node at a time; the protocol that keeps it that way when a node vanishes is its own page — volume fencing.
simulated — no daemon, no disk, no cloud API. Lines starting $ are real shc commands; lines starting → name the path each one touches, not captured stdout. Node names are illustrative; the path shapes and commands are real.
These are the root paths, what you get when shcd runs as root. Run it as a normal user and the same tree moves to XDG: state to ~/.local/share/shc, config to ~/.config/shc. SHC_STATE_HOME overrides the root outright. Also under the state home but left off for clarity: staging/, tmp/, shcd.lock. There are exactly three storage-provider kinds — local, nfs, cephfs — and those three names are reserved for the managed singletons. A cloud block volume is a different axis: not a provider row but a per-mount disk, built from a named connection's credentials (hcloud-volume, aws-ebs-volume, gcepd, azure-disk, cinder-volume, dovolume, linode-volume, vultr-volume, cloudstack-volume). Verified against internal/core/paths/paths.go, internal/core/volume/binding.go, internal/daemon/volume_binder.go, internal/daemon/services_seams_volume.go, internal/modules/storage/models.go, internal/modules/storage/storageapi/types.go, internal/modules/storage/connbridge.go, internal/core/config/default.yaml, docs/guide/operations/storage-providers.md and docs/reference/cli/.