diff --git a/README.md b/README.md index 5033482..ec9f9d1 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Borg backup role This role installs Borg backup on borgbackup\_servers and clients. The role contains a wrapper-script 'borg-backup' to ease the usage on the client. Supported options include borg-backup info | init | list | backup | mount. Automysqlbackup will run as pre-backup command if it's installed. -The role supports both self hosted and rsync.net as Borg server. +The role supports both self hosted and offsite backup-storage such as rsync.net and hetzner storage box as Borg server. It's possible to configure append-only repositories to secure the backups against deletion from the client. @@ -29,6 +29,13 @@ borgbackup_servers: home: "" pool: repos options: "--remote-path=borg1" + - fqdn: username.your-storagebox.de + user: username + type: hetzner + home: "" + pool: repos + options: "" + borgbackup_retention: hourly: 12 diff --git a/defaults/main.yml b/defaults/main.yml index 59f3745..d4312d4 100644 --- a/defaults/main.yml +++ b/defaults/main.yml @@ -10,6 +10,8 @@ borgbackup_download_url: "https://github.com/borgbackup/borg/releases/download/{ borgbackup_pre_commands: - '[[ ! -f "/usr/sbin/automysqlbackup" ]] || /usr/sbin/automysqlbackup' +borgbackup_post_commands: [] + borgbackup_include: - "/etc" - "/home" @@ -17,6 +19,8 @@ borgbackup_include: - "/var/www" - "/var/log" +borgbackup_exclude: [] + borgbackup_retention: hourly: 12 daily: 7 @@ -33,3 +37,7 @@ borgbackup_appendonly: False borgbackup_management_station: '' borgbackup_management_user: '' borgbackup_management_ssh_pubkey: '' + +borgbackup_owner: root +borgbackup_group: root +borgbackup_shell: "/bin/bash" diff --git a/tasks/borg-client.yml b/tasks/borg-client.yml index 919a026..fce6b6a 100644 --- a/tasks/borg-client.yml +++ b/tasks/borg-client.yml @@ -37,38 +37,38 @@ when: item.type == 'normal' with_items: "{{ borgbackup_servers }}" -# rsync.net has no python, so we can only use raw to manage ssh keys - workaround with local tmp file -- name: client | get rsync.net authorized_keys file - raw: scp {{ item.user }}@{{ item.fqdn }}:.ssh/authorized_keys /tmp/rsync.net-{{ item.fqdn }}-authkeys +# rsync.net and hetzner have no python, so we can only use raw to manage ssh keys - workaround with local tmp file +- name: client | get authorized_keys file + raw: scp {{ item.user }}@{{ item.fqdn }}:.ssh/authorized_keys /tmp/authkeys-{{ item.type }}-{{ item.fqdn }}-authkeys delegate_to: localhost become: no - when: item.type == 'rsync.net' + when: item.type in ['rsync.net','hetzner'] with_items: "{{ borgbackup_servers }}" changed_when: false -- name: client | modify local rsync.net authorized_keys +- name: client | modify local rsync.net/hetzner authorized_keys authorized_key: user: "{{ ansible_user_id }}" key: "{{ sshkey.stdout }}" key_options: 'command="cd {{ item.pool }}/{{ inventory_hostname }};/usr/local/bin/borg1 serve {% if borgbackup_appendonly %}--append-only {% endif %} --restrict-to-path {{ item.pool }}/{{ inventory_hostname }}",no-port-forwarding,no-X11-forwarding,no-pty,no-agent-forwarding,no-user-rc' - path: "/tmp/rsync.net-{{ item.fqdn }}-authkeys" + path: "/tmp/authkeys-{{ item.type }}-{{ item.fqdn }}-authkeys" manage_dir: no delegate_to: localhost become: no - when: item.type == 'rsync.net' + when: item.type in ['rsync.net','hetzner'] with_items: "{{ borgbackup_servers }}" register: authkeys -- name: client | upload local authorized_keys to rsync.net - raw: scp /tmp/rsync.net-{{ item.fqdn }}-authkeys {{ item.user }}@{{ item.fqdn }}:.ssh/authorized_keys +- name: client | upload local authorized_keys to rsync.net / hetzner + raw: scp /tmp/authkeys-{{ item.type }}-{{ item.fqdn }}-authkeys {{ item.user }}@{{ item.fqdn }}:.ssh/authorized_keys delegate_to: localhost become: no - when: item.type == 'rsync.net' and authkeys.changed + when: item.type in ['rsync.net','hetzner'] and authkeys.changed with_items: "{{ borgbackup_servers }}" - name: client | remove tmp authorized_keys files file: - path: /tmp/rsync.net-{{ item.fqdn }}-authkeys + path: /tmp/authkeys-{{ item.type }}-{{ item.fqdn }}-authkeys state: absent delegate_to: localhost become: no @@ -84,8 +84,8 @@ template: src: "borg-backup.sh.j2" dest: "/usr/local/bin/borg-backup" - owner: "root" - group: "root" + owner: "{{ borgbackup_owner }}" + group: "{{ borgbackup_group }}" mode: "0744" - name: client | create backup-directory on backup server diff --git a/tasks/install.yml b/tasks/install.yml index 87ff287..1a59145 100644 --- a/tasks/install.yml +++ b/tasks/install.yml @@ -3,8 +3,8 @@ get_url: dest: "/usr/local/bin/borg" checksum: "{{ borgbackup_checksum }}" - owner: "root" - group: "root" + owner: "{{ borgbackup_owner }}" + group: "{{ borgbackup_group }}" mode: "0755" url: "{{ borgbackup_download_url }}" tags: borginstall diff --git a/templates/borg-backup.sh.j2 b/templates/borg-backup.sh.j2 index 0e7bd60..3f89d6d 100644 --- a/templates/borg-backup.sh.j2 +++ b/templates/borg-backup.sh.j2 @@ -1,4 +1,4 @@ -#!/bin/bash +#!{{ borgbackup_shell }} if [ -z "$1" ] || [ ! -z "$2" ] then @@ -15,7 +15,7 @@ if [ "$1" = "info" ] then if [ -z "$2" ]; then printf "run $0 with list and use the backup-tag to request information\n"; exit 1; fi {% for b in borgbackup_servers %} - REPOSITORY={{ b.user }}@{{ b.fqdn }}:{{ b.home }}{{ b.pool }}/{{ inventory_hostname }} + REPOSITORY={% if b.type == 'hetzner' %}ssh://{% endif %}{{ b.user }}@{{ b.fqdn }}:{% if b.type == 'hetzner' %}23/./{% endif %}{{ b.home }}{{ b.pool }}/{{ inventory_hostname }} /usr/local/bin/borg info $REPOSITORY::$2 {{ b.options }} {% endfor %} exit 0 @@ -27,7 +27,7 @@ if [ "$1" = "mount" ] if [ -z "$3" ]; then printf "Select the backup to mount\n"; exit 1; fi if [ -z "$4" ]; then printf "Select the path to mount the backup on\n"; exit 1; fi {% for b in borgbackup_servers %} - REPOSITORY={{ b.user }}@{{ b.fqdn }}:{{ b.home }}{{ b.pool }}/{{ inventory_hostname }} + REPOSITORY={% if b.type == 'hetzner' %}ssh://{% endif %}{{ b.user }}@{{ b.fqdn }}:{% if b.type == 'hetzner' %}23/./{% endif %}{{ b.home }}{{ b.pool }}/{{ inventory_hostname }} /usr/local/bin/borg mount $REPOSITORY::$3 $4 {{ b.options }} if [ "$?" = "0" ]; then printf "Backup mounted on $4, do not forget to unmount!\n"; fi exit 0 @@ -37,7 +37,7 @@ fi if [ "$1" = "list" ] then {% for b in borgbackup_servers %} - REPOSITORY={{ b.user }}@{{ b.fqdn }}:{{ b.home }}{{ b.pool }}/{{ inventory_hostname }} + REPOSITORY={% if b.type == 'hetzner' %}ssh://{% endif %}{{ b.user }}@{{ b.fqdn }}:{% if b.type == 'hetzner' %}23/./{% endif %}{{ b.home }}{{ b.pool }}/{{ inventory_hostname }} printf "Archives on {{ b.fqdn }} :\n" /usr/local/bin/borg list -v $REPOSITORY {{ b.options }} {% endfor %} @@ -47,8 +47,8 @@ fi if [ "$1" = "init" ] then {% for b in borgbackup_servers %} - REPOSITORY={{ b.user }}@{{ b.fqdn }}:{{ b.home }}{{ b.pool }}/{{ inventory_hostname }} - borg init $REPOSITORY {{ b.options }} + REPOSITORY={% if b.type == 'hetzner' %}ssh://{% endif %}{{ b.user }}@{{ b.fqdn }}:{% if b.type == 'hetzner' %}23/./{% endif %}{{ b.home }}{{ b.pool }}/{{ inventory_hostname }} + /usr/local/bin/borg init $REPOSITORY {{ b.options }} {% endfor %} exit 0 fi @@ -64,16 +64,22 @@ if [ "$1" = "backup" ] {% for b in borgbackup_servers %} printf "Backing up to {{ b.fqdn }} :\n" - REPOSITORY={{ b.user }}@{{ b.fqdn }}:{{ b.home }}{{ b.pool }}/{{ inventory_hostname }} + REPOSITORY={% if b.type == 'hetzner' %}ssh://{% endif %}{{ b.user }}@{{ b.fqdn }}:{% if b.type == 'hetzner' %}23/./{% endif %}{{ b.home }}{{ b.pool }}/{{ inventory_hostname }} - /usr/local/bin/borg create --compression zlib,6 --stats $REPOSITORY::$date {{ b.options }} {% for dir in borgbackup_include %}{{ dir }} {% endfor %}{% if automysql.stat.isdir is defined and automysql.stat.isdir == True %}/var/lib/automysqlbackup{% endif %} + /usr/local/bin/borg create -p --compression zlib,6 --stats $REPOSITORY::$date {{ b.options }} {% for dir in borgbackup_include %}{{ dir }} {% endfor %}{% if automysql.stat.isdir is defined and automysql.stat.isdir == True %}/var/lib/automysqlbackup{% endif %} {% for dir in borgbackup_exclude %} --exclude '{{ dir }}'{% endfor %} - if [ "$?" -eq "0" ]; then printf "Backup succeeded on $date\n" >> /var/log/borg-backup.log; fi + if [ "$?" -eq "0" ]; then printf "Backup succeeded on $date to {{ b.fqdn }}\n" >> /var/log/borg-backup.log; fi {% if not borgbackup_appendonly %} # prune old backups /usr/local/bin/borg prune -v $REPOSITORY {{ b.options }} -H {{ borgbackup_retention.hourly }} -d {{ borgbackup_retention.daily }} -w {{ borgbackup_retention.weekly }} -m {{ borgbackup_retention.monthly }} -y {{ borgbackup_retention.yearly }} {% endif %} {% endfor %} + + # Running some commands post-backup +{% for postcommand in borgbackup_post_commands %} + {{ postcommand }} +{% endfor %} + fi