1## Example setup
2
3[`keld/`](./keld/) is example content for `~/.config/keld`. It contains a config and some env files for the systemd stuff. [`systemd/user/`](./systemd/user/) contains that systemd stuff. Backup runs daily, verify runs monthly, both read from the env files to ping healthchecks.io and let you know whether your backups failed. Both also use mise to install/execute runitor (for healthchecks) and keld.
4
5[`config_long.toml`](./keld/config_long.toml) is more exhaustive.
6
7### 1. Copy the configs
8
9```bash
10mkdir -p ~/.config/keld/timers
11cp -r examples/keld/* ~/.config/keld/
12```
13
14### 2. Edit
15
16Open `~/.config/keld/config.toml` and customize it for your backups:
17
18- Define your presets (e.g., `media@hetzner_media`, `docs@b2_docs`)
19- Set your repository URLs
20- Configure environment variables for authentication
21- Set backup sources via `_arguments`
22
23Backup presets can also define shell hooks:
24
25```toml
26["media@".backup]
27_arguments = ["/home/user/Music/Final"]
28_pre_hooks = ["echo preparing media backup"]
29_post_hooks = ["echo backup finished with $KELD_RESTIC_STATUS"]
30```
31
32`_pre_hooks` run before `restic backup`. If a pre-hook fails, restic is not
33started and post-hooks do not run. `_post_hooks` run after restic is attempted,
34even when restic fails. Post-hooks receive `KELD_RESTIC_STATUS` and, when restic
35started, `KELD_RESTIC_EXIT_CODE`. Use `keld --show-command --preset <preset>
36backup` to preview configured hooks without running them.
37
38Keld status names are based on [restic's documented exit
39codes](https://restic.readthedocs.io/en/stable/075_scripting.html#exit-codes),
40with one extra status for restic start failures:
41
42| Restic exit code | `KELD_RESTIC_STATUS` | Meaning |
43| ---------------- | -------------------- | ------- |
44| 0 | `success` | Restic completed successfully. |
45| 1 | `fatal` | Restic failed; see restic output for details. |
46| 2 | `runtime_error` | Go runtime error. |
47| 3 | `partial` | `backup` could not read some source data. |
48| 10 | `repository_missing` | Repository does not exist. |
49| 11 | `locked` | Restic failed to lock the repository. |
50| 12 | `wrong_password` | Repository password was wrong. |
51| 130 | `interrupted` | Restic was interrupted. |
52| 143 | `terminated` | Restic was terminated by SIGTERM. |
53| other non-zero | `unknown_failure` | Unknown restic failure; treat as failed. |
54| restic not started | `start_failed` | Keld could not start the restic process. |
55
56Repeat this to add backups later.
57
58### 3. Set up healthchecks.io (optional)
59
60Create two checks on [healthchecks.io](https://healthchecks.io) for each backup:
61
62- One for the backup job
63- One for the verify job
64
65Create env files in `~/.config/keld/timers/`:
66
67```bash
68# ~/.config/keld/timers/mybackup@myrepo.env
69CHECK_UUID=your-backup-check-uuid-here
70
71# ~/.config/keld/timers/mybackup@myrepo-verify.env
72CHECK_UUID=your-verify-check-uuid-here
73```
74
75Repeat this to add backups later.
76
77### 4. Install the systemd units
78
79```bash
80mkdir -p ~/.config/systemd/user
81cp examples/systemd/user/* ~/.config/systemd/user/
82```
83
84### 5. Enable and start the timers
85
86For each backup preset you defined (e.g., `media@hetzner_media`):
87
88```bash
89# Escape the @ symbol for systemd instance names
90systemctl --user enable keld-backup@media@hetzner_media.timer
91systemctl --user start keld-backup@media@hetzner_media.timer
92
93systemctl --user enable keld-verify@media@hetzner_media.timer
94systemctl --user start keld-verify@media@hetzner_media.timer
95```
96
97Repeat this to add backups later.
98
99### 6. Verify everything is working
100
101```bash
102# List active timers
103systemctl --user list-timers
104
105# Check service status
106systemctl --user status keld-backup@media@hetzner_media.service
107
108# Test a dry run
109keld --show-command --preset media@hetzner_media backup
110```
111
112Repeat this to add backups later.