/
/
/
Ansible role that can run restic backups and push it to a remote storage server.
1---
2# Backup Role Default Variables
3#
4# What gets backed up, per host:
5# 1. every directory under /docker (one restic snapshot per service,
6# tagged with the service name), minus backup_skip_services
7# 2. backup_data_paths - data outside /docker, backed up hot
8# 3. appliances (Home Assistant, OPNsense) where backup_appliance_enabled
9#
10# New services are included automatically: nothing has to be registered for
11# a /docker/<service> directory to be backed up.
12
13# Operation Mode
14backup_mode: "backup" # backup|restore
15
16# Limit a run to some services (list or comma-separated string; empty = all)
17backup_services: []
18
19# ==============================================================================
20# RESTIC CLIENT
21# ==============================================================================
22# One pinned binary on every host, independent of the distro package (which
23# ranged from 0.12 to 0.16 across hosts). 0.19 rather than 0.18: 0.17-0.18
24# could drop index data during prune on format-v1 repositories - this one.
25backup_restic_version: "0.19.1"
26backup_restic_bin: /usr/local/bin/restic
27backup_restic_checksums:
28 amd64: "f415415624dcc452f2a02b8c33641791a8c6d6d3b65bbb3543fcf9a25151585c"
29 arm64: "a5f64aaab53d51e311fa3829124c5b703f2d14cf187d8640b6be3b2b49376465"
30
31# Repository (credentials from vault)
32restic_repo: "{{ restic_backup_repo | default('rest:http://storage.home:8000/backup') }}"
33restic_password: "{{ restic_backup_password | default('') }}"
34restic_backup_args: [] # extra arguments for every `restic backup`
35
36# Optional second repository. When set, the maintenance stage copies every
37# new snapshot there with `restic copy`. Empty = no off-site copy yet.
38backup_offsite_repo: ""
39backup_offsite_password: ""
40
41# ==============================================================================
42# DOCKER SERVICES
43# ==============================================================================
44backup_docker_root: /docker
45
46# Directories under /docker that are never backed up
47backup_skip_services:
48 - glances # stateless monitoring
49 - gdu # stateless, and stopping it throws away a 15T scan
50 - restic-server # this is the repository itself
51 - appliance-backups # staging dir for OPNsense configs, snapshotted separately
52
53# Per-host additions to the skip list (host_vars)
54backup_host_skip_services: []
55
56# Stop a service's running containers for the duration of its backup, so
57# databases are copied consistently. Only the containers that were running
58# are stopped, and exactly those are started again afterwards - stacks that
59# are deliberately down stay down.
60backup_stop_containers: true
61# Services backed up while running (stateless, or must not go down)
62backup_hot_services: []
63
64# Applied to every /docker service (never to backup_data_paths). Restic
65# matches a pattern without a slash against every path component.
66backup_global_excludes:
67 - "cache"
68 - ".cache"
69 - "logs"
70 - "*.log"
71 - "MediaCover" # *arr artwork, re-downloaded on demand
72 - ".git" # e.g. the CVAT checkout, re-cloned by its role
73
74# Per-service excludes, relative to /docker/<service> (host_vars), e.g.
75# backup_service_excludes:
76# llm-stack: ["ollama/data"]
77backup_service_excludes: {}
78
79# Extra absolute paths that belong to a service and are backed up in the
80# same snapshot, while its containers are stopped (host_vars), e.g. a
81# database that lives in a named Docker volume.
82backup_service_extra_paths: {}
83
84# ==============================================================================
85# DATA PATHS (outside /docker)
86# ==============================================================================
87# Backed up hot, one snapshot each, tagged with `name`. Global excludes do
88# NOT apply here (a git repository must keep its files), only their own.
89# backup_data_paths:
90# - { name: code-repo, path: /mnt/rstorage/code-repo, excludes: [] }
91backup_data_paths: []
92
93# ==============================================================================
94# RETENTION & MAINTENANCE (run once per backup, on the repository host)
95# ==============================================================================
96# Backups run weekly: keep two months of weekly and a year of monthly.
97backup_retention_args: ["--keep-weekly", "8", "--keep-monthly", "12"]
98backup_prune: true
99# Read back this share of the pack data on every run, so the whole repository
100# is verified over time, not just its metadata.
101backup_check_read_subset: "5%"
102
103# ==============================================================================
104# REPORTING TO HOME ASSISTANT
105# ==============================================================================
106# The maintenance stage publishes one retained MQTT sensor through Home
107# Assistant's mqtt.publish service: no HA config changes are needed, and the
108# value survives HA restarts.
109backup_report_enabled: true
110backup_report_ha_url: "{{ vault_runner.homeassistant_url | default('') }}"
111backup_report_ha_token: "{{ vault_runner.homeassistant_token | default('') }}"
112backup_report_validate_certs: false
113backup_report_object_id: homelab_backup
114# The sensors published per run. value templates are evaluated by Home
115# Assistant, so they are !unsafe here: Ansible must not render them.
116backup_report_sensors:
117 - key: status
118 name: "Status"
119 icon: "mdi:backup-restore"
120 value: !unsafe "{{ value_json.status }}"
121 attributes: true
122 - key: last_run
123 name: "Last run"
124 device_class: timestamp
125 value: !unsafe "{{ value_json.finished }}"
126 - key: repo_size
127 name: "Repository size"
128 icon: "mdi:database"
129 unit: "GB"
130 state_class: measurement
131 value: !unsafe "{{ value_json.repo_size_gb }}"
132
133# ==============================================================================
134# CONTAINER HEALTH AFTER RESTART
135# ==============================================================================
136backup_health_check: true
137backup_health_timeout_sec: 300
138backup_health_interval_sec: 10
139
140# ==============================================================================
141# APPLIANCE BACKUP (non-Docker services)
142# ==============================================================================
143backup_appliance_enabled: false
144backup_appliance_staging_dir: /docker/appliance-backups
145
146# Home Assistant: a full backup created through the Supervisor CLI, then the
147# backup directory is snapshotted. Only backups this role created (name
148# prefix) are ever pruned locally - manual ones are left alone.
149backup_ha_enabled: false
150backup_ha_backup_path: /var/lib/homeassistant/backup
151backup_ha_name_prefix: "restic-"
152backup_ha_keep_local: 2
153
154# OPNsense: config.xml downloaded through the API
155backup_opnsense_enabled: false
156backup_opnsense_host: ""
157backup_opnsense_api_key: ""
158backup_opnsense_api_secret: ""
159backup_opnsense_validate_certs: false
160backup_opnsense_keep_local: 3
161