diff --git a/active/software_borg/backup.service b/active/software_borg/backup.service index 3604a22..75223b7 100644 --- a/active/software_borg/backup.service +++ b/active/software_borg/backup.service @@ -1,12 +1,12 @@ [Unit] -Description=Runs backup script for {{ repo_name }} +Description=Runs the Borg backup script at /usr/local/script/borg-backup.sh After=network.target Wants=network-online.target [Service] Restart=no Type=oneshot -ExecStart=/usr/local/script/backup-{{ repo_name }}.sh +ExecStart=/usr/local/script/borg-backup.sh [Install] WantedBy=multi-user.target \ No newline at end of file diff --git a/active/software_borg/backup.sh.j2 b/active/software_borg/backup.sh.j2 index 3d8d31d..62eb481 100644 --- a/active/software_borg/backup.sh.j2 +++ b/active/software_borg/backup.sh.j2 @@ -1,5 +1,7 @@ #!/bin/sh +set -x + {% for service in stop_services %} systemctl stop {{ service }} {% endfor %} @@ -8,8 +10,12 @@ systemctl stop {{ service }} systemctl --user --machine={{ systemd_user }}@.host stop {{ service }} {% endfor %} +{% for compose in docker_compose_down %} +docker compose -f {{compose}} down +{% endfor %} + # Setting this, so the repo does not need to be given on the commandline: -export BORG_REPO={{ borg_user }}@{{ borg_host }}:{{ repo_name }} +export BORG_REPO={{ borg_user }}@{{ borg_host }}:. # See the section "Passphrase notes" for more infos. export BORG_PASSPHRASE={{ borg_passphrase }} @@ -34,6 +40,7 @@ borg create \ --exclude 'home/*/.cache/*' \ --exclude 'var/tmp/*' \ --exclude 'home/*/.snapshots/*' \ + --exclude 'home/.snapshots/*' \ {% for dir in exclude_dirs %} --exclude '{{ dir }}' \ {% endfor %} @@ -53,6 +60,10 @@ systemctl start {{ service }} systemctl --user --machine={{ systemd_user }}@.host start {{ service }} {% endfor %} +{% for compose in docker_compose_down %} +docker compose -f {{compose}} up -d +{% endfor %} + info "Pruning repository" # Use the `prune` subcommand to maintain 7 daily, 4 weekly and 6 monthly diff --git a/active/software_borg/backup.timer b/active/software_borg/backup.timer index 396b0ee..c3396ad 100644 --- a/active/software_borg/backup.timer +++ b/active/software_borg/backup.timer @@ -1,11 +1,11 @@ [Unit] -Description=Run Backup backup-{{ repo_name }}.service every day +Description=Run Backup borg-backup.service every day [Timer] OnCalendar=*-*-* 2:00:00 AccuracySec=10min Persistent=true -Unit=backup-{{ repo_name }}.service +Unit=borg-backup.service [Install] WantedBy=timers.target diff --git a/active/software_borg/borg.md b/active/software_borg/borg.md index 5807fc8..efc2fed 100644 --- a/active/software_borg/borg.md +++ b/active/software_borg/borg.md @@ -2,9 +2,7 @@ - [Borg Backup](#borg-backup) - [Install Borg](#install-borg) - - [Set up a laptop or workstation client](#set-up-a-laptop-or-workstation-client) - - [Set up a new server client](#set-up-a-new-server-client) - - [Create a Backup Service](#create-a-backup-service) + - [Set up a new client](#set-up-a-new-client) - [Check backup service logs](#check-backup-service-logs) - [Run a Manual Backup](#run-a-manual-backup) - [Back up and Entire System](#back-up-and-entire-system) @@ -31,11 +29,22 @@ touch /home/backup/.ssh/authorized_keys chown -R backup:backup /home/backup/.ssh ``` -## Set up a laptop or workstation client +## Set up a new client -For backing up your laptop or personal account. +Clients will either use a backup app (Pika) or the `backup.sh.j2` script in this +directory. -1. On your personal account, set up the borg connection +We'll be using ssh authorized keys to control where the repo gets created. This +keeps client configuration simple, since clients will just need to reference +their repo at `.` rather than an absolute path. + +For pika, you can set the backup location to something like `borg-backup:.` +(assuming you have an entry matching `borg-backup` in your `.ssh/config`) + +Backups will be run as the root user. Generate them an SSH key to connect to the borg server. + +1. On the client server, install borg. On Fedora this is `dnf install borgbackup`. +2. On the client server as root (or as the laptop user, for pika), create an SSH key for borg ```bash export BACKUP_HOST="borg.reeselink.com" @@ -49,125 +58,58 @@ For backing up your laptop or personal account. User backup Port 22 EOF - - echo "export CLIENT_FQDN=${USER}.${HOSTNAME}.reeselink.com" - echo "export SSH_PUBKEY=\"$(cat ~/.ssh/id_${BACKUP_HOST}.pub)\"" ``` -2. On the borg backup server as the backup user: +3. On borg.reeselink.com as the `backup` user, allow that SSH key to access the repo ```bash - # Use echo from above - export CLIENT_FQDN= - export SSH_PUBKEY= + # Fill these out + export CLIENT_HOSTNAME="fqdn.reeseapps.com" + export SSH_PUBKEY="ssh-rsa abcd1234 backup@fqdn.something.com" - # Create the authkey entry to restrict the user's access to the borg repo folder - export BORG_COMMAND="cd /home/backup/repos/${CLIENT_FQDN}; borg serve --restrict-to-path /home/backup/repos/${CLIENT_FQDN}" + # Just copy and paste these + export BORG_COMMAND="cd /home/backup/repos/${CLIENT_HOSTNAME}; borg serve --restrict-to-path /home/backup/repos/${CLIENT_HOSTNAME}" export AUTHKEY_ENTRY="command=\"${BORG_COMMAND}\",restrict ${SSH_PUBKEY}" - echo $AUTHKEY_ENTRY >> /home/backup/.ssh/authorized_keys - # Create the directory - mkdir repos/${CLIENT_FQDN} + # Inspect the authkey entry + echo $AUTHKEY_ENTRY + + # add the authkey entry to authorized_keys and create the repo dir + echo $AUTHKEY_ENTRY >> ~/.ssh/authorized_keys + mkdir /home/backup/repos/${CLIENT_HOSTNAME} ``` -3. On your personal account, create the repo and your first backup +4. On the client server, `ssh borg.reeselink.com` to accept the SSH key +5. Create the vars file for your client in `secrets/host_vars.yaml` like the following + + ```yaml + repo_name: my_repo + borg_user: backup + borg_host: borg.reeselink.com + borg_passphrase: "" + backup_dirs: + - /home/foobar + exclude_dirs: [] + keep_daily: 7 + keep_weekly: 4 + keep_monthly: 1 + stop_services: [] + stop_user_services: + - foobar + docker_compose_down: + - /root/release-compose.yaml + ``` + +6. Create the backup task with ansible ```bash - # Do not include the first / in the path - export PATH_TO_BACKUP=home/${USER} - export BACKUP_HOST="borg.reeselink.com" - export BORG_REPO=${BACKUP_HOST}:home - - # If not initialized, do that now - borg init --encryption none $BORG_REPO - borg list - - # Run backup and timestamp it - borg create \ - --verbose \ - --filter AME \ - --list \ - --stats \ - --progress \ - --show-rc \ - --compression lz4 \ - --exclude-caches \ - ${BORG_REPO}::$(date +"%F-%H-%M-%S") \ - /${PATH_TO_BACKUP} - - # Mount a borg archive - borg mount $BORG_REPO::2025-05-14-00-44-05 /mnt/ - - # Restore a borg archive to a location (dry run) - # First, cd to the location you want to extract to - cd ~ - # Then, extract to that location. --strip-components takes the first n items off a path - borg extract --dry-run --list --strip-components 2 $BORG_REPO::my-files home/USERNAME + ansible-playbook \ + -i ansible/inventory.yaml \ + -l deskwork-root \ + active/software_borg/install_backup.yaml \ + -e "@active/software_borg/secrets/ai.deskwork_vars.yaml" ``` -## Set up a new server client - -Backups will be run as the root user. Generate them an SSH key to - -On the server as root: - -```bash -export BACKUP_HOST="borg.reeselink.com" - -ssh-keygen -C root@${HOSTNAME} -f ~/.ssh/id_${BACKUP_HOST} - -cat <> ~/.ssh/config -Host ${BACKUP_HOST} - Hostname ${BACKUP_HOST} - IdentityFile ~/.ssh/id_${BACKUP_HOST} - User backup - Port 22 -EOF -``` - -Now on borg.reeselink.com as root: - -```bash -export CLIENT_FQDN="fqdn.reeseapps.com" -export SSH_PUBKEY="ssh-rsa abcd1234 backup@fqdn.something.com" -export BORG_COMMAND="cd /home/backup/repos/${CLIENT_FQDN}; borg serve --restrict-to-path /home/backup/repos/${CLIENT_FQDN}" -export AUTHKEY_ENTRY="command=\"${BORG_COMMAND}\",restrict ${SSH_PUBKEY}" -echo $AUTHKEY_ENTRY >> /home/backup/.ssh/authorized_keys -mkdir /home/backup/repos/${CLIENT_FQDN} -chown -R backup:backup /home/backup/repos/${CLIENT_FQDN} -``` - -## Create a Backup Service - -Create your vars file in `secrets/host_vars.yaml` - -```yaml -repo_name: my_repo -borg_user: backup -borg_host: borg.reeselink.com -borg_passphrase: "" -backup_dirs: - - /home/foobar -exclude_dirs: [] -keep_daily: 7 -keep_weekly: 4 -keep_monthly: 1 -stop_services: [] -stop_user_services: - - foobar -``` - -```bash -# Update all existing backup services for podman -for var_file in $(ls active/systemd_borg/secrets); do -ansible-playbook \ --i ansible/inventory.yaml \ --l 3dserver \ -active/systemd_borg/install_backup.yaml \ --e "@active/systemd_borg/secrets/$var_file" -done -``` - ## Check backup service logs ```bash diff --git a/active/software_borg/install_backup.yaml b/active/software_borg/install_backup.yaml index 82a3029..57cf3a3 100644 --- a/active/software_borg/install_backup.yaml +++ b/active/software_borg/install_backup.yaml @@ -8,32 +8,32 @@ path: /usr/local/script state: directory mode: '0755' - - name: Copy backup-{{ repo_name }}.service + - name: Copy borg-backup.service template: src: backup.service - dest: /etc/systemd/system/backup-{{ repo_name }}.service + dest: /etc/systemd/system/borg-backup.service owner: root group: root mode: '0644' - - name: Copy backup-{{ repo_name }}.timer + - name: Copy borg-backup.timer template: src: backup.timer - dest: /etc/systemd/system/backup-{{ repo_name }}.timer + dest: /etc/systemd/system/borg-backup.timer owner: root group: root mode: '0644' - - name: Template backup-{{ repo_name }}.sh + - name: Template borg-backup.sh template: src: backup.sh.j2 - dest: /usr/local/script/backup-{{ repo_name }}.sh + dest: /usr/local/script/borg-backup.sh owner: root group: root mode: '0744' - - name: Initialize Repo {{ borg_user }}@{{ borg_host }}:{{ repo_name }} - script: /usr/bin/borg init -e none {{ borg_user }}@{{ borg_host }}:{{ repo_name }} + - name: Initialize Repo {{ borg_user }}@{{ borg_host }}:. + script: /usr/bin/borg init -e none {{ borg_user }}@{{ borg_host }}:. ignore_errors: yes - - name: Reload backup timer backup-{{ repo_name }}.timer + - name: Reload backup timer borg-backup.timer ansible.builtin.systemd_service: - name: backup-{{ repo_name }}.timer + name: borg-backup.timer enabled: true daemon_reload: true