Provisioned Resources
Manage repositories and volumes through a configuration file with secret references
Zerobyte can sync operator-managed repositories and volumes from a JSON configuration file at startup. This is useful when you want credentials and connection details to live in deployment-time configuration instead of being entered through the UI.
What Provisioning Supports Today
Provisioning currently supports:
- repositories
- volumes
- secret references through
env://andfile:// - updating managed resources in place by keeping the same
id - deleting managed resources with
"delete": true
Provisioning does not currently support:
- backup jobs or schedules
- notification destinations
- exporting UI-created resources back into provisioning JSON
- live reloading without restarting the Zerobyte container
Provisioning is limited to repositories and volumes in schema version 1. If you need to manage backup jobs or
notifications, create them through the UI or API for now.
Prerequisites
- A running Zerobyte instance with an organization ID
- The
PROVISIONING_PATHenvironment variable pointing to your JSON file
Find your organization ID
- Sign in to Zerobyte and switch to the organization you want to provision into
- Open Settings
- Open the Organization tab
- Copy the read-only Organization ID value from Organization Details
The Organization tab is only visible to organization admin and owner members. If you do not see it, ask an
organization admin or owner for the ID, or have them grant you the required role first.
Quick Start
Create the provisioning file
Create a provisioning.json file:
{
"version": 1,
"repositories": [
{
"id": "local-repo",
"organizationId": "your-organization-id",
"name": "Primary Local Repository",
"backend": "local",
"compressionMode": "auto",
"config": {
"backend": "local",
"path": "/var/lib/zerobyte/repositories/primary",
"isExistingRepository": false
}
}
],
"volumes": [
{
"id": "documents",
"organizationId": "your-organization-id",
"name": "Documents",
"backend": "directory",
"autoRemount": true,
"config": {
"backend": "directory",
"path": "/data/documents"
}
}
]
}Mount the file and configure Zerobyte
Mount the provisioning file and set PROVISIONING_PATH:
services:
zerobyte:
image: ghcr.io/nicotsx/zerobyte:latest
environment:
- PROVISIONING_PATH=/config/provisioning.json
volumes:
- ./provisioning.json:/config/provisioning.json:ro
- /var/lib/zerobyte:/var/lib/zerobyte
- /srv/documents:/data/documentsStart or restart Zerobyte
docker compose up -dOn startup, Zerobyte reads the provisioning file, resolves supported secret references, encrypts the resolved secret values, and syncs the managed resources into the database.
Root File Format
The root object always has the same shape:
{
"version": 1,
"repositories": [],
"volumes": []
}| Field | Required | Notes |
|---|---|---|
version | yes | Must be 1 |
repositories | no | Array of provisioned repositories. Defaults to [] |
volumes | no | Array of provisioned volumes. Defaults to [] |
Repository Entry Reference
Each item in repositories uses this top-level shape:
{
"id": "repo-id",
"organizationId": "org-id",
"name": "Repository Name",
"backend": "local",
"compressionMode": "auto",
"delete": false,
"config": {
"backend": "local",
"path": "/var/lib/zerobyte/repositories/repo-id"
}
}| Field | Required | Notes |
|---|---|---|
id | yes | Stable provisioning identifier inside the organization. Keep this stable if you want Zerobyte to update the same resource in place |
organizationId | yes | Must match an existing organization |
name | yes | Display name in Zerobyte |
backend | yes | Must be one of local, s3, r2, gcs, azure, rclone, rest, sftp |
compressionMode | no | off, auto, or max |
delete | no | Defaults to false |
config | yes | Backend-specific object. config.backend must match the top-level backend value |
Repository Shared Config Fields
These fields are available inside every repository config object:
| Field | Required | Notes |
|---|---|---|
isExistingRepository | no | When true, Zerobyte treats the repository as already initialized. When omitted or false, a newly created provisioned repository is initialized with restic init on first sync |
customPassword | no | Overrides the organization-level repository password |
cacert | no | Custom CA certificate contents |
insecureTls | no | Disables TLS verification for supported backends |
uploadLimit | no | Bandwidth limit object |
downloadLimit | no | Bandwidth limit object |
Bandwidth limit objects use this shape:
{
"enabled": true,
"value": 10,
"unit": "Mbps"
}unit must be one of Kbps, Mbps, or Gbps.
Repository Backends
| Field | Required | Notes |
|---|---|---|
path | yes | Path inside the Zerobyte container |
{
"backend": "local",
"path": "/var/lib/zerobyte/repositories/primary",
"isExistingRepository": false
}| Field | Required | Notes |
|---|---|---|
endpoint | yes | Example: https://s3.amazonaws.com |
bucket | yes | Bucket name |
accessKeyId | yes | Supports secret references |
secretAccessKey | yes | Supports secret references |
{
"backend": "s3",
"endpoint": "https://s3.amazonaws.com",
"bucket": "company-backups",
"accessKeyId": "env://AWS_ACCESS_KEY_ID",
"secretAccessKey": "file://aws_secret_access_key",
"isExistingRepository": true
}| Field | Required | Notes |
|---|---|---|
endpoint | yes | Your Cloudflare R2 S3 endpoint |
bucket | yes | Bucket name |
accessKeyId | yes | Supports secret references |
secretAccessKey | yes | Supports secret references |
{
"backend": "r2",
"endpoint": "https://<account-id>.r2.cloudflarestorage.com",
"bucket": "zerobyte-backups",
"accessKeyId": "env://R2_ACCESS_KEY_ID",
"secretAccessKey": "env://R2_SECRET_ACCESS_KEY",
"isExistingRepository": true
}| Field | Required | Notes |
|---|---|---|
bucket | yes | Bucket name |
projectId | yes | Google Cloud project ID |
credentialsJson | yes | Service account JSON. Supports secret references |
{
"backend": "gcs",
"bucket": "zerobyte-backups",
"projectId": "my-gcp-project",
"credentialsJson": "file://gcs_credentials_json",
"isExistingRepository": true
}| Field | Required | Notes |
|---|---|---|
container | yes | Blob container name |
accountName | yes | Storage account name |
accountKey | yes | Supports secret references |
endpointSuffix | no | Custom endpoint suffix |
{
"backend": "azure",
"container": "zerobyte-backups",
"accountName": "storageaccount",
"accountKey": "env://AZURE_STORAGE_ACCOUNT_KEY",
"endpointSuffix": "core.windows.net",
"isExistingRepository": true
}| Field | Required | Notes |
|---|---|---|
remote | yes | Name of the configured rclone remote |
path | yes | Path inside that remote |
{
"backend": "rclone",
"remote": "remote-name",
"path": "zerobyte/backups",
"isExistingRepository": true
}| Field | Required | Notes |
|---|---|---|
url | yes | Base REST server URL |
username | no | Supports secret references |
password | no | Supports secret references |
path | no | Optional path below the REST endpoint |
{
"backend": "rest",
"url": "https://rest-server.example.com",
"username": "env://REST_USERNAME",
"password": "file://rest_password",
"path": "zerobyte",
"isExistingRepository": true
}| Field | Required | Notes |
|---|---|---|
host | yes | SFTP hostname |
port | no | Defaults to 22 |
user | yes | SSH username |
path | yes | Remote repository path |
privateKey | yes | Private key contents. Supports secret references |
skipHostKeyCheck | no | Defaults to false |
knownHosts | no | Contents of a known hosts file |
{
"backend": "sftp",
"host": "backup.example.com",
"port": 22,
"user": "backup",
"path": "/srv/restic",
"privateKey": "file://sftp_private_key",
"skipHostKeyCheck": false,
"knownHosts": "backup.example.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAI..."
}Volume Entry Reference
Each item in volumes uses this top-level shape:
{
"id": "volume-id",
"organizationId": "org-id",
"name": "Volume Name",
"backend": "directory",
"autoRemount": true,
"delete": false,
"config": {
"backend": "directory",
"path": "/data/volume"
}
}| Field | Required | Notes |
|---|---|---|
id | yes | Stable provisioning identifier inside the organization |
organizationId | yes | Must match an existing organization |
name | yes | Display name in Zerobyte |
backend | yes | Must be one of nfs, smb, directory, webdav, rclone, sftp |
autoRemount | no | Defaults to true |
delete | no | Defaults to false |
config | yes | Backend-specific object. config.backend must match the top-level backend value |
Volume Backends
| Field | Required | Notes |
|---|---|---|
path | yes | Path inside the Zerobyte container |
readOnly | no | If provided, it must be false |
{
"backend": "directory",
"path": "/data/documents"
}| Field | Required | Notes |
|---|---|---|
server | yes | NFS server hostname or IP |
exportPath | yes | Exported path on the server |
port | no | Defaults to 2049 |
version | yes | Must be 3, 4, or 4.1 |
readOnly | no | Mount the volume read-only |
{
"backend": "nfs",
"server": "10.0.0.10",
"exportPath": "/exports/media",
"port": 2049,
"version": "4.1",
"readOnly": true
}| Field | Required | Notes |
|---|---|---|
server | yes | SMB server hostname or IP |
share | yes | Share name |
username | no | Login username |
password | no | Supports secret references |
guest | no | Use guest authentication |
vers | no | 1.0, 2.0, 2.1, 3.0, or auto. Defaults to auto |
domain | no | SMB domain or workgroup |
port | no | Defaults to 445 |
readOnly | no | Mount the volume read-only |
{
"backend": "smb",
"server": "fileserver.local",
"share": "team",
"username": "backup-user",
"password": "env://SMB_PASSWORD",
"vers": "3.0",
"domain": "WORKGROUP",
"port": 445,
"readOnly": false
}| Field | Required | Notes |
|---|---|---|
server | yes | WebDAV hostname, without scheme |
path | yes | Remote path |
username | no | Login username |
password | no | Supports secret references |
port | no | Defaults to 80 |
readOnly | no | Mount the volume read-only |
ssl | no | Enable HTTPS |
{
"backend": "webdav",
"server": "cloud.example.com",
"path": "/team-a",
"username": "team-a",
"password": "env://WEBDAV_PASSWORD",
"port": 443,
"ssl": true
}| Field | Required | Notes |
|---|---|---|
host | yes | SFTP hostname |
port | no | Defaults to 22 |
username | yes | SSH username |
password | no | Supports secret references |
privateKey | no | Private key contents. Supports secret references |
path | yes | Remote path |
readOnly | no | Mount the volume read-only |
skipHostKeyCheck | no | Defaults to false |
knownHosts | no | Contents of a known hosts file |
{
"backend": "sftp",
"host": "files.example.com",
"port": 22,
"username": "backup-user",
"privateKey": "file://volume_sftp_private_key",
"path": "/srv/data",
"readOnly": true,
"skipHostKeyCheck": false,
"knownHosts": "files.example.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAI..."
}| Field | Required | Notes |
|---|---|---|
remote | yes | Name of the configured rclone remote |
path | yes | Path inside that remote |
readOnly | no | Mount the volume read-only |
{
"backend": "rclone",
"remote": "remote-name",
"path": "team-a",
"readOnly": true
}Secret References
Supported secret references use one of these prefixes:
| Reference | Resolves From | Example |
|---|---|---|
env://VARIABLE_NAME | Container environment variables | env://AWS_ACCESS_KEY_ID |
file://secret_name | /run/secrets/secret_name | file://aws_secret_access_key |
file:// references always resolve from /run/secrets/ and must be a single filename, not a nested path.
Only specific fields are resolved as secret references. Other string fields are treated literally.
Repository fields that support secret references
- shared fields:
customPassword,cacert s3:accessKeyId,secretAccessKeyr2:accessKeyId,secretAccessKeygcs:credentialsJsonazure:accountKeyrest:username,passwordsftp:privateKey
Volume fields that support secret references
smb:passwordwebdav:passwordsftp:password,privateKey
Resolved secret values are encrypted before Zerobyte stores them in the database.
Rotating Secrets
To rotate a provisioned secret:
- Update the environment variable or secret file
- Restart Zerobyte with
docker compose restart
Zerobyte re-resolves supported secret references on each startup.
Updating And Removing Managed Resources
- Keep the same
idto update a managed resource in place - Changing only
namekeeps the same underlying resource record - Setting
"delete": trueremoves the managed resource on the next startup sync
Deletion entries still need the normal entry shape today because the provisioning file is validated before Zerobyte applies the delete flag:
{
"id": "repo-to-remove",
"organizationId": "your-organization-id",
"name": "Repo to remove",
"backend": "local",
"delete": true,
"config": {
"backend": "local",
"path": "/var/lib/zerobyte/repositories/old",
"isExistingRepository": true
}
}Troubleshooting
No matching discriminator
This error usually means one of these is wrong:
backendis not a valid value for that resource typeconfig.backenddoes not match the top-levelbackend- the
configobject does not match the required fields for that backend
Secret reference errors
env://NAMErequires the environment variable to exist in the Zerobyte containerfile://namerequires/run/secrets/nameto exist- Zerobyte stops syncing when it hits a provisioning error, so fix the first reported error and restart again
Important Notes
Each provisioned entry must reference an existing organizationId. Complete first-run setup before enabling
provisioning so you have a valid organization ID.
- Changes to
provisioning.jsononly apply on container restart - Provisioned resources appear in the normal UI and are marked as managed
- Editing a provisioned resource in the UI is useful for testing, but the next provisioning sync can overwrite it
