Config Archive
Ze archives configuration files to local or remote destinations. Archives can be triggered manually from the CLI, automatically on every editor commit, or on a schedule.
Configuration
Archive destinations are named blocks under system { archive { } }. Each block defines one destination with its own trigger, filename format, and timeout.
system {
host router1;
domain dc1.example.com;
archive local-backup {
location file:///var/backups/ze;
trigger commit;
}
archive offsite {
location https://archive.example.com/configs;
trigger daily;
on-change true;
timeout 10s;
filename "{host}-{date}-{time}";
}
}
Fields
| Field | Type | Default | Description |
|---|---|---|---|
location |
string | (required) | Destination URL |
trigger |
enum | manual |
When to archive: commit, manual, daily, hourly |
filename |
string | {name}-{host}-{date}-{time} |
Filename format with token substitution |
timeout |
duration | 30s |
HTTP upload timeout |
on-change |
boolean | false |
Time-based triggers only: skip if config is unchanged since last archive |
Location Schemes
| Scheme | Behavior |
|---|---|
file:///path |
Writes to local filesystem. Creates parent directories if needed. Files written with 0600 permissions. |
http://host/path |
HTTP POST with text/plain content type. Filename sent in X-Archive-Filename header. |
https://host/path |
Same as HTTP with TLS. |
Use absolute paths for file:// locations. file://./relative does not work correctly in Go's URL parser.
Triggers
| Trigger | When it fires | Fires on boot | Respects on-change |
|---|---|---|---|
commit |
After every editor commit | ✕ | ✕ |
manual |
ze config archive <name> CLI command |
✕ | ✕ |
daily |
Every 24 hours from daemon start | ✓ | ✓ |
hourly |
Every hour from daemon start | ✓ | ✓ |
Time-based triggers (daily, hourly) always fire once on daemon boot regardless of on-change, establishing a baseline. Subsequent ticks respect the on-change flag.
Filename Tokens
| Token | Value | Example |
|---|---|---|
{name} |
Config file basename without extension | router |
{host} |
system.host value |
router1 |
{domain} |
system.domain value |
dc1.example.com |
{date} |
Date as YYYYMMDD |
20260329 |
{time} |
Time as HHMMSS |
143045 |
{archive} |
Archive block name | local-backup |
The .conf extension is always appended. With the default format {name}-{host}-{date}-{time}, a file named router.conf on host router1 produces router-router1-20260329-143045.conf.
System Identity
The system block provides hostname and domain values used in archive filenames and elsewhere.
system {
host router1;
domain dc1.example.com;
}
Both host and domain support $ENV variable expansion. If the value starts with $, the remainder is looked up as an OS environment variable:
system {
host $HOSTNAME;
domain $DOMAIN;
}
If the environment variable is empty or unset, the literal string is kept (e.g., $HOSTNAME stays as-is). When host is not configured, it defaults to unknown. No os.Hostname() fallback is used.
CLI Usage
Archive a configuration to a named destination:
ze config archive <name> <config-file>
The <name> must match a named block under system { archive { } } in the config file. The command parses the config, extracts the named block's settings, and uploads.
ze config archive local-backup router.conf
ze config archive offsite router.conf
Reading from stdin is supported with - as the config file:
cat router.conf | ze config archive local-backup -
If the named block does not exist, the command prints the available archive names and exits with code 1.
Exit Codes
| Code | Meaning |
|---|---|
| 0 | Archive succeeded |
| 1 | Error (missing arguments, block not found, parse failure, upload failure) |
Editor Integration
When the editor starts, it reads archive blocks from the config. Blocks with trigger commit are wired into the editor's commit path. After every successful commit, the editor archives the current config content to all trigger commit destinations.
Archive errors during commit are non-fatal. The commit succeeds and the editor reports the number of archive failures in the status line. Other trigger types (manual, daily, hourly) are not fired by the editor.
Archive locations are read from the config at editor startup. Adding an archive block during an editing session requires restarting the editor for it to take effect.
Fan-Out Behavior
All configured destinations are attempted regardless of individual failures. Errors are collected per destination. A failure uploading to one location does not prevent archiving to other locations.
Change Detection
For time-based triggers with on-change true, ze tracks config changes using SHA-256 hashes in memory. Each named archive block has its own hash. The first check after daemon start always reports "changed" (no baseline yet), so the boot archive fires unconditionally. Subsequent checks compare the current config hash against the last archived hash and skip the archive if unchanged.
The tracker resets on daemon restart since hashes are in-memory only.
Examples
Local backup on every commit
system {
host $HOSTNAME;
archive local {
location file:///var/backups/ze;
trigger commit;
}
}
Every editor commit writes a timestamped copy to /var/backups/ze/.
Daily offsite with change detection
system {
host router1;
domain dc1.example.com;
archive offsite {
location https://archive.example.com/upload;
trigger daily;
on-change true;
timeout 10s;
filename "{host}-{domain}-{date}";
}
}
On daemon boot, archives immediately. Every 24 hours, archives again only if the config has changed. Filename: router1-dc1.example.com-20260329.conf.
Multiple destinations
system {
host edge-01;
archive local {
location file:///var/backups/ze;
trigger commit;
}
archive central {
location https://hub.example.com/configs;
trigger hourly;
on-change true;
}
}
Local backup on every commit. Central server receives a copy hourly (skipped if unchanged). Manual archive to either destination via ze config archive local edge-01.conf or ze config archive central edge-01.conf.
HTTP receiver
The HTTP endpoint receives a POST with:
| Header | Value |
|---|---|
Content-Type |
text/plain |
X-Archive-Filename |
Generated filename (e.g., edge-01-router1-20260329-143045.conf) |
The body is the raw config file content. Any HTTP 2xx response is treated as success.