Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add nextcloud backup role #268

Merged
merged 45 commits into from
May 19, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
835f730
Initial commit
aalaesar Apr 14, 2022
0546874
first version of server files backup
aalaesar Apr 26, 2022
da1f2a7
exit maintenance node task
aalaesar Apr 29, 2022
22cf0ac
move task to another file
aalaesar Apr 29, 2022
2707dfd
add app_data & user data backup
aalaesar Apr 29, 2022
eff3887
add db dump automation
aalaesar Apr 30, 2022
e1dc5ad
finishing backup
aalaesar May 3, 2022
268f967
use camel_case
aalaesar May 3, 2022
6c749f8
ansible-lint fixes
aalaesar May 3, 2022
a6aff33
adjusting for documentation
aalaesar May 5, 2022
4e635cb
fix ansible_lint issue
aalaesar May 11, 2022
148f3da
add examples in readme
aalaesar May 11, 2022
b0b8c90
adjusting metadata for ansible galaxy
aalaesar May 11, 2022
3fe51c4
fix missing jinja bracets
aalaesar Aug 8, 2022
606bf98
fix spaces outside of jinja brackets
aalaesar Aug 15, 2022
b1cc779
add archive format
aalaesar Dec 2, 2022
ab50548
yamllint fixes
wiktor2200 Jan 26, 2023
830742f
Add github actions - yamllint, ansible-lint and pre-commit
wiktor2200 Jan 26, 2023
2d3ebe5
Merge pull request #7 from wiktor2200/improve-fmt-and-yamllint
aalaesar Jan 30, 2023
195466c
completed metadatas and fix ansible-lint errors
aalaesar Jan 30, 2023
acfa421
fix tasks name casing
aalaesar Jan 30, 2023
90d3e19
fix key ordering
aalaesar Jan 30, 2023
116c77f
Merge pull request #8 from aalaesar/fix_ansible_lint
aalaesar Jan 30, 2023
815fed1
change become parameters to variables
wiktor2200 Jan 28, 2023
eda3865
use ad-hoc var to adjust user for occ commands
aalaesar Jan 30, 2023
cd95984
Fix chmod mode bug with directories
wiktor2200 Jan 31, 2023
cd19243
fmt
wiktor2200 Jan 31, 2023
fbcef93
Introduce backup featch feature
wiktor2200 Jan 31, 2023
9a12f1d
Merge pull request #5 from wiktor2200/fix-chmod-mode-bug
aalaesar Jan 31, 2023
f75e98c
Merge branch 'master' of github.com:aalaesar/backup_nextcloud into in…
wiktor2200 Feb 1, 2023
f1f75b8
Add missing import_tasks entry
wiktor2200 Feb 1, 2023
70bd32c
fix jinja not passing the test result to filter
aalaesar Feb 2, 2023
d60930b
change dpkg command.
aalaesar Feb 2, 2023
787a2d5
Merge pull request #9 from aalaesar/victor2200/fix-become_method-para…
aalaesar Feb 2, 2023
9f3e229
Merge branch 'master' into introduce-backup-fetch-feature
wiktor2200 Feb 2, 2023
a9ab7f0
remove duplicated condition
wiktor2200 Feb 2, 2023
07b13a2
Merge pull request #6 from wiktor2200/introduce-backup-fetch-feature
aalaesar Feb 2, 2023
f1ce67d
Add switch for dowloading Nextcloud-server archive
wiktor2200 Feb 10, 2023
ec201dc
change default value for archive download
wiktor2200 Feb 14, 2023
922a569
Merge pull request #10 from wiktor2200/add-switch-for-nextcloud-serve…
aalaesar Feb 14, 2023
7a71495
Add 'roles/backup_nextcloud/' from commit '922a569d339f05716a69cb27b3…
wiktor2200 Apr 29, 2023
d424c70
role cleanup
wiktor2200 Apr 29, 2023
041c3cb
add missing requirement
wiktor2200 Apr 29, 2023
89935bd
more cleanup
wiktor2200 Apr 29, 2023
c04643c
Port changes from #260
staticdev May 6, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,11 @@ Name | Description
nextcloud.admin.run_occ|Run the occ command line tool with given arguments

### Roles

Name | Description
--- | ---
nextcloud.admin.install_nextcloud|Install and configure an Nextcloud instance for a Debian/Ubuntu server - formerly `aalaesar.install_nextcloud`
nextcloud.admin.backup (**beta**)|Create a backup of a Nextcloud server - formerly `aalaesar.backup_nextcloud`
nextcloud.admin.install_nextcloud | Install and configure an Nextcloud instance for a Debian/Ubuntu server - formerly `aalaesar.install_nextcloud`

<!--end collection content-->

Expand Down
2 changes: 2 additions & 0 deletions requirements.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
collections:
- name: ansible.utils
version: 2.9.0
- name: community.general
version: 6.5.0
roles:
- name: geerlingguy.php-versions
version: 5.0.1
150 changes: 150 additions & 0 deletions roles/backup/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
# Ansible role: backup

An ansible role that creates a backup of a Nextcloud server. The backup is kept on the server (unless you [fetch it](#fetching-backup-from-remote-to-local-machine)).

## Requirements

The roles requires the following tools to be available on the host:
- tar
- gzip
- rsync
- a mysql or postgreSQL client if the database has to be dumped.

You'll need enough space on the target file system, depending on the size of your nextcloud server.

## Role Variables

### Locating the nextcloud server

The role has to know where the server files are, how to access it and where to store the backup.

```yaml
nextcloud_backup_target_dir: "/opt/nextcloud_backups"
nextcloud_webroot: "/opt/nextcloud"
# nextcloud_data_dir: "/var/ncdata" # optional.
nextcloud_websrv_user: "www-data" # you may need to change this to the nextcloud file owner depending of your setup and OS
```

### Adjusting the backup owner
The backup owner can be adjusted with. This may be useful when operating user is different than nextcloud's process owner.

```yaml
nextcloud_backup_owner: "www-data" # user name who will get owner on backup_target_dir and final archive
nextcloud_backup_group: "www-data" # user group who will get owner on backup_target_dir and final archive
```

### Adjusting the backup name
The backup name can be adjusted with

```yaml
nextcloud_instance_name: "nextcloud" # a human identifier for the server
nextcloud_backup_suffix: "" # some arbitrary information at the end of the archive name
nextcloud_backup_format: "tgz" # extension of the archive. use a supported format used by the archive module (Choices: bz2, gz, tar, xz, zip)
```

Or you can change it completely by redefining

```yaml
nc_archive_name: "{{ nextcloud_instance_name }}_nextcloud-{{ nc_status.versionstring }}_{{ ansible_date_time.iso8601_basic_short }}{{ nextcloud_backup_suffix }}"
```

### Adjusting the backup content

The role will __always__:
- backup the server's config
- create a list of installed & enabled applications(along with the version numbers)

You can adjust the scope of the backup by enabling/disabling some flags defined in default:

```yaml
nextcloud_backup_download_server_archive: true
nextcloud_backup_app_data: true
nextcloud_backup_user: true
nextcloud_backup_database: true
```

### Adjusting nextcloud-server archive included in backup
Role can download the proper server archive from the nextcloud download site and add it to backup archive.
It can be turned on using: `nextcloud_backup_download_server_archive` variable.

### Adjusting app data backup

You may want to exclude some app_data folders from the backup.
But you cannot target a specific app to backup, this requires knowledge of the app's code.

```yaml
nextcloud_backup_app_data_exclude_folder:
- preview
```

By default the preview folder is excluded from the backup as it can be notoriously __large__

### Adjusting user backup

You can exclude a list of user(s) from the backup

```yaml
nextcloud_backup_exclude_users: []
```

You can also decide to include or not some side-folders.

```yaml
nextcloud_backup_user_files_trashbin: true
nextcloud_backup_user_files_versions: true
nextcloud_backup_user_uploads: true
nextcloud_backup_user_cache: true
```

### Fetching backup from remote to local machine

You can fetch created backup from remote by setting these variables.
WARNING: user which you are used in Ansible has to be set as [backup owner](#adjusting-the-backup-owner) due to Ansible limitation on using `become` with `ansible.builtin.fetch`

```yaml
nextcloud_backup_fetch_to_local: true
nextcloud_backup_fetch_local_path: "/local_path/nextcloud_backup"
```

### Other

You can leave the server in maintenance mode at the end of the process by turning false

```yaml
nextcloud_exit_maintenance_mode: true
```

## The Dependencies

None

## Example Playbook

### Running a full backup of your nextcloud server

```yaml
- hosts: nextcloud
roles:
- role: nextcloud.admin.backup
```

### Making a partial backup with only the app_data

```yaml
- hosts: nextcloud
roles:
- role: nextcloud.admin.backup
vars:
nextcloud_backup_suffix: _only_app_data
nextcloud_backup_user: false
nextcloud_backup_database: false
```

## Contributing

We encourage you to contribute to this role! Please check out the
[contributing guide](../CONTRIBUTING.md) for guidelines about how to proceed.

## License

BSD
40 changes: 40 additions & 0 deletions roles/backup/defaults/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
---
### APPLICATION SETTINGS ##
nextcloud_instance_name: "nextcloud"
nextcloud_backup_target_dir: "/opt/nextcloud_backups"
nextcloud_webroot: "/opt/nextcloud"
# nextcloud_data_dir: "/var/ncdata"
nextcloud_websrv_user: www-data

nextcloud_exit_maintenance_mode: true

### ARCHIVE PROPERTIES ###
nextcloud_backup_suffix: ""
nextcloud_backup_owner: "{{ nextcloud_websrv_user }}"
nextcloud_backup_group: "{{ nextcloud_websrv_user }}"
nextcloud_backup_file_mode: "0640"
nextcloud_backup_dir_mode: "0750"
nextcloud_backup_format: "tgz"

### NEXTCLOUD SERVER ARCHIVE DOWNLOAD ###
nextcloud_backup_download_server_archive: false

### APPS BACKUPS ###
nextcloud_backup_app_data: true
nextcloud_backup_app_data_exclude_folder:
- preview

### USER BACKUPS ###
nextcloud_backup_user: true
nextcloud_backup_exclude_users: []
nextcloud_backup_user_files_trashbin: true
nextcloud_backup_user_files_versions: true
nextcloud_backup_user_uploads: true
nextcloud_backup_user_cache: true

### DATABASE BACKUP ###
nextcloud_backup_database: true

### FETCH TO LOCAL MACHINE ###
nextcloud_backup_fetch_to_local: false
nextcloud_backup_fetch_local_path: "/tmp/nextcloud_backup"
29 changes: 29 additions & 0 deletions roles/backup/meta/main.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
---
galaxy_info:
author: aalaesar
role_name: backup
description: Create a backup of your nextcloud server with this ansible role

license: BSD

min_ansible_version: "2.10"

platforms:
- name: EL
versions:
- all
- name: Debian
versions:
- all
- name: Ubuntu
versions:
- all

galaxy_tags:
- backup
- nextcloud
- storage
- selfhosted
- privacy

dependencies: []
18 changes: 18 additions & 0 deletions roles/backup/tasks/app_data.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
---
- name: The app_data backup folder exists
ansible.builtin.file:
path: "{{ nc_archive_path }}/data"
state: directory
owner: "{{ nextcloud_backup_owner }}"
group: "{{ nextcloud_backup_group }}"
mode: "{{ nextcloud_backup_dir_mode }}"

- name: Backup applications data
ansible.builtin.command: >-
rsync -r {{ _exclude_folders }}
{{ nextcloud_data_dir }}/appdata_{{ nc_id }}
{{ nc_archive_path }}/data
vars:
_exclude_folders: "{% for _folder in nextcloud_backup_app_data_exclude_folder %}--exclude={{ _folder }} {% endfor %}"
tags:
- skip_ansible_lint
37 changes: 37 additions & 0 deletions roles/backup/tasks/database.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
---
- name: The app_data backup folder exists
ansible.builtin.file:
path: "{{ nc_archive_path }}"
state: directory
owner: "{{ nextcloud_backup_owner }}"
group: "{{ nextcloud_backup_group }}"
mode: "{{ nextcloud_backup_dir_mode }}"

- name: Create a dump of the mysql database
ansible.builtin.shell: >-
mysqldump --single-transaction --default-character-set=utf8mb4
-h {{ _nc_dbhost.stdout }} -u {{ _nc_dbuser.stdout }} -p{{ _nc_dbpassword.stdout }}
{{ _nc_dbname.stdout }} > database_dump.bak.sql
args:
chdir: "{{ nc_archive_path }}"
no_log: true
when:
- _nc_dbtype.stdout == 'mysql'
register: output
changed_when: output.rc != 0

- name: Create a dump of the postgreSQL database
ansible.builtin.command: >-
pg_dump {{ _nc_dbname.stdout }}
-h {{ _nc_dbhost.stdout }}
-U {{ _nc_dbuser.stdout }}
-f database_dump.bak.sql
args:
chdir: "{{ nc_archive_path }}"
no_log: true
environment:
PGPASSWORD: "{{ _nc_dbpassword.stdout }}"
when:
- _nc_dbtype.stdout == 'pgsql'
register: output
changed_when: output.rc != 0
6 changes: 6 additions & 0 deletions roles/backup/tasks/fetching.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
- name: Fetch file from remote to local
become: false # Using become may cause OOM errors. (https://docs.ansible.com/ansible/latest/collections/ansible/builtin/fetch_module.html#notes)
ansible.builtin.fetch:
src: "{{ nc_archive_path }}.{{ nextcloud_backup_format }}"
dest: "{{ nextcloud_backup_fetch_local_path }}"
41 changes: 41 additions & 0 deletions roles/backup/tasks/files.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
---
- name: Backup target dir exists on the host
ansible.builtin.file:
path: "{{ nextcloud_backup_target_dir }}"
state: directory
owner: "{{ nextcloud_backup_owner }}"
group: "{{ nextcloud_backup_group }}"
mode: "{{ nextcloud_backup_dir_mode }}"

- name: Backup folder exists on the host
ansible.builtin.file:
path: "{{ nc_archive_path }}"
state: directory
owner: "{{ nextcloud_backup_owner }}"
group: "{{ nextcloud_backup_group }}"
mode: "{{ nextcloud_backup_dir_mode }}"

- name: Copy config in archive
ansible.builtin.shell: "rsync -r --exclude='*.sample.*' {{nextcloud_webroot}}/config/ {{ nc_archive_path }}/config/"
tags:
- skip_ansible_lint

- name: Download server files for current version
vars:
nc_server_dl_url: "https://download.nextcloud.com/server/releases/nextcloud-{{ nc_status.versionstring }}.zip"
ansible.builtin.get_url:
url: "{{ nc_server_dl_url }}"
checksum: "sha512:{{ nc_server_dl_url }}.sha512"
dest: "{{ nc_archive_path }}/nextcloud-{{ nc_status.versionstring }}.zip"
owner: "{{ nextcloud_backup_owner }}"
group: "{{ nextcloud_backup_group }}"
mode: "{{ nextcloud_backup_file_mode }}"
when: nextcloud_backup_download_server_archive

- name: Export the list of apps in the backup
ansible.builtin.copy:
content: "{{ _nc_app_list.stdout | from_json | to_nice_json }}"
dest: "{{ nc_archive_path }}/installed_apps.json"
owner: "{{ nextcloud_backup_owner }}"
group: "{{ nextcloud_backup_group }}"
mode: "{{ nextcloud_backup_file_mode }}"
30 changes: 30 additions & 0 deletions roles/backup/tasks/finishing.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
---
- name: Create the archive
community.general.archive:
path:
- "{{ nc_archive_path }}/*"
dest: "{{ nc_archive_path }}.{{ nextcloud_backup_format }}"
owner: "{{ nextcloud_backup_owner }}"
group: "{{ nextcloud_backup_group }}"
mode: "{{ nextcloud_backup_file_mode }}"
format: "{{ nextcloud_backup_format | regex_replace('tgz', 'gz') }}"
tags:
- always

- name: Cleanup the archive folder
ansible.builtin.file:
path: "{{ nc_archive_path }}"
state: absent

- name: Leave maintenance mode
ansible.builtin.command: "php {{ nextcloud_webroot }}/occ maintenance:mode --off"
become_user: "{{ nextcloud_websrv_user }}"
become: true
become_method: "{{ occ_become_method }}"
become_flags: "{{ occ_become_flags }}"
register: __leave_maintenance
changed_when:
- __leave_maintenance.stdout | regex_search('already') == none
when: nextcloud_exit_maintenance_mode
tags:
- always
Loading