harden nextcloud backups: db dumps, alerting, drift fix
The data-only rsync left no way to restore a working instance: mysql/ and config/ were never backed up, so a recovery would have files but no shares, users or metadata. Dump the database before syncing files (a DB older than the files is repairable with occ files:scan; a newer one references blobs that never made it into the backup) and ship config/ alongside it. Capture the --chmod=Du=rwx,Dgo=rx flag that had been hand-added to the deployed skudak-cloud script. It was outside git, so every deploy silently reverted it. It now lives in backup_rsync_extra_args. Add OnFailure= alerting. The units failed silently before, which is how an iDrive sync failure sat unnoticed since May. msmtp rather than the esmtp already installed: the OpenSRS relay is port 465 (implicit TLS) and libesmtp only speaks STARTTLS. Exclude nextcloud.log* from the sync and cap log_rotate_size. skudak-cloud was running at loglevel 0 and had written a 64 GB log that was being rsynced and pushed to S3; set it to 2 to match the home instance. Stagger the timers (04:00 / 04:30) so both finish before the 05:00 TrueNAS snapshot task, and bound TimeoutStartSec so a wedged rsync cannot leave the unit activating forever and skip every subsequent trigger. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -28,6 +28,27 @@
|
||||
mode: 0755
|
||||
setype: bin_t
|
||||
|
||||
# Shared by every backup instance. Rendered once per include; the second and
|
||||
# later renders are no-ops.
|
||||
- name: template nextcloud backup alert script
|
||||
become: true
|
||||
ansible.builtin.template:
|
||||
src: nextcloud/nextcloud-backup-alert.sh.j2
|
||||
dest: /usr/local/bin/nextcloud-backup-alert.sh
|
||||
owner: root
|
||||
group: root
|
||||
mode: 0755
|
||||
setype: bin_t
|
||||
|
||||
- name: template nextcloud backup failure handler unit
|
||||
become: true
|
||||
ansible.builtin.template:
|
||||
src: nextcloud/nextcloud-backup-failed@.service.j2
|
||||
dest: /etc/systemd/system/nextcloud-backup-failed@.service
|
||||
owner: root
|
||||
group: root
|
||||
mode: 0644
|
||||
|
||||
- name: template {{ backup_name }} backup systemd service
|
||||
become: true
|
||||
ansible.builtin.template:
|
||||
|
||||
@@ -84,10 +84,24 @@
|
||||
vars:
|
||||
container_name: cloud
|
||||
|
||||
# Unbounded by default: nextcloud.log.1 had reached 1.12 GB and was being
|
||||
# rsynced to TrueNAS and pushed to S3 on every run. Cap at 10 MiB.
|
||||
- name: cap nextcloud log rotation size for cloud
|
||||
become: true
|
||||
become_user: "{{ podman_user }}"
|
||||
ansible.builtin.command: >
|
||||
podman exec -u www-data cloud
|
||||
php occ config:system:set log_rotate_size --value 10485760 --type integer
|
||||
register: cloud_log_rotate
|
||||
changed_when: "'System config value log_rotate_size' in cloud_log_rotate.stdout"
|
||||
failed_when: false
|
||||
|
||||
- include_tasks: containers/cloud-backup.yml
|
||||
vars:
|
||||
backup_name: cloud
|
||||
data_path: "{{ cloud_path }}/data"
|
||||
config_path: "{{ cloud_path }}/config"
|
||||
db_container: cloud-db
|
||||
ssh_key_path: /etc/ssh/backup_keys/cloud
|
||||
ssh_key_content: "{{ cloud_backup_ssh_key }}"
|
||||
ssh_user: cloud
|
||||
|
||||
@@ -131,12 +131,44 @@
|
||||
changed_when: "'System config value trusted_domains' in trusted_domain_result.stdout"
|
||||
failed_when: false
|
||||
|
||||
# This instance was left at loglevel 0 (DEBUG) and had written a 64 GB
|
||||
# nextcloud.log, almost entirely repeated deprecation notices. 2 = Warning,
|
||||
# which is both the Nextcloud default and what the home instance already uses.
|
||||
- name: set nextcloud loglevel for skudak-cloud
|
||||
become: true
|
||||
become_user: "{{ podman_user }}"
|
||||
ansible.builtin.command: >
|
||||
podman exec -u www-data skudak-cloud
|
||||
php occ config:system:set loglevel --value 2 --type integer
|
||||
register: skudak_loglevel
|
||||
changed_when: "'System config value loglevel' in skudak_loglevel.stdout"
|
||||
failed_when: false
|
||||
|
||||
# Unbounded by default; see the equivalent task in containers/home/cloud.yml.
|
||||
- name: cap nextcloud log rotation size for skudak-cloud
|
||||
become: true
|
||||
become_user: "{{ podman_user }}"
|
||||
ansible.builtin.command: >
|
||||
podman exec -u www-data skudak-cloud
|
||||
php occ config:system:set log_rotate_size --value 10485760 --type integer
|
||||
register: skudak_log_rotate
|
||||
changed_when: "'System config value log_rotate_size' in skudak_log_rotate.stdout"
|
||||
failed_when: false
|
||||
|
||||
- include_tasks: containers/cloud-backup.yml
|
||||
vars:
|
||||
backup_name: skudak-cloud
|
||||
data_path: "{{ cloud_skudak_path }}/data"
|
||||
config_path: "{{ cloud_skudak_path }}/config"
|
||||
db_container: skudak-cloud-db
|
||||
ssh_key_path: /etc/ssh/backup_keys/skudak-cloud
|
||||
ssh_key_content: "{{ cloud_skudak_backup_ssh_key }}"
|
||||
ssh_user: skucloud
|
||||
remote_path: /mnt/glacier/skudakcloud
|
||||
script_path: /usr/local/bin/skudak-cloud-backup.sh
|
||||
# skudakcloud/data is mode 770, so the receiving side needs traversable
|
||||
# dirs. This flag was hand-added on the host and was being silently
|
||||
# reverted by every `make deploy TAGS=skudak-cloud`; it now lives in git.
|
||||
backup_rsync_extra_args: "--chmod=Du=rwx,Dgo=rx"
|
||||
# Staggered so both instances finish before the 05:00 TrueNAS snapshot.
|
||||
backup_oncalendar: "*-*-* 04:30:00"
|
||||
|
||||
Reference in New Issue
Block a user