Manifests
The manifest is the local state of an instance on the host. It holds everything DeployAlly needs to redeploy, update, or recover the service without losing configuration or secrets.
Each instance has its own directory at:
/opt/deployally/<instance_uid>/This directory is the home of the instance: it persists across redeploys, is local to the host (never versioned in git), and contains only what belongs to that instance.
Structure
/opt/deployally/<instance_uid>/
├── state.yaml # Instance metadata
├── secrets/ # Persisted secrets (mode 0700)
│ ├── MARIADB_ROOT_PASSWORD # 0600
│ ├── MARIADB_PASSWORD # 0600
│ └── WP_DB_PASSWORD # 0600
└── config/ # Rendered config files (bind-mount)
├── custom.cnf
└── nginx.conf`state.yaml`
Instance metadata — template reference, applied inputs, chosen profile, IDs of created containers and volumes, timestamps:
schema_version: "3"
instance:
uid: memos-blog-001
species: memos
created_at: "2026-06-05T10:00:00Z"
updated_at: "2026-06-05T10:00:00Z"
template:
spec: "3"
app_version: "0.22.0"
archetype: application
variant: stable
inputs:
WEB_HOSTNAME: memos.example.com
MEMOS_MODE: prod
profile: production
container:
id: "a1b2c3d4e5f6…"
name: memos-blog-001
image: "neosmemo/memos:0.22.0"
storage:
- id: data
kind: volume
docker_volume: memos-blog-001_data
mount: /var/opt/memos
needs:
database:
asset_uid: mariadb-shared
provisioned:
database: wp_memos-blog-001
user: wp_memos-blog-001
state:
status: running
health: healthy
last_check: "2026-06-05T10:05:00Z"`secrets/`
Each secret declared in the template takes one file, named after the secret with permission 0600. The secrets/ directory has permission 0700.
secrets/MARIADB_ROOT_PASSWORD → p4ssw0rd_s3cr3t0_d0_r00t
secrets/WP_DB_PASSWORD → aXc92kf…When the template has secrets.X.persist: true, the secret is written on the first deploy and reused on subsequent redeploys. This guarantees that the database password doesn't change across updates.
`config/`
When the template has storage with kind: config_file, the file is rendered here and bind-mounted into the container. Each redeploy regenerates the file from the template (resolving ${input.X}, ${secrets.X}, etc.) — so configuration changes propagate automatically.
storage:
- id: my-cnf
kind: config_file
mount: /etc/mysql/conf.d/custom.cnf
content: |
[mysqld]
max_connections = ${input.MAX_CONNECTIONS}Result on the host: /opt/deployally/<uid>/config/custom.cnf (mode 0644), mounted read-only at /etc/mysql/conf.d/custom.cnf inside the container.
Why this matters
1. Redeploy is idempotent
Running deployally deploy --species memos --instance-uid memos-blog-001 --apply twice yields the same container, with the same secrets and the same volumes. The manifest is the source of truth.
2. Recovery without losing data
If the container disappears (accident, cleanup, host crash), state.yaml lets you reconstruct everything: the Docker volume keeps its name, secrets stay on disk, inputs are recorded. Just redeploy.
3. Isolated multi-tenant
Each instance has its own directory. Ten WordPress instances on a shared MariaDB mean ten distinct /opt/deployally/wp-* directories, each with its own DB password in secrets/WP_DB_PASSWORD.
4. Auditability
state.yaml records which app_version, which variant, and which inputs produced that container. Who deployed, when, with what config — all traceable without inspecting the container.
Permissions
| Path | Mode | Owner |
|---|---|---|
/opt/deployally/<uid>/ |
0755 |
root |
state.yaml |
0644 |
root |
secrets/ |
0700 |
root |
secrets/<NAME> |
0600 |
root |
config/ |
0755 |
root |
config/<file> |
0644 |
root |
The container process runs as the user defined by the image; bind-mounts are read-only by default.
What's NOT in the manifest
- Not versioned in git. The
/opt/deployally/directory is local to the host and contains secrets — never commit it. - Not stored elsewhere. DeployAlly does not sync manifests to the cloud by default.
- No remote copy of secrets. If you lose the host disk without backup, the secrets are gone.
Backup
Backing up /opt/deployally/ is the operator's responsibility. Recommended:
# Backup all manifests on the host
tar -czf deployally-manifests-$(date +%F).tar.gz /opt/deployally/
# Restore
tar -xzf deployally-manifests-YYYY-MM-DD.tar.gz -C /BackupAlly (a component of the CCS ecosystem) does this automatically when configured, honoring the backup tags declared on each template's storage (backup.tag: critical, backup.frequency: hourly, backup.retain: 168).
Next Steps
- Definitions and Instances — How inputs become secrets and the manifest is populated.
- Templates — How the template declares
storage,secrets, andconfig. - Ecology — How multi-tenant instances share assets.