Initial VPS operations handbook
This commit is contained in:
@@ -0,0 +1,21 @@
|
||||
---
|
||||
restic_enabled: false
|
||||
restic_binary: /usr/bin/restic
|
||||
restic_config_path: /etc/vps-restic/repository.env
|
||||
restic_state_dir: /var/lib/vps-restic
|
||||
restic_log_dir: /var/log/vps-restic
|
||||
restic_backup_on_calendar: '*-*-* 04:30:00'
|
||||
restic_check_on_calendar: 'Sun *-*-* 05:30:00'
|
||||
restic_forget_on_calendar: 'Sat *-*-* 05:30:00'
|
||||
restic_keep_daily: 7
|
||||
restic_keep_weekly: 4
|
||||
restic_keep_monthly: 6
|
||||
restic_sources:
|
||||
vaultwarden:
|
||||
- /opt/vaultwarden/backups
|
||||
- /opt/vaultwarden/vw-data
|
||||
pdns:
|
||||
- /opt/pdns/backup
|
||||
- /opt/pdns/auth/pdns.conf
|
||||
# Mailcow is deliberately excluded pending its official consistency and restore
|
||||
# design review. No repository/backend value is supplied by this project.
|
||||
@@ -0,0 +1,4 @@
|
||||
---
|
||||
- name: Reload systemd
|
||||
ansible.builtin.systemd_service:
|
||||
daemon_reload: true
|
||||
@@ -0,0 +1,97 @@
|
||||
---
|
||||
- name: Require explicit Restic opt-in
|
||||
ansible.builtin.assert:
|
||||
that:
|
||||
- restic_enabled | bool
|
||||
fail_msg: >-
|
||||
Restic is disabled by default. Set restic_enabled=true and provision the
|
||||
repository configuration only on the target host after backend approval.
|
||||
|
||||
- name: Validate supported Restic source profile
|
||||
ansible.builtin.assert:
|
||||
that:
|
||||
- healthcheck_profile in restic_sources
|
||||
fail_msg: "No approved Restic source profile for {{ healthcheck_profile }}."
|
||||
|
||||
- name: Verify Restic binary exists on target
|
||||
ansible.builtin.stat:
|
||||
path: "{{ restic_binary }}"
|
||||
register: restic_binary_stat
|
||||
|
||||
- name: Require target-side Restic binary
|
||||
ansible.builtin.assert:
|
||||
that: restic_binary_stat.stat.exists
|
||||
fail_msg: "Install Restic through an approved host maintenance change first."
|
||||
|
||||
- name: Verify target-side repository configuration exists
|
||||
ansible.builtin.stat:
|
||||
path: "{{ restic_config_path }}"
|
||||
register: restic_config_stat
|
||||
|
||||
- name: Require root-only repository configuration
|
||||
ansible.builtin.assert:
|
||||
that:
|
||||
- restic_config_stat.stat.exists
|
||||
- restic_config_stat.stat.mode == '0600'
|
||||
fail_msg: >-
|
||||
Provision {{ restic_config_path }} directly on the host with mode 0600.
|
||||
It must contain RESTIC_REPOSITORY, RESTIC_PASSWORD_FILE, and any backend
|
||||
credentials; do not commit or pass them via Ansible.
|
||||
|
||||
- name: Install Restic state and log directories
|
||||
ansible.builtin.file:
|
||||
path: "{{ item }}"
|
||||
state: directory
|
||||
owner: root
|
||||
group: root
|
||||
mode: "0750"
|
||||
loop:
|
||||
- "{{ restic_state_dir }}"
|
||||
- "{{ restic_log_dir }}"
|
||||
|
||||
- name: Install Restic script directory
|
||||
ansible.builtin.file:
|
||||
path: /usr/local/lib/vps-restic
|
||||
state: directory
|
||||
owner: root
|
||||
group: root
|
||||
mode: "0755"
|
||||
|
||||
- name: Install Restic scripts
|
||||
ansible.builtin.template:
|
||||
src: "{{ item }}.j2"
|
||||
dest: "/usr/local/lib/vps-restic/{{ item }}"
|
||||
owner: root
|
||||
group: root
|
||||
mode: "0750"
|
||||
loop:
|
||||
- backup
|
||||
- check
|
||||
- forget-prune
|
||||
|
||||
- name: Install Restic systemd units and timers
|
||||
ansible.builtin.template:
|
||||
src: "{{ item }}.j2"
|
||||
dest: "/etc/systemd/system/{{ item }}"
|
||||
owner: root
|
||||
group: root
|
||||
mode: "0644"
|
||||
loop:
|
||||
- vps-restic-backup.service
|
||||
- vps-restic-backup.timer
|
||||
- vps-restic-check.service
|
||||
- vps-restic-check.timer
|
||||
- vps-restic-forget-prune.service
|
||||
- vps-restic-forget-prune.timer
|
||||
notify: Reload systemd
|
||||
|
||||
- name: Enable Restic timers
|
||||
ansible.builtin.systemd_service:
|
||||
name: "{{ item }}"
|
||||
enabled: true
|
||||
state: started
|
||||
daemon_reload: true
|
||||
loop:
|
||||
- vps-restic-backup.timer
|
||||
- vps-restic-check.timer
|
||||
- vps-restic-forget-prune.timer
|
||||
@@ -0,0 +1,6 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
# Repository and password credentials are host-local in {{ restic_config_path }}.
|
||||
# shellcheck source=/dev/null
|
||||
source '{{ restic_config_path }}'
|
||||
exec '{{ restic_binary }}' backup --tag '{{ healthcheck_profile }}' --tag "$(hostname -s)" {% for source in restic_sources[healthcheck_profile] %}{{ source | quote }} {% endfor %}
|
||||
@@ -0,0 +1,5 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
# shellcheck source=/dev/null
|
||||
source '{{ restic_config_path }}'
|
||||
exec '{{ restic_binary }}' check --read-data-subset=5%
|
||||
@@ -0,0 +1,5 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
# shellcheck source=/dev/null
|
||||
source '{{ restic_config_path }}'
|
||||
exec '{{ restic_binary }}' forget --prune --keep-daily {{ restic_keep_daily }} --keep-weekly {{ restic_keep_weekly }} --keep-monthly {{ restic_keep_monthly }} --tag '{{ healthcheck_profile }}'
|
||||
@@ -0,0 +1,11 @@
|
||||
[Unit]
|
||||
Description=Restic backup for approved {{ healthcheck_profile }} sources
|
||||
After=network-online.target
|
||||
Wants=network-online.target
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
User=root
|
||||
Group=root
|
||||
UMask=0077
|
||||
ExecStart=/usr/local/lib/vps-restic/backup
|
||||
@@ -0,0 +1,11 @@
|
||||
[Unit]
|
||||
Description=Daily Restic backup timer
|
||||
|
||||
[Timer]
|
||||
OnCalendar={{ restic_backup_on_calendar }}
|
||||
Persistent=true
|
||||
RandomizedDelaySec=20m
|
||||
Unit=vps-restic-backup.service
|
||||
|
||||
[Install]
|
||||
WantedBy=timers.target
|
||||
@@ -0,0 +1,9 @@
|
||||
[Unit]
|
||||
Description=Restic repository integrity check
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
User=root
|
||||
Group=root
|
||||
UMask=0077
|
||||
ExecStart=/usr/local/lib/vps-restic/check
|
||||
@@ -0,0 +1,11 @@
|
||||
[Unit]
|
||||
Description=Weekly Restic integrity check timer
|
||||
|
||||
[Timer]
|
||||
OnCalendar={{ restic_check_on_calendar }}
|
||||
Persistent=true
|
||||
RandomizedDelaySec=30m
|
||||
Unit=vps-restic-check.service
|
||||
|
||||
[Install]
|
||||
WantedBy=timers.target
|
||||
@@ -0,0 +1,9 @@
|
||||
[Unit]
|
||||
Description=Restic retention and prune
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
User=root
|
||||
Group=root
|
||||
UMask=0077
|
||||
ExecStart=/usr/local/lib/vps-restic/forget-prune
|
||||
@@ -0,0 +1,11 @@
|
||||
[Unit]
|
||||
Description=Weekly Restic retention timer
|
||||
|
||||
[Timer]
|
||||
OnCalendar={{ restic_forget_on_calendar }}
|
||||
Persistent=true
|
||||
RandomizedDelaySec=30m
|
||||
Unit=vps-restic-forget-prune.service
|
||||
|
||||
[Install]
|
||||
WantedBy=timers.target
|
||||
Reference in New Issue
Block a user