From 8dd8c00e37c8f118724763e5ab6d10a8d4e64a6b Mon Sep 17 00:00:00 2001 From: Fabio Sinibaldi Date: Fri, 4 Sep 2026 18:02:29 +0200 Subject: [PATCH 1/2] Setup borg backup server --- ansible/inventories/distributed.yaml | 5 +- ansible/inventories/group_vars/all/borg.yaml | 4 ++ .../group_vars/borg/auth_users.yaml | 3 ++ ansible/playbooks/borg_server.yaml | 28 +++++++++++ .../playbooks/roles/borg/defaults/main.yaml | 10 ++++ .../borg/tasks/configure_borg_client.yaml | 0 .../borg/tasks/configure_borg_server.yaml | 46 +++++++++++++++++++ ansible/playbooks/roles/borg/tasks/main.yaml | 8 ++++ .../roles/borg/tasks/prepare_borg.yaml | 6 +++ 9 files changed, 109 insertions(+), 1 deletion(-) create mode 100644 ansible/inventories/group_vars/all/borg.yaml create mode 100644 ansible/inventories/group_vars/borg/auth_users.yaml create mode 100644 ansible/playbooks/borg_server.yaml create mode 100644 ansible/playbooks/roles/borg/defaults/main.yaml create mode 100644 ansible/playbooks/roles/borg/tasks/configure_borg_client.yaml create mode 100644 ansible/playbooks/roles/borg/tasks/configure_borg_server.yaml create mode 100644 ansible/playbooks/roles/borg/tasks/main.yaml create mode 100644 ansible/playbooks/roles/borg/tasks/prepare_borg.yaml diff --git a/ansible/inventories/distributed.yaml b/ansible/inventories/distributed.yaml index d251e2b..8e5af4b 100644 --- a/ansible/inventories/distributed.yaml +++ b/ansible/inventories/distributed.yaml @@ -4,7 +4,7 @@ new_sudo: hserve1: hserve2: mini1: - + backs.hassallab.it: distributed: @@ -28,4 +28,7 @@ distributed: forgejo: hosts: hserve1: + borg: + hosts: + backs.hassallab.it: diff --git a/ansible/inventories/group_vars/all/borg.yaml b/ansible/inventories/group_vars/all/borg.yaml new file mode 100644 index 0000000..94b8f8f --- /dev/null +++ b/ansible/inventories/group_vars/all/borg.yaml @@ -0,0 +1,4 @@ +--- +borg_user: borg +borg_backup_server: backs.hassallab.it +borg_repo_base_path: "ssh://{{ borg_user }}@{{ borg_backup_server }}/./" \ No newline at end of file diff --git a/ansible/inventories/group_vars/borg/auth_users.yaml b/ansible/inventories/group_vars/borg/auth_users.yaml new file mode 100644 index 0000000..1e1e04a --- /dev/null +++ b/ansible/inventories/group_vars/borg/auth_users.yaml @@ -0,0 +1,3 @@ +# auth_users: +# - host: johndoe.clnt.local +# key: "{{ lookup('file', '/path/to/keys/johndoe.clnt.local.pub') }}" diff --git a/ansible/playbooks/borg_server.yaml b/ansible/playbooks/borg_server.yaml new file mode 100644 index 0000000..ffdd33b --- /dev/null +++ b/ansible/playbooks/borg_server.yaml @@ -0,0 +1,28 @@ +--- +- hosts: backup01.srv.local + vars: + user: backup + group: backup + home: /home/backup + pool: "{{ home }}/repos" + auth_users: + - host: johndoe.clnt.local + key: "{{ lookup('file', '/path/to/keys/johndoe.clnt.local.pub') }}" + - host: web01.clnt.local + key: "{{ lookup('file', '/path/to/keys/web01.clnt.local.pub') }}" + - host: app01.clnt.local + key: "{{ lookup('file', '/path/to/keys/app01.clnt.local.pub') }}" + tasks: + - package: name=borg state=present + - group: name="{{ group }}" state=present + - user: name="{{ user }}" shell=/bin/bash home="{{ home }}" createhome=yes group="{{ group }}" groups= state=present + - file: path="{{ home }}" owner="{{ user }}" group="{{ group }}" mode=0700 state=directory + - file: path="{{ home }}/.ssh" owner="{{ user }}" group="{{ group }}" mode=0700 state=directory + - file: path="{{ pool }}" owner="{{ user }}" group="{{ group }}" mode=0700 state=directory + - authorized_key: user="{{ user }}" + key="{{ item.key }}" + key_options='command="cd {{ pool }}/{{ item.host }};borg serve --restrict-to-path {{ pool }}/{{ item.host }}",restrict' + with_items: "{{ auth_users }}" + - file: path="{{ home }}/.ssh/authorized_keys" owner="{{ user }}" group="{{ group }}" mode=0600 state=file + - file: path="{{ pool }}/{{ item.host }}" owner="{{ user }}" group="{{ group }}" mode=0700 state=directory + with_items: "{{ auth_users }}" diff --git a/ansible/playbooks/roles/borg/defaults/main.yaml b/ansible/playbooks/roles/borg/defaults/main.yaml new file mode 100644 index 0000000..6e160ce --- /dev/null +++ b/ansible/playbooks/roles/borg/defaults/main.yaml @@ -0,0 +1,10 @@ +--- +borg_user: borg +borg_group: borg +borg_home: /home/borg +borg_pool: "{{ borg_home }}/repos" +borg_pool_dest : /usr/backups/borg_repos +auth_users: + - host: hserve1 + # Chiave di esempio per test + key: "ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEArNhKFcJ6T08sn7kTTLf+rO9HEvgOvqfhv5HQ2sRf2tFYfjfCb0zHKnMkgW+sy5gMU10Lyx1r7juXCvqRC955uIM97m1B1Xc6sVqASVKuGPhCKfhxEaMAyBcWFdE+HYbCOPYVN+JMrcwWfbblwiZTtK1OCqaEUvDDI7cFeU68noXwggEp46T48eqMUdi541D9Y+BVx9HYAo6OCQz0+6eXwxJL+tpRcAAXIMMWv362CYHoOgIU45R7xVSMLY1k/HLrcEAblwxEaSpduCH5cWUXZE/56IyxpvP44BxZkVhNdqJLmg4hxBQWhoMNYiTZxbLay3W2TwBCM111cAtUx4M/jQ==" \ No newline at end of file diff --git a/ansible/playbooks/roles/borg/tasks/configure_borg_client.yaml b/ansible/playbooks/roles/borg/tasks/configure_borg_client.yaml new file mode 100644 index 0000000..e69de29 diff --git a/ansible/playbooks/roles/borg/tasks/configure_borg_server.yaml b/ansible/playbooks/roles/borg/tasks/configure_borg_server.yaml new file mode 100644 index 0000000..06ee884 --- /dev/null +++ b/ansible/playbooks/roles/borg/tasks/configure_borg_server.yaml @@ -0,0 +1,46 @@ +--- +- name: Set borg user group + group: + name: "{{ borg_group }}" + state: present + +- name: Set borg user + user: + name: "{{ borg_user }}" + shell: /bin/bash + home: "{{ borg_home }}" + createhome: yes + group: "{{ borg_group }}" + state: present + +- name: Set home directory + file: + path: "{{ borg_home }}" + owner: "{{ borg_user }}" + group: "{{ borg_group }}" + mode: "0700" + state: directory + +- name: Set ssh directory + file: + path: "{{ borg_home }}/.ssh" + owner: "{{ borg_user }}" + group: "{{ borg_group }}" + mode: "0700" + state: directory + +- name: Set pool directory link + file: + src: "{{ borg_pool }}" + dest: "{{ borg_pool_dest }}" + state: link + + +- name: Add authorized keys + authorized_key: + user: "{{ borg_user }}" + key: "{{ item.key }}" + key_options: "command=cd {{ borg_pool }}/{{ item.host }};borg serve --restrict-to-path {{ borg_pool }}/{{ item.host }},restrict" + with_items: "{{ borg_auth_users }}" + + diff --git a/ansible/playbooks/roles/borg/tasks/main.yaml b/ansible/playbooks/roles/borg/tasks/main.yaml new file mode 100644 index 0000000..e493ba7 --- /dev/null +++ b/ansible/playbooks/roles/borg/tasks/main.yaml @@ -0,0 +1,8 @@ +--- +include_tasks: prepare_borg.yaml +include_tasks: configure_borg_server.yaml + when: + - configure_borg_server +include_tasks: configure_borg_client.yaml + when: + - configure_borg_client \ No newline at end of file diff --git a/ansible/playbooks/roles/borg/tasks/prepare_borg.yaml b/ansible/playbooks/roles/borg/tasks/prepare_borg.yaml new file mode 100644 index 0000000..89a8adb --- /dev/null +++ b/ansible/playbooks/roles/borg/tasks/prepare_borg.yaml @@ -0,0 +1,6 @@ +--- +- name: Install borg and requirements +- package: + name: borg + state: present + From 9c60baf297c31efcacc178f506874e5fe8b7a3dd Mon Sep 17 00:00:00 2001 From: Fabio Sinibaldi Date: Wed, 9 Sep 2026 17:15:18 +0200 Subject: [PATCH 2/2] Configure both clients and servers --- .../roles/borg/templates/backup_script.sh.j2 | 86 +++++++++++++++++++ .../borg/templates/borg_backup.service.j2 | 13 +++ 2 files changed, 99 insertions(+) create mode 100644 ansible/playbooks/roles/borg/templates/backup_script.sh.j2 create mode 100644 ansible/playbooks/roles/borg/templates/borg_backup.service.j2 diff --git a/ansible/playbooks/roles/borg/templates/backup_script.sh.j2 b/ansible/playbooks/roles/borg/templates/backup_script.sh.j2 new file mode 100644 index 0000000..12a36b0 --- /dev/null +++ b/ansible/playbooks/roles/borg/templates/backup_script.sh.j2 @@ -0,0 +1,86 @@ +#!/bin/bash +{% for repo_item in borg_repos %} + +# Setting this, so the repo does not need to be given on the commandline: +export BORG_REPO="{{borg_repo_base}}{{repo_item.name}}" + +# See the section "Passphrase notes" for more infos. +export BORG_PASSPHRASE="'{{ repo_item.borg_passphrase }}'" + +# some helpers and error handling: +info() { logger "$*"; } +trap 'echo $( date ) Backup interrupted >&2; exit 2' INT TERM + +info "Trying to initialize repo. NB returns error if already initialized" +borg init --encryption=repokey + +info "Starting backup for repo {{repo_item.name}}" + +# Backup the most important directories into an archive named after +# the machine this script is currently running on: + +borg create \ + --verbose \ + --filter AME \ + --list \ + --stats \ + --show-rc \ + --compression lz4 \ + --exclude-caches \ + --exclude 'home/*/.cache/*' \ + --exclude 'var/tmp/*' \ + \ + ::"'{{ inventory_hostname }}-{now}'"\ + {% for item in repo_item.paths_to_backup %} + {{ item }}\ + {% endfor %} + +backup_exit=$? + +info "Pruning repository {{ repo_item.name }}" + +# Use the `prune` subcommand to maintain 7 daily, 4 weekly and 6 monthly +# archives of THIS machine. The '{hostname}-*' matching is very important to +# limit prune's operation to this machine's archives and not apply to +# other machines' archives also: + +borg prune \ + --list \ + --glob-archives "'{{ inventory_hostname }}-*'" \ + --show-rc \ + --keep-daily 7 \ + --keep-weekly 4 \ + --keep-monthly 6 + +prune_exit=$? + +# actually free repo disk space by compacting segments + +info "Compacting repository {{ repo_item.name }}" + +borg compact + +compact_exit=$? + +# use highest exit code as global exit code +global_exit=$(( backup_exit > prune_exit ? backup_exit : prune_exit )) +global_exit=$(( compact_exit > global_exit ? compact_exit : global_exit )) + +if [ ${global_exit} -eq 0 ]; then + info "Backup, Prune, and Compact finished successfully" +elif [ ${global_exit} -eq 1 ]; then + info "Backup, Prune, and/or Compact finished with warnings" +else + info "Backup, Prune, and/or Compact finished with errors" +fi + + +# end loop for repos + +{% endfor %} + + +exit ${global_exit} + + + diff --git a/ansible/playbooks/roles/borg/templates/borg_backup.service.j2 b/ansible/playbooks/roles/borg/templates/borg_backup.service.j2 new file mode 100644 index 0000000..578173b --- /dev/null +++ b/ansible/playbooks/roles/borg/templates/borg_backup.service.j2 @@ -0,0 +1,13 @@ +[Unit] +Description=Borg Backup + +[Service] +Type=oneshot +User={{ borg_user }} +ExecStart=/home/{{borg_user}}/backup_script.sh + +AmbientCapabilities=CAP_DAC_READ_SEARCH + +StandardOutput=journal +StandardError=journal +SyslogIdentifier=borg \ No newline at end of file