{"id":19109995,"url":"https://github.com/coopdevs/backups_role","last_synced_at":"2026-03-02T12:05:35.259Z","repository":{"id":52190769,"uuid":"157860893","full_name":"coopdevs/backups_role","owner":"coopdevs","description":"Backups strategy for Coopdevs projects","archived":false,"fork":false,"pushed_at":"2025-01-27T16:28:06.000Z","size":130,"stargazers_count":1,"open_issues_count":1,"forks_count":1,"subscribers_count":10,"default_branch":"master","last_synced_at":"2025-04-19T08:33:22.740Z","etag":null,"topics":["ansible","ansible-role","backup"],"latest_commit_sha":null,"homepage":"https://galaxy.ansible.com/coopdevs/backups_role","language":"Jinja","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/coopdevs.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":null,"code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2018-11-16T11:53:36.000Z","updated_at":"2025-02-10T13:38:43.000Z","dependencies_parsed_at":"2024-11-09T04:24:40.938Z","dependency_job_id":"075de5e7-fd53-4af2-97a0-aa44e896f79a","html_url":"https://github.com/coopdevs/backups_role","commit_stats":null,"previous_names":[],"tags_count":18,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/coopdevs%2Fbackups_role","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/coopdevs%2Fbackups_role/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/coopdevs%2Fbackups_role/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/coopdevs%2Fbackups_role/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/coopdevs","download_url":"https://codeload.github.com/coopdevs/backups_role/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":251777972,"owners_count":21642251,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ansible","ansible-role","backup"],"created_at":"2024-11-09T04:23:13.794Z","updated_at":"2026-03-02T12:05:30.198Z","avatar_url":"https://github.com/coopdevs.png","language":"Jinja","funding_links":[],"categories":[],"sub_categories":[],"readme":"backups_role\n=========\n\nBackup and restore strategies for Coopdevs projects.\n\nRequirements\n------------\n\nThis role uses [Restic](https://restic.net) with the help of [restic-ansible](https://github.com/coopdevs/restic-role)\n\nRole Variables\n--------------\n```yaml\n# Restic version\nbackups_role_restic_version: '0.16.4'\n\n# Location of the scripts\nbackups_role_path: '/opt/backup'\nbackups_role_script_dir: \"{{ backups_role_path }}/bin\"\n\n# Overridable name of the template to generate\n#+ the \"prepare\" script, which will be embedded inside\n#+ the rendered script `backups_role_script_path`\nbackups_role_script_prepare_template: \"cron-prepare.sh.j2\"\n\n# If you modify backups_role_script_prepare_template , then it means that you are not using\n#+ the default script template and therefore we don't need to create postgres roles, etc.\n#+ and you may not need sudoer permissions for tar. Therefore, we disable\n#+ the related tasks by default. However, if you would like to enable those tasks,\n#+ set to true the corresponding variables:\nbackups_role_postgresql_enabled:\nbackups_role_sudoers_enabled:\n\n# Complete path to rendered script formed by main, prepare and upload.\nbackups_role_script_path:    \"{{ backups_role_script_dir }}/backup.sh\"\n\n# Location of the files generated by cron jobs\nbackups_role_tmp_path: '/tmp/backups'\n\n# Lists of paths to backup\nbackups_role_assets_paths: []\n\n# System user, its primary group, and additional ones.\n#+ Who will run scripts, restic and cron jobs\n#+  and will own directories and files\nbackups_role_user_name: 'backups'\nbackups_role_user_group: 'backups'\nbackups_role_user_groups: ''\n\n# Postgresql internal read-only role to perform the dump\nbackups_role_postgresql_user_name: \"{{ backups_role_user_name }}\"\n# Postgres internal admin role\npostgresql_user: \"postgres\"\nbackups_role_db_names: [ \"postgres\" ]\n\n# Restic repository name used only in case\n#+ we need to address different restic repos\nbackups_role_restic_repo_name: {{ escaped_inventory_hostname }}\n\n#########################################\n### WARNING! Sensible variables below ###\n#########################################\n###  Consider placing them inside an  ###\n###  ansible-vault. As an example see ###\n###  defaults/secrets.yml.example     ###\n#########################################\n\n# Password for postgresql unprivileged backups user\nbackups_role_postgresql_user_password:\n\n# Restic repository password. A new password you provide to encrypt the backups.\nbackups_role_restic_repo_password:\n\n# Remote bucket URL in restic format\n# Example for backblaze:  \"b2:bucketname:path/to/repo\". Chances are that\n#   \"b2:bucketname:/\" will work for you.\n# Example for local repo: \"/var/backups/repo\"\nbackups_role_restic_repo_url:\n\n# Backblaze \"application\" key, restricted to the bucket referenced above\n# More on this at the example secrets file and\n# at https://gitlab.com/coopdevs/b2-bucket-and-key\nbackups_role_b2_app_key_id:\nbackups_role_b2_app_key:\n```\n\n\nDependencies\n------------\n\n* [coopdevs.restic-role](https://github.com/coopdevs/restic-role)\n\nUsage\n-----\n\nYou will need to prepare an inventory for your hosts with the variables above. For instance, in `inventory/hosts`\n\n### Sample postgresql playbook with backups\n```yaml\n# playbooks/main.yml\n---\n- name: Install Postgresql with automatic backups\n  hosts: servers\n  become: yes\n  roles:\n    - role: geerlingguy.postgresql\n    - role: coopdevs.backups_role\n```\n\n### Playbook to restore a backup to the controller\n```yaml\n# playbooks/restore.yml\n---\n- name: Restore backup locally\n  hosts: servers\n  connection: local\n  tasks:\n  - import_role:\n      name: coopdevs.backups_role\n      tasks_from: restore-to-controller.yml\n```\n\n### Playbook to restore a backup to the host\n```yaml\n# playbooks/restore-in-situ.yml\n---\n- name: Restore backup to the host\n  hosts: servers\n  tasks:\n  - import_role:\n      name: coopdevs.backups_role\n      tasks_from: restore-to-host.yml\n```\n\n### Restore snapshot using playbook from above\n```shell\nansible-playbook playbooks/restore.yml -i inventory/hosts -l servers\n```\n\nThis playbook won't install any binary globally, but it still needs root power. Therefore, you may need to provide sudo password:\n```shell\nansible-playbook playbooks/restore.yml -i inventory/hosts -l servers --ask-become-pass\n```\n\nBy default, it creates a directory with restic and a handy wrapper and a restore of the latest snapshot. Finally, it removes securely the wrapper, as it contains credentials that we don't want them to be lying around. However, if you prefer to install the wrapper and use it manually, you can run the playbook with by the tag `install`:\n\n```shell\nansible-playbook playbooks/restore.yml -i inventory/hosts -l servers --tags install\n```\n\n### Custom backup script\n\nWhen your app doesn't use PostgreSQL or the backup script doesn't fit your needs, you can provide yours by passing a new template to `backups_role_script_prepare_template`. You can use the same helper methods `log` and `run` specified in [cron-main.sh.j2](https://github.com/coopdevs/backups_role/blob/master/templates/cron-main.sh.j2). You can refer to any vars you may have specified in the `include_role` declaration.\n\nThe upload of the backup to the object storage can't be customized and so you still need to specify the paths where your script leaves the backup files with `backups_role_assets_paths`. Yes, that var should be named something like `backups_role_file_to_upload` or similar :shrug:. See [cron-upload.sh.j2](https://github.com/coopdevs/backups_role/blob/master/templates/cron-upload.sh.j2) for details.\n\nNote that although it doesn't apply in this case, this var also used in [cron-prepare.sh](https://github.com/coopdevs/backups_role/blob/master/templates/cron-prepare.sh.j2) to list the files to backup and this can be very confusing. It has two different usages.\n\nSee https://github.com/coopdevs/donalo/pull/82 or https://gitlab.com/coopdevs/odoo-provisioning/-/tree/master/roles/backups for production-ready examples.\n\n\nSensible variables\n------------------\nPlease protect at least the variables below the \"sensible variables\" above. To do so, use [Ansible Vault](https://docs.ansible.com/ansible/latest/user_guide/vault.html) to encrypt with a passphrase the config file with these vars.\n\n\nBackblaze\n---------\nBackblaze provides two kind of keys: account or master, and application. There's only one account key and has power over all other keys and all the buckets. We can have many app keys, that can have rw access to either all or exactly one bucket.\n\nWe should not use the account key to access a bucket or reuse application keys. Even if restic passwords are different, and buckets are different, one server could be able to delete backups of others, or even create more buckets, fill them, and feed the bill.\n\nTherefore, we use app keys instead of the master key. As per `ansible-restic`, it just passes the credentials to restic, regardless of the type of key. Actually, we set `ansible-restic`'s `b2_account_key` (suggests using the master key) with `backup-role`'s `backups_role_b2_app_key` (suggests using an app key).\n\nWhat restic calls \"Account key\" appears at B2 web as \"Master application key\".\n\nIf you want to create a new bucket and a restricted app key, you can use the [Backblaze bucket and key](https://gitlab.com/coopdevs/b2-bucket-and-key) script.\n\nRestic\n------\n\nRestic will create a \"repository\" during the Ansible provisioning. This looks like a directory inside the BackBlaze bucket being the path inside the bucket the last part of `backups_role_bucket_url`, split by `:`. If you want to place it at the root, try something like `b2:mybucket:/`. More on this at [restic docs](https://restic.readthedocs.io/en/latest/030_preparing_a_new_repo.html#backblaze-b2). From the outside, you will see:  \n`config  data  index  keys  locks  snapshots`\n\nAnd if you decrypt it, for instance, when [mounting it](https://restic.readthedocs.io/en/latest/050_restore.html#restore-using-mount):  \n`hosts  ids  snapshots  tags`\n\nHowever, you may probably want to restore just a particular snapshot from the repo. To do it, use [`restic restore`](https://restic.readthedocs.io/en/latest/050_restore.html#restoring-from-a-snapshot). You will need to provide it with the snapshot id you want to resotore and the target dir to unload it. You can explore snapshots doing [`restic snapshots`](https://restic.readthedocs.io/en/latest/045_working_with_repos.html#listing-all-snapshots). A particular case is to restore the last snapshot, where you can use `latest` as snapshot id.\n\nTo restore just a file from the last snapshot instead of the whole repo, you can use the `dump` subcommand: `restic dump latest myfile \u003e /home/user/myfile`\n\nRemember that all restic commands need to know where to communicate to and which credentials with. So you can either pass them as parameters, or export them as environment variables. For this case, we need:\n\n```sh\nexport RESTIC_REPOSITORY=\"b2:mybucketname:/\"\nexport RESTIC_PASSWORD=\"long sentence with at least 7 words\"\nexport B2_ACCOUNT_ID=\"our app key id\"\nexport B2_ACCOUNT_KEY=\"our app key that is very long and has numbers and uppercase letters\"\n```\n\n\nLicense\n-------\n\nGPLv3\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcoopdevs%2Fbackups_role","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcoopdevs%2Fbackups_role","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcoopdevs%2Fbackups_role/lists"}