Files
ansible-playbooks/examples/inventory/host_vars.example.yml
T
Clément Désiles 0ec6224941 feat(backup): per-job schedules, stale-lock recovery, service manifests
- Add per-job `schedule` (systemd OnCalendar) overrides and document the
  global `backup_schedule` / `backup_randomized_delay` knobs.
- Run `restic unlock` before backup/forget/check so a run killed mid-flight
  no longer wedges every later run on a stale exclusive lock.
- Publish backup manifests for fdroid, immich and unifi, so the inventory
  decides only where (repositories, retention, schedule).
- Document that `read_data_subset` re-reads on every job targeting the
  repository, so a large repository wants a small fraction.
2026-09-10 16:47:33 +02:00

259 lines
7.8 KiB
YAML

---
# Network configuration
# ---------------------
network_interfaces:
- name: lan0
type: ethernet
mac_address: 02:a0:c9:8d:7e:b6
ipv4:
address: 192.168.1.2/24
gateway: 192.168.1.254
nameservers:
- 1.1.1.1
- 8.8.8.8
- name: lan1
type: ethernet
mac_address: 0a:3f:5b:1c:d2:e4
# Unbound DNS resolver configuration
# ----------------------------------
unbound_custom_lan_domain: "example.lan"
unbound_interfaces:
- { address: "192.168.1.2", comment: "lan0" }
- { address: "192.168.20.4", comment: "wg0" }
unbound_access_control:
- { subnet: "192.168.1.0/24", action: "allow", view: "lan", comment: "lan0" }
- { subnet: "192.168.20.0/27", action: "allow", view: "vpn", comment: "wg0" }
unbound_custom_lan_config_path: "{{ unbound_config_base_path }}/lan.conf"
unbound_custom_lan_records:
"server.example.lan":
v4: 192.168.1.2
aliases:
- "server"
# unbound VPN configuration
unbound_custom_vpn_config_path: "{{ unbound_config_base_path }}/vpn.conf"
unbound_custom_vpn_records:
"server.example.lan":
v4: 192.168.20.4
aliases:
- "server"
unbound_firewall_allowed_sources:
- { src: "192.168.1.0/24", comment: "DNS from LAN" }
- { src: "192.168.20.0/27", comment: "DNS from VPN" }
# Unbound Prometheus exporter (Arch Linux only)
# unbound_exporter_enabled: true
# NTP servers configuration
# -------------------------
ntp_pools:
- "0.uk.pool.ntp.org"
- "1.uk.pool.ntp.org"
- "2.uk.pool.ntp.org"
- "3.uk.pool.ntp.org"
ntp_timezone: "Europe/London"
ntp_allowed_networks:
- "127.0.0.1"
- "::1"
- "192.168.1.0 mask 255.255.255.0"
- "192.168.20.0 mask 255.255.255.224"
ntp_firewall_allowed_sources:
- 192.168.1.0/24 # lan0
- 192.168.20.0/27 # wg0
disk_partitioning:
- device: /dev/nvme0n1
layout_file: inventory_data/partition_layouts/omer.nvme0n1.sfdisk
partitions:
- name: EFI
device: /dev/nvme0n1p1
size: 512M
type: EFI
- name: SWAP
device: /dev/nvme0n1p2
size: 1G
type: swap
- name: ROOT
device: /dev/nvme0n1p3
size: 500G
type: ext4
- name: SLOG
device: /dev/nvme0n1p4
size: 400G
type: zfs
- name: CLUB
device: /dev/nvme0n1p5
size: 2.7TiB
type: zfs
# ZFS pool configuration
# ----------------------
zfs_pools:
- name: omer
type: raidz1
devices:
- ata-SAMSUNG_MZ7LN512HMJP-00000_S1G2NSAF934567
- ata-SAMSUNG_MZ7LN512HMJP-00000_S1G3NSAF934568
options:
ashift: 12
root: /mnt/omer
state: present
zfs_datasets:
- name: omer/photos
extra_zfs_properties:
mountpoint: /mnt/omer/photos
state: present
- name: omer/movies
extra_zfs_properties:
mountpoint: /mnt/omer/movies
state: present
# Wireguard VPN configuration
# ----------------------------
wireguard_tunnels:
- interface: wg0
address: 192.168.20.4/27
dns: 192.168.20.1
server_mode: false
peers:
- name: "Marge server"
public_key: fB6zC8oWpQxN4yR2sT1uA7vJ9kH3mG5eD0cLlI8bV6aF2dP3eXwZ1qY4rU7tO9
allowed_ips:
- 192.168.20.1/32
endpoint: 192.168.1.56:51820
# NFS server configuration
# ------------------------
nfs_clients:
- name: all_wg0_rw_clients
host: "192.168.20.0/255.255.255.224"
options: "rw,sync,no_subtree_check,all_squash,anonuid=1000,anongid=1000,insecure"
- name: laptop_lan0_rw_clients
host: "192.168.1.167"
options: "rw,sync,no_subtree_check,all_squash,anonuid=1000,anongid=1000,insecure"
nfs_shares:
- dir: /mnt/omer/movies
clients: "{{ nfs_clients }}"
- dir: /mnt/omer/photos
clients: "{{ nfs_clients }}"
nfs_server_firewall_allowed_sources:
- 192.168.1.0/24 # lan0
- 192.168.20.0/27 # wg0
nfs_bind_addresses:
- 192.168.20.4
- 192.168.1.2
# Podman configuration
# --------------------
# Address inside containers that maps to the host's loopback (via pasta
# --map-host-loopback). Containers reach host services bound to 127.0.0.1
# by connecting to this address. Defined in roles/podman/defaults/main.yml.
# podman_gw_gateway: 100.64.0.1
# PostgreSQL configuration
# ------------------------
postgres_admin_password: "{{ vault_postgres_admin_password }}"
postgres_bind: "127.0.0.1"
postgres_firewall_allowed_sources:
- 127.0.0.0/8
# Valkey configuration
# --------------------
valkey_admin_password: "{{ vault_valkey_admin_password }}"
valkey_bind: "127.0.0.1"
valkey_firewall_allowed_sources:
- 127.0.0.0/8
# Valkey ACL users
valkey_acl_users:
- username: immich
password: "{{ vault_immich_valkey_password }}"
keypattern: "immich_bull* immich_channel*"
commands: "&* -@dangerous +@read +@write +@pubsub +select +auth +ping +info +eval +evalsha"
# Immich configuration
# --------------------
immich_postgres_password: "{{ vault_immich_postgres_password }}"
immich_valkey_password: "{{ vault_immich_valkey_password }}"
# Backup configuration
# --------------------
# restic: encrypted, deduplicated, incremental. See roles/backup/README.md.
#
# Schedule is a systemd OnCalendar expression. This global default applies to
# every job; a job's own `schedule` overrides it.
# backup_schedule: "Sun *-*-* 03:00:00" # weekly
# backup_randomized_delay: 30m
# Destinations. `repository` is RESTIC_REPOSITORY verbatim. Retention lives
# here: a large local disk can afford more history than metered object storage.
# Each destination can carry its own `notify` channel for fine-tuned alerts.
backup_repositories:
- name: offsite
# Two hosts must never share a repository - keep the paths distinct.
repository: "s3:https://s3.fr1.next.ink/lisez-next/{{ inventory_hostname }}"
password: "{{ vault_backup_offsite_password }}"
env:
AWS_ACCESS_KEY_ID: "{{ vault_backup_s3_access_key }}"
AWS_SECRET_ACCESS_KEY: "{{ vault_backup_s3_secret_key }}"
AWS_DEFAULT_REGION: fr1
retention:
keep_weekly: 4
# Re-hash 5% of the pack files on each run, so the whole repository gets
# verified over time without a full read every week.
read_data_subset: "5%"
notify:
server: https://ntfy.example.org
topic: sys-alerts
token: "{{ vault_backup_ntfy_token }}"
# Removable disk. Skipped without error when it is not plugged in - alert at
# low priority rather than urgent, so a disk in a drawer is a reminder, not
# an alarm.
# - name: usb
# repository: /mnt/backup-usb/restic
# uuid: 1234-5678-90ab # blkid; never /dev/sdX, it renumbers
# mountpoint: /mnt/backup-usb
# fstype: ext4
# password: "{{ vault_backup_usb_password }}"
# retention:
# keep_weekly: 12
# notify:
# topic: backups-reminders
# Always-present filesystem, e.g. a ZFS dataset.
# - name: nas
# repository: /mnt/andromeda/backups/restic
# password: "{{ vault_backup_nas_password }}"
# retention:
# keep_daily: 7
# keep_weekly: 4
# Sources. Dumps are produced once and pushed to every listed repository.
backup_jobs:
# WHAT gets backed up is declared by the service role (ntfy_backup_paths /
# ntfy_backup_exclude / ntfy_backup_sqlite in roles/ntfy/defaults/main.yml);
# only WHERE (repositories, retention, schedule) is decided here. The ntfy
# role knows its storage layout - cache.db is ephemeral and skipped, user.db
# is dumped with sqlite3 .backup rather than copied (torn -wal risk).
- name: ntfy
repositories: [offsite]
paths: "{{ ntfy_backup_paths }}"
exclude: "{{ ntfy_backup_exclude }}"
sqlite: "{{ ntfy_backup_sqlite }}"
# Daily. Weekly jobs omit this and inherit backup_schedule. Retention is
# per-tag, so jobs sharing a repository never prune each other's snapshots.
schedule: "*-*-* 03:00:00"
# Databases only, no files. pg_dumpall --globals-only is always included.
# - name: databases
# repositories: [offsite, nas]
# postgres: all
# command: |
# valkey-cli --rdb "$DUMPS/valkey.rdb"