Data model
Deployment Identity
Section titled “Deployment Identity”Deployments are identified by a composite key:
tenant + stack + environment = unique deployment- Tenant: Isolation boundary (e.g.,
default,acme-corp) - Stack: The installed app instance (e.g.,
nextcloud,my-blog) - Environment: Deployment context (e.g.,
default,prod,staging)
The deployment_id (used for Docker Compose project naming) is derived:
deployment_id = "{tenant}_{environment}_{stack}"# Example: "default_prod_nextcloud"See Deployment Identity for more details.
Environments
Section titled “Environments”Environments provide deployment isolation within a stack. Common environment names:
| Environment | Purpose |
|---|---|
default | Default when not specified |
prod | Production workloads |
staging | Pre-production testing |
dev | Development and experimentation |
Environment-Specific Config
Section titled “Environment-Specific Config”# Override config for specific environmentshc config set backup.retention_days 14 --scope deploymentshc config set resources.memory_limit 4G --scope deploymentEnvironment Isolation
Section titled “Environment Isolation”| Aspect | Shared Between Environments? |
|---|---|
| App definition | Yes (same app.yaml, compose.yaml) |
| Data volumes | No (each env has own mounts/ directory) |
| Config | Inherited but can be overridden per-env |
| Vault secrets | Can be scoped to environment or shared |
| Docker network | No (each env has own network) |
| Container names | No (prefixed with deployment_id) |
Platform-Specific Paths
Section titled “Platform-Specific Paths”SHC uses a minimal set of directories, following XDG conventions on Linux:
Root Installation (System-Wide)
Section titled “Root Installation (System-Wide)”| Directory | Linux | macOS (Darwin) | BSD |
|---|---|---|---|
state_home | /var/lib/shc | /var/lib/shc | /var/lib/shc |
cache_home | /var/cache/shc | /var/cache/shc | /var/cache/shc |
runtime_dir | /run/shc | /var/run/shc | /var/run/shc |
logs_dir | /var/log/shc | /var/log/shc | /var/log/shc |
User Installation (Per-User)
Section titled “User Installation (Per-User)”| Directory | All Platforms (XDG) |
|---|---|
config_home | ~/.config/shc |
state_home | ~/.local/share/shc |
cache_home | ~/.cache/shc |
runtime_dir | $XDG_RUNTIME_DIR/shc or /tmp/shc-{uid} |
logs_dir | ~/.local/share/shc/logs |
Dev Mode
Section titled “Dev Mode”When running from source (go.mod detected), all paths consolidate under the project:
{project_root}/.shc/├── state/├── cache/├── run/└── logs/What’s NOT in paths.go
Section titled “What’s NOT in paths.go”- Config paths - Configuration is stored in the database, not files
- Backup paths - Backups go to Restic or user-specified paths
- Deployment state paths - Handled by StorageService (provider-dependent)
Directory Structure
Section titled “Directory Structure”Static Paths (paths.go)
Section titled “Static Paths (paths.go)”# State (database only - deployment state handled by StorageService){state_home}/├── shc.db # SQLite database (single-node)├── engine.json # engine marker (present in cluster mode)├── node.id # this node's cluster member id└── rqlite/ # rqlited data (cluster mode: raft log + snapshots)
# Logs (scoped hierarchy, each node has its own logs){logs_dir}/├── shc.log # Global log└── tenants/{tenant}/ └── stacks/{stack}/ └── environments/{environment}/ └── shc.log # Deployment log
# Runtime (ephemeral, cleared on reboot){runtime_dir}/├── shc.pid # Server PID file└── shc.sock # Unix socket
# Cache (can be deleted anytime){cache_home}/└── git/ # Cloned git repositories └── {url_hash}/ # Hashed repo URLDeployment State (StorageService)
Section titled “Deployment State (StorageService)”Deployment state is managed by storage providers, not paths.go. The path depends on the configured storage provider:
# Storage provider base path varies:# - Local: /var/lib/shc/deployments (or configured path)# - NFS: /mnt/shc/nfs (managed NFS mount)# - CephFS: /mnt/shc/cephfs (managed CephFS mount)
{provider_base_path}/{tenant}/{stack}/{environment}/├── compose/ # Generated compose files│ ├── compose.yaml│ └── vars.yaml├── mounts/ # DATA mounts (BACKED UP)│ ├── pgdata/│ └── uploads/├── files/ # FILE mounts (regenerated on install)└── app/ # App definition (copied from repo) ├── app.yaml └── compose.yamlDatabase Modes (Mutually Exclusive)
Section titled “Database Modes (Mutually Exclusive)”| Mode | Database | Path |
|---|---|---|
| Single-node | SQLite (pure-Go, file + WAL) | {state_home}/shc.db |
| Cluster | rqlite (external rqlited process) | {state_home}/rqlite/ |
Cluster mode is detected by the presence of the {state_home}/engine.json
marker; the daemon then supervises rqlited and swaps its pool to the
raft-replicated engine at boot.
Configuration
Section titled “Configuration”All configuration is stored in the database, not in files:
- Single-node: Config table in SQLite
- Cluster: Config table in rqlite (raft-replicated across nodes)
Config supports scoped cascade lookup: global → tenant → stack (most specific wins).
Backups
Section titled “Backups”Backups are not stored in a fixed location. They either:
- Go to Restic (configured via
backup.repo) - Go to an explicit path specified by the user
Key File Locations
Section titled “Key File Locations”| File | Path | Purpose |
|---|---|---|
| SQLite DB | {state_home}/shc.db | Database (single-node) |
| rqlite dir | {state_home}/rqlite/ | Database (cluster) |
| Engine marker | {state_home}/engine.json | Cluster-engine flag |
| PID file | {runtime_dir}/shc.pid | Server process ID |
| Unix socket | {runtime_dir}/shc.sock | CLI-server communication |
| Global log | {logs_dir}/shc.log | System-wide log |
| Deployment log | {logs_dir}/tenants/.../shc.log | Per-deployment log |
| Git cache | {cache_home}/git/ | Cloned git repositories |
Mount Types
Section titled “Mount Types”| Type | Example | Location | Backed Up |
|---|---|---|---|
| DATA | pgdata:/var/lib/postgresql | mounts/pgdata/ | ✅ Yes |
| FILE | ./config.yaml:/app/config.yaml | files/config.yaml | ❌ No (part of app) |
| RUNTIME | tmp:/cache | /tmp/... | ❌ No (ephemeral) |
| SYSTEM | /var/run/docker.sock | unchanged | ❌ No (host path) |
The mounts/ directory contains persistent application data (DATA mounts). This is what gets backed up.
The files/ directory contains config files copied from the app definition (FILE mounts). These are regenerated on install/upgrade, not backed up.
Both mounts/ and files/ are within the deployment state directory, managed by the storage provider.
See Also
Section titled “See Also”- Deployment Identity
- File Locations
backupmodule — backup vs export, restore vs recover, archive formats- Overview