├── .gitattributes ├── .github ├── FUNDING.yml ├── dependabot.yml ├── workflows │ ├── test.yaml │ └── publish.yaml ├── stale.yml └── renovate.json ├── remote-backup ├── icon.png ├── logo.png ├── build.yaml ├── DOCS.md ├── Dockerfile ├── config.yaml ├── apparmor.txt ├── translations │ └── en.yaml ├── CHANGELOG.md └── run.sh ├── .vscode └── tasks.json ├── .devcontainer └── devcontainer.json ├── README.md └── assets └── Logo.svg /.gitattributes: -------------------------------------------------------------------------------- 1 | text eol=lf -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | ko_fi: mathesonsteplock -------------------------------------------------------------------------------- /remote-backup/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ikifar2012/remote-backup-addon/HEAD/remote-backup/icon.png -------------------------------------------------------------------------------- /remote-backup/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ikifar2012/remote-backup-addon/HEAD/remote-backup/logo.png -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | # Maintain dependencies for GitHub Actions 4 | - package-ecosystem: "github-actions" 5 | directory: "/" 6 | schedule: 7 | interval: "daily" -------------------------------------------------------------------------------- /remote-backup/build.yaml: -------------------------------------------------------------------------------- 1 | squash: false 2 | build_from: 3 | aarch64: ghcr.io/hassio-addons/base/aarch64:18.2.1 4 | amd64: ghcr.io/hassio-addons/base/amd64:18.2.1 5 | armhf: ghcr.io/hassio-addons/base/armhf:18.2.1 6 | armv7: ghcr.io/hassio-addons/base/armv7:18.2.1 7 | i386: ghcr.io/hassio-addons/base/i386:18.2.1 8 | -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.0.0", 3 | "tasks": [ 4 | { 5 | "label": "Start Home Assistant", 6 | "type": "shell", 7 | "command": "supervisor_run", 8 | "group": { 9 | "kind": "test", 10 | "isDefault": true 11 | }, 12 | "presentation": { 13 | "reveal": "always", 14 | "panel": "new" 15 | }, 16 | "problemMatcher": [] 17 | } 18 | ] 19 | } 20 | -------------------------------------------------------------------------------- /.github/workflows/test.yaml: -------------------------------------------------------------------------------- 1 | name: "Test" 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | build: 7 | name: Test build 8 | runs-on: ubuntu-latest 9 | steps: 10 | - name: Checkout the repository 11 | uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6 12 | - name: Test build 13 | uses: home-assistant/builder@master 14 | with: 15 | args: | 16 | --test \ 17 | --all \ 18 | --target remote-backup \ 19 | --docker-hub ikifar \ 20 | --cosign 21 | -------------------------------------------------------------------------------- /.github/stale.yml: -------------------------------------------------------------------------------- 1 | # Number of days of inactivity before an issue becomes stale 2 | daysUntilStale: 60 3 | # Number of days of inactivity before a stale issue is closed 4 | daysUntilClose: 7 5 | # Issues with these labels will never be considered stale 6 | exemptLabels: 7 | - pinned 8 | - security 9 | # Label to use when marking an issue as stale 10 | staleLabel: stale 11 | # Comment to post when marking an issue as stale. Set to `false` to disable 12 | markComment: > 13 | This issue has been automatically marked as stale because it has not had 14 | recent activity. It will be closed if no further activity occurs. Thank you 15 | for your contributions. 16 | # Comment to post when closing a stale issue. Set to `false` to disable 17 | closeComment: false -------------------------------------------------------------------------------- /remote-backup/DOCS.md: -------------------------------------------------------------------------------- 1 | # Documentation 2 | 3 | Please visit the documentation at [addons.mathesonsteplock.ca](https://addons.mathesonsteplock.ca/docs/addons/remote-backup/basic-config) 4 | 5 | ## Security 6 | For SSH and rsync operation it is recommend to add the public key of the remote host to the file `/config/known_hosts`. If you see a warning `Missing known_hosts file!` then you have not done so and the add-on automatically does it for you each time it is called. 7 | **Note that this is a security risk** which can be fixed by executing `ssh-keyscan -t rsa >> /addon_configs/3490a758_remote_backup/known_hosts` from a terminal, e.g. [SSH & Web Terminal](https://github.com/hassio-addons/addon-ssh). 8 | 9 | # Support Me 10 | 11 | [![ko-fi](https://ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/mathesonsteplock) 12 | -------------------------------------------------------------------------------- /.devcontainer/devcontainer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Remote Backup Addon", 3 | "image": "ghcr.io/home-assistant/devcontainer:addons", 4 | "appPort": ["7123:8123", "7357:4357"], 5 | "postStartCommand": "bash devcontainer_bootstrap", 6 | "runArgs": ["-e", "GIT_EDITOR=code --wait", "--privileged"], 7 | "containerEnv": { 8 | "WORKSPACE_DIRECTORY": "${containerWorkspaceFolder}" 9 | }, 10 | "extensions": [ 11 | "timonwong.shellcheck", 12 | "esbenp.prettier-vscode", 13 | "GitHub.copilot", 14 | "GitHub.vscode-pull-request-github", 15 | "bierner.markdown-preview-github-styles" 16 | ], 17 | "mounts": [ "type=volume,target=/var/lib/docker" ], 18 | "settings": { 19 | "terminal.integrated.profiles.linux": { 20 | "zsh": { 21 | "path": "/usr/bin/zsh" 22 | } 23 | }, 24 | "terminal.integrated.defaultProfile.linux": "zsh", 25 | "editor.formatOnPaste": false, 26 | "editor.formatOnSave": true, 27 | "editor.formatOnType": true, 28 | "files.trimTrailingWhitespace": true 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Remote Backup 2 | 3 | This add-on is a fork of the work of [carstenschroeder] which was originally created by [overkill32] 4 | 5 | # Installation 6 | 7 | This add-on can be added via my [Home Assistant Add-on repository](https://github.com/ikifar2012/ha-addons): 8 | 9 | [![Open your Home Assistant instance and show the add add-on repository dialog with a specific repository URL pre-filled.](https://my.home-assistant.io/badges/supervisor_add_addon_repository.svg)](https://my.home-assistant.io/redirect/supervisor_add_addon_repository/?repository_url=https%3A%2F%2Fgithub.com%2Fikifar2012%2Fha-addons) 10 | 11 | # [Documentation](https://addons.mathesonsteplock.ca/docs/addons/remote-backup/basic-config) 12 | 13 | # Support Me 14 | 15 | [![ko-fi](https://ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/mathesonsteplock) 16 | 17 | [overkill32]: https://github.com/overkill32/hassio-remote-backup 18 | [carstenschroeder]: https://github.com/carstenschroeder/hassio-addons 19 | [here]: https://www.home-assistant.io/hassio/installing_third_party_addons/ 20 | -------------------------------------------------------------------------------- /.github/workflows/publish.yaml: -------------------------------------------------------------------------------- 1 | name: "Publish" 2 | 3 | on: 4 | workflow_dispatch: 5 | release: 6 | types: [published] 7 | 8 | jobs: 9 | publish: 10 | name: Publish 11 | runs-on: ubuntu-latest 12 | steps: 13 | - name: Checkout the repository 14 | uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6 15 | - name: Login to DockerHub 16 | uses: docker/login-action@v3 17 | with: 18 | username: ${{ secrets.DOCKERHUB_USERNAME }} 19 | password: ${{ secrets.DOCKERHUB_TOKEN }} 20 | - name: Publish 21 | uses: home-assistant/builder@master 22 | with: 23 | args: | 24 | --all \ 25 | --target remote-backup \ 26 | --docker-user ${{ secrets.DOCKERHUB_USERNAME }} \ 27 | --docker-password ${{ secrets.DOCKERHUB_TOKEN }} 28 | 29 | - name: 🚀 Dispatch Repository Updater update signal 30 | uses: peter-evans/repository-dispatch@v4 31 | with: 32 | token: ${{ secrets.DISPATCH_TOKEN }} 33 | repository: ikifar2012/ha-addons 34 | event-type: update 35 | client-payload: '{"addon": "remote-backup"}' 36 | -------------------------------------------------------------------------------- /remote-backup/Dockerfile: -------------------------------------------------------------------------------- 1 | ARG BUILD_FROM 2 | FROM ${BUILD_FROM} 3 | 4 | SHELL ["/bin/bash", "-o", "pipefail", "-c"] 5 | 6 | # Add env 7 | ENV LANG C.UTF-8 8 | 9 | # Setup base 10 | RUN apk add --no-cache jq openssh-client sshpass rsync curl unzip 11 | 12 | # Rclone CLI 13 | ARG BUILD_ARCH 14 | RUN curl https://rclone.org/install.sh | bash 15 | 16 | # Copy data 17 | COPY run.sh / 18 | RUN chmod a+x run.sh 19 | CMD [ "/run.sh" ] 20 | 21 | # Build arugments 22 | ARG BUILD_DATE 23 | ARG BUILD_REF 24 | ARG BUILD_VERSION 25 | 26 | # Labels 27 | LABEL \ 28 | io.hass.name="Remote Backup" \ 29 | io.hass.description="Automatically create and transfer HA backups using SFTP (SCP), rsync." \ 30 | io.hass.arch="${BUILD_ARCH}" \ 31 | io.hass.type="addon" \ 32 | io.hass.version=${BUILD_VERSION} \ 33 | maintainer="Matheson Steplock " \ 34 | org.label-schema.description="Automatically create and transfer HA backups using SFTP (SCP), rsync." \ 35 | org.label-schema.build-date=${BUILD_DATE} \ 36 | org.label-schema.name="Remote Backup" \ 37 | org.label-schema.schema-version="1.0" \ 38 | org.label-schema.usage="https://github.com/ikifar2012/remote-backup-addon/blob/master/README.md" \ 39 | org.label-schema.vcs-ref=${BUILD_REF} \ 40 | org.label-schema.vcs-url="https://github.com/ikifar2012/remote-backup-addon/" \ 41 | org.label-schema.vendor="Matheson's Home Assistant Addons" 42 | -------------------------------------------------------------------------------- /.github/renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://docs.renovatebot.com/renovate-schema.json", 3 | "rebaseWhen": "behind-base-branch", 4 | "dependencyDashboard": true, 5 | "labels": ["dependencies", "no-stale"], 6 | "commitMessagePrefix": "⬆️", 7 | "commitMessageTopic": "{{depName}}", 8 | "regexManagers": [ 9 | { 10 | "fileMatch": [ 11 | "^(.*\/)?(Dockerfile|build\\.yaml)$" 12 | ], 13 | "matchStringsStrategy": "any", 14 | "matchStrings": [ 15 | "ARG BUILD_FROM=(?.*?):(?.*?)\\s+", 16 | "(aarch64|amd64|armhf|armv7|i386):\\s[\"']?(?.*?):(?.*?)[\"']?\\s" 17 | ], 18 | "datasourceTemplate": "docker" 19 | }, 20 | { 21 | "fileMatch": ["/Dockerfile$"], 22 | "matchStringsStrategy": "any", 23 | "matchStrings": [ 24 | "\\s\\s(?[a-z0-9-]+)=(?[a-z0-9-_.]+)\\s+" 25 | ], 26 | "versioningTemplate": "loose", 27 | "datasourceTemplate": "repology", 28 | "depNameTemplate": "alpine_3_17/{{package}}" 29 | } 30 | ], 31 | "packageRules": [ 32 | { 33 | "matchDatasources": ["repology"], 34 | "automerge": true 35 | }, 36 | { 37 | "groupName": "Add-on base image", 38 | "matchDatasources": ["docker"] 39 | }, 40 | { 41 | "groupName": "Add-on base image", 42 | "matchDatasources": ["docker"], 43 | "matchUpdateTypes": ["minor", "patch"], 44 | "automerge": true 45 | }, 46 | { 47 | "matchDatasources": ["github-tags"], 48 | "automerge": true 49 | } 50 | ] 51 | } -------------------------------------------------------------------------------- /remote-backup/config.yaml: -------------------------------------------------------------------------------- 1 | name: Remote Backup 2 | version: "2025.2.0" 3 | slug: remote_backup 4 | description: Automatically create and transfer HA backups using SFTP (SCP), rsync, or rclone (experimental) 5 | image: ikifar/remote-backup-{arch} 6 | url: https://addons.mathesonsteplock.ca/docs/addons/remote-backup/basic-config 7 | startup: once 8 | boot: manual 9 | init: false 10 | apparmor: false 11 | arch: 12 | - aarch64 13 | - amd64 14 | - armhf 15 | - armv7 16 | - i386 17 | homeassistant: "2021.9.0" 18 | hassio_api: true 19 | hassio_role: manager 20 | homeassistant_api: true 21 | map: 22 | - addon_config:rw 23 | - addons 24 | - share 25 | - ssl:rw 26 | - backup:rw 27 | - homeassistant_config 28 | - all_addon_configs 29 | 30 | options: 31 | remote_host: null 32 | remote_port: 22 33 | remote_user: null 34 | remote_key: "" 35 | backup_friendly_name: true 36 | backup_custom_prefix: Automated_backup 37 | backup_custom_delimiter: "_" 38 | backup_keep_local: "all" 39 | ssh_enabled: true 40 | ssh_remote_directory: "hassio-backup" 41 | rsync_enabled: false 42 | rsync_rootfolder: hassio-sync 43 | rsync_exclude: 44 | - "/config/*.db-shm" 45 | - "/config/*.db-wal" 46 | - "/config/*.db" 47 | 48 | schema: 49 | debug: bool? 50 | remote_host: str 51 | remote_port: port 52 | remote_user: str 53 | remote_password: str? 54 | remote_key: str? 55 | remote_host_key_algorithms: str? 56 | backup_friendly_name: bool? 57 | backup_custom_prefix: str? 58 | backup_custom_delimiter: str? 59 | backup_exclude_folders: 60 | - match(^[A-Za-z0-9_\-\.\*\/\?\+\\ ]*$)? 61 | backup_exclude_addons: 62 | - str? 63 | backup_keep_local: match(^(all|null|[+]?\d*)$)? 64 | backup_password: str? 65 | ssh_enabled: bool 66 | ssh_remote_directory: str? 67 | rsync_enabled: bool 68 | rsync_rootfolder: str? 69 | rsync_exclude: 70 | - match(^[A-Za-z0-9_\-\.\*\/\?\+\\ ]+$)? 71 | rclone_enabled: bool? 72 | rclone_remote_directory: str? 73 | rclone_remote_host: str? 74 | rclone_copy: bool? 75 | rclone_sync: bool? 76 | rclone_restore: bool? 77 | -------------------------------------------------------------------------------- /remote-backup/apparmor.txt: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | profile remote_backup flags=(attach_disconnected,mediate_deleted) { 4 | #include 5 | 6 | # Capabilities 7 | file, 8 | signal (send) set=(kill,term,int,hup,cont), 9 | network, 10 | 11 | # S6-Overlay 12 | /init ix, 13 | /bin/** ix, 14 | /usr/bin/** ix, 15 | /run/{s6,s6-rc*,service}/** ix, 16 | /package/** ix, 17 | /command/** ix, 18 | /etc/services.d/** rwix, 19 | /etc/cont-init.d/** rwix, 20 | /etc/cont-finish.d/** rwix, 21 | /run/{,**} rwk, 22 | /dev/tty rw, 23 | 24 | # Bashio 25 | /usr/lib/bashio/** ix, 26 | /tmp/** rwk, 27 | 28 | # Access to options.json and other files within your addon 29 | /data/** rw, 30 | 31 | # Start new profile for service 32 | /run.sh cx -> run.sh, 33 | 34 | profile run.sh flags=(attach_disconnected,mediate_deleted) { 35 | #include 36 | 37 | # Capabilities 38 | file, 39 | signal (send) set=(kill,term,int,hup,cont), 40 | network, 41 | 42 | # Receive signals from S6-Overlay 43 | signal (receive) peer=*_remote_backup_*, # <- Replace with your service name 44 | 45 | 46 | # Access to options.json and other files within your addon 47 | /data/** rw, 48 | 49 | # Access to mapped volumes specified in config.json 50 | /config/** rw, 51 | /addons/** rw, 52 | /share/** rw, 53 | /ssl/** rw, 54 | /backup/** rw, 55 | /homeassistant_config/** rw, 56 | 57 | # Access required for service functionality 58 | /run.sh r, 59 | /bin/bash rix, 60 | /usr/bin/curl rix, 61 | /bin/echo ix, 62 | /etc/passwd r, 63 | /dev/tty rw, 64 | } 65 | profile /usr/bin/curl flags=(attach_disconnected,mediate_deleted) { 66 | #include 67 | 68 | # Capabilities 69 | file, 70 | signal (send) set=(kill,term,int,hup,cont), 71 | network, 72 | 73 | # Receive signals from S6-Overlay 74 | signal (receive) peer=*_remote_backup_*, # <- Replace with your service name 75 | 76 | 77 | # Access to options.json and other files within your addon 78 | /data/** rw, 79 | 80 | # Access to mapped volumes specified in config.json 81 | /config/** rw, 82 | /addons/** rw, 83 | /share/** rw, 84 | /ssl/** rw, 85 | /backup/** rw, 86 | /homeassistant_config/** rw, 87 | 88 | # Access required for service functionality 89 | /run.sh r, 90 | /bin/bash rix, 91 | /usr/bin/curl rix, 92 | /bin/echo ix, 93 | /etc/passwd r, 94 | /dev/tty rw, 95 | } 96 | } -------------------------------------------------------------------------------- /remote-backup/translations/en.yaml: -------------------------------------------------------------------------------- 1 | configuration: 2 | debug: 3 | name: Enable debugging 4 | remote_host: 5 | name: Remote host 6 | description: The hostname or IP address of the remote server 7 | remote_port: 8 | name: Remote port 9 | description: Port number of the remote server 10 | remote_user: 11 | name: Username 12 | description: Username to be used for authentication with remote server 13 | remote_password: 14 | name: Password 15 | description: Password to be used for authentication with remote server 16 | remote_key: 17 | name: SSH private key 18 | description: SSH private key file to be used for authentication with remote server. The key must be stored in the directory 'addon_configs/3490a758_remote_backup' of Home Assistant. 19 | remote_host_key_algorithms: 20 | name: Host key algorithms 21 | description: Can be used to enable further (legacy) algorithms for authentication 22 | backup_friendly_name: 23 | name: Friendly name 24 | description: Rename the backup on the destination server to match the name in the Home Assistant UI 25 | backup_custom_prefix: 26 | name: Custom backup name prefix 27 | description: Prefix to be used for the backup name 28 | backup_custom_delimiter: 29 | name: Custom backup name delimiter 30 | description: Allows you to change the delimiter between the prefix and the date of the snapshot, by default this is set to `_` 31 | backup_exclude_folders: 32 | name: Folder to exclude from backup 33 | description: valid options are addons/local, homeassistant, media, share, ssl, all_addon_configs 34 | backup_exclude_addons: 35 | name: Addon to exclude from backup 36 | description: Give the addons slug which equals the addon hostname using '_' instead of '-', e.g. core_mariadb 37 | backup_keep_local: 38 | name: Local backups to keep 39 | description: default is 'all', give a number for the last x backups to keep or 'null' to immediately remove created backups after copying. 40 | backup_password: 41 | name: Password for protected backup 42 | ssh_enabled: 43 | name: Enable SSH 44 | description: Copies Home Assistant backups to the remote server 45 | ssh_remote_directory: 46 | name: SSH remote directory 47 | description: Remote directory the backups are copied to (path must exist) 48 | rsync_enabled: 49 | name: Enable rsync 50 | description: Clones local folders to remote server (including backups) 51 | rsync_rootfolder: 52 | name: rsync root folder 53 | description: Root folder to which Home Assistant directories are synchronized 54 | rsync_exclude: 55 | name: rsync path patterns to exclude from sync 56 | description: This feature uses the rsync --exclude scheme 57 | rclone_enabled: 58 | name: Enable rclone (experimental) 59 | -------------------------------------------------------------------------------- /assets/Logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 15 | 17 | 39 | 50 | 58 | 65 | 66 | -------------------------------------------------------------------------------- /remote-backup/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # 2025.2.0 2 | 3 | ## ⚠️Warning: Breaking Changes Ahead⚠️ 4 | 5 | - **Breaking Change** - Add `backup_custom_delimiter` option to allow for custom delimiters in backup names by default this is set to `_` (you may need to update your configuration to include this option) 6 | - **Breaking Change** - Change `backup_custom_prefix` from `Automated backup` to `Automated_backup` for better compatibility with some systems (most people will not notice this change) 7 | 8 | ## 🤔 What's Changed 9 | 10 | - ✨ Update backup name format to include custom delimiter by @ikifar2012 in https://github.com/ikifar2012/remote-backup-addon/pull/169 Solves: ([#177](https://github.com/ikifar2012/remote-backup-addon/issues/177)) 11 | - ⬆️Update Descriptions by @ikifar2012 in https://github.com/ikifar2012/remote-backup-addon/pull/178 Mitigates: ([#166](https://github.com/ikifar2012/remote-backup-addon/issues/166)) 12 | - ⬆️ Update Add-on base image to v17.2.1 by @renovate in https://github.com/ikifar2012/remote-backup-addon/pull/176 13 | - ⬆️ Update actions/checkout digest to 11bd719 by @renovate in https://github.com/ikifar2012/remote-backup-addon/pull/163 14 | 15 | **Full Changelog**: https://github.com/ikifar2012/remote-backup-addon/compare/2024.6.0...2025.2.0 16 | 17 | # 2024.6.0 18 | 19 | - Fix error notifications 20 | - Fix SSH key permissions 21 | - ⬆️ Update actions/checkout digest to a5ac7e5 by @renovate in https://github.com/ikifar2012/remote-backup-addon/pull/142 22 | - ⬆️ Update Add-on base image to v16 (major) by @renovate in https://github.com/ikifar2012/remote-backup-addon/pull/144 23 | 24 | **Full Changelog**: https://github.com/ikifar2012/remote-backup-addon/compare/2024.4.0...2024.5.0 25 | 26 | # 2024.4.0 27 | 28 | - ⬆️ Update peter-evans/repository-dispatch action to v3 by @renovate in https://github.com/ikifar2012/remote-backup-addon/pull/130 29 | - ⬆️ Update Add-on base image to v15.0.7 by @renovate in https://github.com/ikifar2012/remote-backup-addon/pull/132 30 | - Fix rsync folders ([#134](https://github.com/ikifar2012/remote-backup-addon/issues/134)) 31 | 32 | **Full Changelog**: https://github.com/ikifar2012/remote-backup-addon/compare/2023.12.0...2024.4.0 33 | 34 | # 2023.12.0 35 | 36 | - ⬆️ Bump base image to 15.0.1 from 13.1.3 37 | - **Breaking Change** - Switch from `/ssl` to `addon_configs/3490a758_remote_backup` for config directory (migration should be automatic) 38 | - Temporarily disable `apparmor` to fix #119 39 | - Drop CodeNotary signing 40 | 41 | **Full Changelog**: https://github.com/ikifar2012/remote-backup-addon/compare/2023.3.0...2023.12.0 42 | 43 | # 2023.3.0 44 | 45 | - Bump base image from 13.0.0 to 13.1.3 46 | - Fix quoting issue #89 47 | 48 | **Full Changelog**: https://github.com/ikifar2012/remote-backup-addon/compare/2022.12.1...2023.3.0 49 | 50 | # 2022.12.1 51 | 52 | - Fix `scp: dest open` double quoting issue #86 addresses #84 53 | - Correct null behavior #85 addresses #81 54 | - Bump Base Image to 13.0.1 55 | 56 | **Full Changelog**: https://github.com/ikifar2012/remote-backup-addon/compare/2022.12.0...2022.12.1 57 | 58 | # 2022.12.0 59 | 60 | - Bump Base Image to 13.0.0 61 | - extend connection debug messages #77 62 | - Logo #78 63 | - Add null option #83 64 | 65 | **Full Changelog**: https://github.com/ikifar2012/remote-backup-addon/compare/2022.9.4...2022.12.0 66 | 67 | # 2022.9.4 68 | 69 | - Message typo fix #73 70 | 71 | **Full Changelog**: https://github.com/ikifar2012/remote-backup-addon/compare/2022.9.3...2022.9.4 72 | 73 | # 2022.9.3 74 | 75 | - Switch to `bashio::config.has_value` to fix #70 76 | 77 | **Full Changelog**: https://github.com/ikifar2012/remote-backup-addon/compare/2022.9.2...2022.9.3 78 | 79 | # 2022.9.2 80 | 81 | - Fix password check #69 82 | 83 | **Full Changelog**: https://github.com/ikifar2012/remote-backup-addon/compare/2022.9.1...2022.9.2 84 | 85 | # 2022.9.1 86 | 87 | - Backup password fix #68 88 | 89 | **Full Changelog**: https://github.com/ikifar2012/remote-backup-addon/compare/2022.9.0...2022.9.1 90 | 91 | # 2022.9.0 92 | 93 | ## Please read before upgrading 94 | 95 | **This release includes a ton of breaking changes** 96 | **Please read the documentation carefully before upgrading** 97 | **Be aware that some of the configuration options have been renamed and may overwrite your current settings** 98 | 99 | Please backup your configuration before upgrading by clicking the vertical dots in the top right corner of the add-on configuration page 100 | and click "Edit in YAML", you can then copy that to a text file and map those settings to their new config options as per the 101 | [documentation](https://addons.mathesonsteplock.ca/docs/addons/remote-backup/basic-config). 102 | 103 | - enable rsync key-based authentication #51 104 | - changed logging to bashio logger #52 105 | - Rsync cleanup #54 106 | - Configuration documentation #56 107 | - Replace zip password with built in backup password #57 108 | - renamed and resorted configuration #58 109 | - Improve error handling #59 110 | - Security enhancements #60 111 | - Bump base image to 12.2.3 112 | - added SFTP/SCP fallback and password auth #64 113 | - Restore rclone config option #66 114 | 115 | Huge thanks to [@patman15](https://github.com/patman15) for all of his work this release! 116 | 117 | **Full Changelog**: https://github.com/ikifar2012/remote-backup-addon/compare/2022.7.2...2022.9.0 118 | 119 | # 2022.7.2 120 | 121 | - Add init to config.yml to solve `s6-overlay-suexec: fatal: can only run as pid 1` 122 | 123 | **Full Changelog**: https://github.com/ikifar2012/remote-backup-addon/compare/2022.7.1...2022.7.2 124 | 125 | # 2022.7.1 126 | 127 | - Update git index 128 | 129 | **Full Changelog**: https://github.com/ikifar2012/remote-backup-addon/compare/2022.7.0...2022.7.1 130 | 131 | # 2022.7.0 132 | 133 | - Updated HA CLI to version 4.18.0 134 | - Updated base image to version 12.2.1 135 | - Workaround issue [#45](https://github.com/ikifar2012/remote-backup-addon/issues/45) 136 | - Automate repository updates 137 | 138 | **Full Changelog**: https://github.com/ikifar2012/remote-backup-addon/compare/2022.5.1...2022.7.0 139 | 140 | # 2022.5.1 141 | 142 | - Fix codenotary signature 143 | - Add ko-fi to `FUNDING.yml` 144 | 145 | **Full Changelog**: https://github.com/ikifar2012/remote-backup-addon/compare/2022.5.0...2022.5.1 146 | 147 | # 2022.5.0 148 | 149 | - Updated base image to 11.1.2 150 | - Updated HA CLI to 4.17.0 151 | - Added support for `HostKeyAlgorithms` hopefully fixing #37 152 | - Added support for excluding addons from backup 153 | - Added support for excluding folders from backup 154 | - Fixed shellcheck warnings 155 | - Added minimum Home Assistant version 156 | - Sign images with Codenotary CAS 157 | 158 | **Full Changelog**: https://github.com/ikifar2012/remote-backup-addon/compare/2022.1.1...2022.5.0 159 | 160 | # 2022.1.1 161 | 162 | - Updated url in `config.yaml` 163 | - Fixed `amd64` base image 164 | 165 | **Full Changelog**: https://github.com/ikifar2012/remote-backup-addon/compare/2022.1.0...2022.1.1 166 | 167 | # 2022.1.0 168 | 169 | - Converted to YAML 170 | - Upgraded base image to 11.0.1 171 | - Moved docs to [addons.mathesonsteplock.ca](https://addons.mathesonsteplock.ca/docs/addons/remote-backup/basic-config) 172 | 173 | **Full Changelog**: https://github.com/ikifar2012/remote-backup-addon/compare/2021.12.0...2022.1.0 174 | 175 | # 2021.12.0 176 | 177 | - Upgraded base image to 11.0.0 178 | 179 | **Full Changelog**: https://github.com/ikifar2012/remote-backup-addon/compare/2021.11.2...2021.12.0 180 | 181 | # 2021.11.2 182 | 183 | - Fix typo in rclone causing failure 184 | 185 | **Full Changelog**: https://github.com/ikifar2012/remote-backup-addon/compare/2021.11.1...2021.11.2 186 | 187 | # 2021.11.1 188 | 189 | - Added rsync exclude (#28) 190 | - Made command line output more friendly 191 | - Upgraded base image to 10.2.3 192 | - Switched to Github Actions 193 | 194 | **Full Changelog**: https://github.com/ikifar2012/remote-backup-addon/compare/2021.10.0...2021.11.1 195 | 196 | # 2021.10.0 197 | 198 | - Upgraded Base to 10.1.1 199 | - Upgraded Home Assistant CLI to 4.14.0 200 | - Changed from `snapshots` to `backups` (See Breaking Change #26) 201 | 202 | # 2021.9.0 203 | 204 | - Upgraded Base to 10.0.2 205 | - 🎉 Solved issue #24 thanks to @hendrikma for pointing it out and @DubhAd for helping me solve it!!! 🎉 206 | 207 | # 2021.8.0 208 | 209 | - Upgraded Base to 10.0.1 210 | 211 | # 2021.6.2 212 | 213 | - Upgraded Base to 10.0.0 214 | 215 | # 2021.6.1 216 | 217 | - Upgraded Base to 9.2.2 218 | 219 | # 2021.6.0 220 | 221 | - Upgraded Base to 9.2.1 222 | 223 | # 2021.5.2 224 | 225 | - Upgraded Home Assistant CLI to 4.12.3 226 | 227 | # 2021.5.1 228 | 229 | - Upgraded Home Assistant CLI to 4.12.2 230 | 231 | # 2021.5.0 232 | 233 | - Added rclone 234 | - Upgraded Base to 9.2.0 235 | - rsync now excludes all database files 236 | 237 | # 2021.4.1 238 | 239 | - Removed extra `:` in $rsyncurl 240 | 241 | # 2021.4.0 242 | 243 | - Changed snapshot date scheme `%Y-%m-%d %H-%M` to improve compatibility 244 | - Added `custom_prefix` Allows you to change the name prefixing the date of the snapshot, by default this is set to `Automated backup` 245 | - Added `friendly_name` Allows the snapshot to be renamed on the destination server to match the name in the Home Assistant UI 246 | - Upgraded Base to 9.1.6 247 | - Upgraded Home Assistant CLI to 4.11.3 248 | - Reformatted code 249 | - Addresses issue #13 250 | 251 | # 2021.3.0 252 | 253 | - Upgraded Home Assistant CLI to 4.11.0 254 | - Upgraded Base to 9.1.5 255 | - Changed versioning to match Home Assistant style 256 | -------------------------------------------------------------------------------- /remote-backup/run.sh: -------------------------------------------------------------------------------- 1 | #!/command/with-contenv bashio 2 | # shellcheck shell=bash 3 | # parse global options from configuration 4 | 5 | bashio::config.require "remote_host" "A target host for copying backups is necessary." 6 | bashio::config.require "remote_port" "A target host port for communication is necessary." 7 | bashio::config.require.username "remote_user" 8 | bashio::config.suggest.password "backup_password" 9 | declare -r REMOTE_HOST=$(bashio::config "remote_host") 10 | declare -r REMOTE_PORT=$(bashio::config "remote_port") 11 | declare -r REMOTE_USER=$(bashio::config "remote_user") 12 | declare -r REMOTE_PASSWORD=$(bashio::config "remote_password" "") 13 | function migrate_config { 14 | # if ssh key file exists in /ssl, move it to /config 15 | if bashio::config.has_value "remote_key"; then 16 | if bashio::fs.file_exists "/ssl/$(bashio::config 'remote_key')"; then 17 | bashio::log.notice "Migrating SSH key file from /ssl to /config." 18 | mv "/ssl/$(bashio::config 'remote_key')" "/config/$(bashio::config 'remote_key')" \ 19 | || bashio::log.error "Failed to copy SSH key file!" 20 | fi 21 | fi 22 | # if rclone config file exists in /ssl, move it to /config 23 | if bashio::fs.file_exists "/ssl/rclone.conf"; then 24 | bashio::log.notice "Migrating rclone config file from /ssl to /config." 25 | mv "/ssl/rclone.conf" "/config/rclone.conf" \ 26 | || bashio::log.error "Failed to copy rclone config file!" 27 | fi 28 | # if known_hosts file exists in /ssl, move it to /config 29 | if bashio::fs.file_exists "/ssl/known_hosts"; then 30 | bashio::log.notice "Migrating known_hosts file from /ssl to /config." 31 | mv "/ssl/known_hosts" "/config/known_hosts" \ 32 | || bashio::log.error "Failed to copy known_hosts file!" 33 | fi 34 | # let user know that the migration is complete 35 | if bashio::fs.directory_exists "/ssl" && bashio::fs.directory_exists "/config"; then 36 | bashio::log.notice "Migration complete." 37 | fi 38 | 39 | } 40 | function run_setup { 41 | # create directory for failed backups 42 | bashio::log.notice "Creating directories for failed backup alerts." 43 | mkdir -p /tmp/backup 44 | mkdir -p /tmp/scp 45 | mkdir -p /tmp/rsync 46 | mkdir -p /tmp/rclone 47 | bashio::log.notice "Directories created." 48 | bashio::log.notice "Setup complete." 49 | 50 | 51 | } 52 | # script global shortcuts 53 | declare -r BACKUP_NAME="$(bashio::config 'backup_custom_prefix' '')$(bashio::config 'backup_custom_delimiter' '_')$(date +'%Y-%m-%d %H-%M')" 54 | declare -r SSH_HOME="${HOME}/.ssh" 55 | 56 | function set-debug-level { 57 | # default log level according to bashio const.sh is INFO 58 | if bashio::config.true "debug"; then 59 | bashio::log.level "debug" 60 | declare -r -g DEBUG_FLAG="-v" 61 | fi 62 | } 63 | 64 | function sshpass_error { 65 | local -r -i errno=${1} 66 | local -r sshpass_err=("OK" "Invalid command line argument" "Conflicting arguments given" "General runtime error" "Unrecognized response from ssh (parse error)" "Invalid/incorrect password" "Host public key is unknown." "IP public key changed.") 67 | 68 | if [[ $errno -ge 0 && $errno -le ${#sshpass_err[@]} ]]; then 69 | echo ${sshpass_err[$errno]} 70 | else 71 | echo "unknown error: $errno" 72 | fi 73 | 74 | return "${__BASHIO_EXIT_OK}" 75 | } 76 | 77 | # Arguments: 78 | # $1 result should be ok or error 79 | # $2 message message to send with the event 80 | function fire-event { 81 | local -r result=${1} 82 | local message=${2:-} 83 | 84 | if bashio::var.has_value "${message}"; then 85 | message=",\"message:\":\"${message}\"" 86 | fi 87 | 88 | # catch return code which is always false, see https://github.com/hassio-addons/bashio/issues/31 89 | local ret=$(bashio::api.supervisor POST /core/api/events/remote_backup_status "{\"result\":\"${result}\"${message}}") 90 | } 91 | function die { 92 | local -r message=${1:-'no message'} 93 | local -r title=${2:-'Addon: Remote Backup Failed!'} 94 | 95 | # catch return code which is always false, see https://github.com/hassio-addons/bashio/issues/31 96 | local ret=$(bashio::api.supervisor POST /core/api/services/persistent_notification/create \ 97 | "{\"message\":\"${message}\", \"title\":\"${title}\", \"notification_id\":\"addon-remote-backup\"}") 98 | fire-event "error" "${message}" 99 | bashio::exit.nok "${message}" 100 | } 101 | 102 | # prepare SSH environment/configuration 103 | # function does never fail to continue with further commands 104 | function add-ssh-key { 105 | if ! bashio::config.true "ssh_enabled" && ! bashio::config.true "rsync_enabled"; then 106 | bashio::log.debug "Not creating configuration, SSH/RSYNC disabled." 107 | return 108 | fi 109 | 110 | bashio::log.info "Adding SSH configuration." 111 | # prepare SSH key pair 112 | mkdir -p ${SSH_HOME} || bashio::log.error "Failed to create .ssh directory!" 113 | if bashio::config.has_value "remote_key"; then 114 | bashio::log.notice "Setting up SSH key pair." 115 | ( 116 | cp "/config/$(bashio::config 'remote_key')" "${SSH_HOME}/id_rsa" 117 | chmod 600 "${SSH_HOME}/id_rsa" 118 | ssh-keygen -y -f ${SSH_HOME}/id_rsa > ${SSH_HOME}/id_rsa.pub 119 | chmod 644 "${SSH_HOME}/id_rsa.pub" 120 | ) || bashio::log.error "Failed to create SSH key pair!" 121 | fi 122 | 123 | # copy known_hosts if available 124 | if bashio::fs.file_exists "/config/known_hosts"; then 125 | bashio::log.debug "Using existing /config/known_hosts file." 126 | cp "/config/known_hosts" "${SSH_HOME}/known_hosts" \ 127 | || bashio::log.error "Failed to copy known_hosts file!" 128 | else 129 | bashio::log.warning "Missing known_hosts file! Retrieving public key of remote host ${REMOTE_HOST}." 130 | ssh-keyscan -t rsa -p ${REMOTE_PORT} ${REMOTE_HOST} >> ${SSH_HOME}/known_hosts \ 131 | || bashio::log.error "Failed to add public key for remote host ${REMOTE_HOST}!" 132 | fi 133 | 134 | # generate configuration file 135 | ( 136 | echo "Host remote" 137 | if bashio::fs.file_exists "${SSH_HOME}/id_rsa"; then 138 | echo " IdentityFile ${SSH_HOME}/id_rsa" 139 | fi 140 | echo " HostName ${REMOTE_HOST}" 141 | echo " User ${REMOTE_USER}" 142 | echo " Port ${REMOTE_PORT}" 143 | if bashio::config.has_value "remote_host_key_algorithms"; then 144 | echo " HostKeyAlgorithms $(bashio::config 'remote_host_key_algorithms')" 145 | fi 146 | ) > "${SSH_HOME}/config" 147 | chmod 600 "${SSH_HOME}/config" || bashio::log.error "Failed to set SSH configuration file permissions!" 148 | } 149 | 150 | # call Home Assistant to create a local backup 151 | # function fails in case local backup is not created 152 | function create-local-backup { 153 | local -r base_folders="addons/local homeassistant media share ssl" 154 | local data="{\"name\":\"${BACKUP_NAME}\"}" 155 | local bak_type="non-encrypted" 156 | 157 | if bashio::config.has_value "backup_password"; then 158 | data="$(echo $data | tr -d '}'), \"password\": \"$(bashio::config 'backup_password')\"}" 159 | local -r bak_type="password encrypted" 160 | fi 161 | if bashio::config.has_value "backup_exclude_addons" || bashio::config.has_value "backup_exclude_folders"; then 162 | bashio::log.info "Creating ${bak_type} partial backup: \"${BACKUP_NAME}\"" 163 | 164 | local unformatted_folders="${base_folders}" 165 | local unformatted_addons=$(bashio::supervisor.addons) 166 | 167 | if bashio::config.has_value "backup_exclude_folders"; then 168 | local -r backup_exclude_folders=$(bashio::config "backup_exclude_folders") 169 | bashio::log.notice "Excluded folder(s):\n${backup_exclude_folders}" 170 | for folder in ${backup_exclude_folders} ; do 171 | unformatted_folders="${unformatted_folders[@]/$folder}" 172 | done 173 | fi 174 | if bashio::config.has_value "backup_exclude_addons"; then 175 | local -r backup_exclude_addons=$(bashio::config "backup_exclude_addons") 176 | bashio::log.notice "Excluded addon(s):\n${backup_exclude_addons}" 177 | for addon in ${backup_exclude_addons} ; do 178 | unformatted_addons="${unformatted_addons[@]/$addon}" 179 | done 180 | fi 181 | 182 | local -r addons=$(jq -nc '$ARGS.positional' --args ${unformatted_addons[@]}) 183 | local -r folders=$(jq -nc '$ARGS.positional' --args ${unformatted_folders[@]}) 184 | bashio::log.debug "Including folder(s) ${folders}" 185 | bashio::log.debug "Including addon(s) ${addons}" 186 | 187 | data="$(echo $data | tr -d '}'), \"addons\": ${addons}, \"folders\": ${folders}}" # append addon and folder set 188 | if ! SLUG=$(bashio::api.supervisor POST /backups/new/partial "${data}" .slug); then 189 | bashio::log.fatal "Error creating ${bak_type} partial backup!" 190 | touch "/tmp/backup/failed" 191 | fi 192 | else 193 | bashio::log.info "Creating ${bak_type} full backup: \"${BACKUP_NAME}\"" 194 | 195 | if ! SLUG=$(bashio::api.supervisor POST /backups/new/full "${data}" .slug); then 196 | bashio::log.fatal "Error creating ${bak_type} full backup!" 197 | touch "/tmp/backup/failed" 198 | fi 199 | 200 | fi 201 | if bashio::fs.file_exists "/tmp/backup/failed"; then 202 | rm -f "/tmp/backup/failed" 203 | return "${__BASHIO_EXIT_NOK}" 204 | else 205 | bashio::log.info "Backup created: ${SLUG}" 206 | return "${__BASHIO_EXIT_OK}" 207 | fi 208 | } 209 | 210 | function copy-backup-to-remote { 211 | if ! bashio::config.true "ssh_enabled"; then 212 | bashio::log.debug "SFTP/SCP disabled." 213 | return "${__BASHIO_EXIT_OK}" 214 | fi 215 | 216 | local -r remote_directory=$(bashio::config "ssh_remote_directory" "") 217 | local remote_name=$SLUG 218 | if bashio::config.true "backup_friendly_name"; then 219 | remote_name=$BACKUP_NAME 220 | fi 221 | 222 | bashio::log.info "Copying backup using SFTP/SCP." 223 | 224 | ( 225 | sshpass -p "${REMOTE_PASSWORD}" \ 226 | scp ${DEBUG_FLAG:-} -F "${SSH_HOME}/config" "/backup/${SLUG}.tar" remote:"${remote_directory}/${remote_name}.tar" || ( 227 | bashio::log.warning "SFTP transfer failed, falling back to SCP: $(sshpass_error $?)" 228 | sshpass -p "${REMOTE_PASSWORD}" \ 229 | scp ${DEBUG_FLAG:-} -O -F "${SSH_HOME}/config" "/backup/${SLUG}.tar" remote:"${remote_directory}/${remote_name}.tar" || ( 230 | bashio::log.error "Error copying backup ${SLUG}.tar to ${remote_directory} on ${REMOTE_HOST}: $(sshpass_error $?)" 231 | touch "/tmp/scp/failed" 232 | ) 233 | ) 234 | ) 235 | 236 | if bashio::fs.file_exists "/tmp/scp/failed"; then 237 | rm -f "/tmp/scp/failed" 238 | return "${__BASHIO_EXIT_NOK}" 239 | else 240 | return "${__BASHIO_EXIT_OK}" 241 | fi 242 | } 243 | 244 | 245 | function rsync-folders { 246 | if ! bashio::config.true "rsync_enabled"; then 247 | bashio::log.debug "Rsync disabled." 248 | return "${__BASHIO_EXIT_OK}" 249 | fi 250 | 251 | local -r folders="/addons /addon_configs /backup /config /homeassistant /media /share /ssl" # put directories without trailing slash 252 | local -r rsync_url="${REMOTE_USER}@${REMOTE_HOST}:$(bashio::config 'rsync_rootfolder')" 253 | local flags="-a -r ${DEBUG_FLAG:-}" 254 | 255 | bashio::log.info "Copying backup using rsync." 256 | 257 | local -r rsync_exclude=$(bashio::config "rsync_exclude" "") 258 | echo "${rsync_exclude}" > /tmp/rsync_exclude.txt 259 | if bashio::config.has_value "rsync_exclude"; then 260 | bashio::log.notice "Excluded rsync file patterns:\n${rsync_exclude}" 261 | fi 262 | 263 | bashio::log.debug "Syncing ${folders}" 264 | ( 265 | sshpass -p "${REMOTE_PASSWORD}" rsync ${flags} --port ${REMOTE_PORT} --exclude-from='/tmp/rsync_exclude.txt' ${folders} "${rsync_url}/" --delete || ( 266 | bashio::log.error "Error rsyncing folder(s) ${folders} to ${rsync_url}: $(sshpass_error $?)!" 267 | touch "/tmp/rsync/failed" 268 | ) 269 | ) 270 | if bashio::fs.file_exists "/tmp/rsync/failed"; then 271 | rm -f "/tmp/rsync/failed" 272 | return "${__BASHIO_EXIT_NOK}" 273 | else 274 | return "${__BASHIO_EXIT_OK}" 275 | fi 276 | } 277 | 278 | function rclone-backups { 279 | if ! bashio::config.true "rclone_enabled"; then 280 | bashio::log.debug "Rclone disabled." 281 | return "${__BASHIO_EXIT_OK}" 282 | fi 283 | 284 | bashio::config.require "rclone_remote_host" " rclone was enabled and a target for copying is necessary." 285 | local -r rclone_remote_host=$(bashio::config "rclone_remote_host" "") 286 | local remote_directory="" 287 | if bashio::config.exists 'rclone_remote_directory'; then 288 | local -r remote_directory=$(bashio::config "rclone_remote_directory") 289 | fi 290 | ( 291 | cd /backup/ 292 | mkdir -p ~/.config/rclone/ 293 | cp -a /config/rclone.conf ~/.config/rclone/rclone.conf 294 | ) || bashio::log.error "Failed to prepare rclone configuration!" 295 | 296 | if bashio::config.true "rclone_copy"; then 297 | local remote_name=$SLUG 298 | if bashio::config.true "backup_friendly_name"; then 299 | remote_name=$BACKUP_NAME 300 | fi 301 | bashio::log.info "Copying backup using rclone." 302 | ( 303 | rclone ${DEBUG_FLAG:-} copyto "/backup/${SLUG}.tar" "${rclone_remote_host}:${remote_directory}/${remote_name}.tar" || ( 304 | bashio::log.error "Error rclone ${SLUG}.tar to ${rclone_remote_host}:${remote_directory}/${remote_name}.tar!" 305 | touch "/tmp/rclone/failed" 306 | ) 307 | ) 308 | fi 309 | if bashio::config.true "rclone_sync"; then 310 | bashio::log.info "Syncing backups using rclone" 311 | ( 312 | rclone ${DEBUG_FLAG:-} sync "/backup" "${rclone_remote_host}:${remote_directory}" || ( 313 | bashio::log.error "Error syncing backups by rclone!" 314 | touch "/tmp/rclone/failed" 315 | ) 316 | ) 317 | fi 318 | if bashio::config.true "rclone_restore"; then 319 | local restore_name="restore-$(date +%F)" 320 | mkdir -p "${restore_name}" 321 | bashio::log.info "Restoring backups to ${restore_name} using rclone" 322 | ( 323 | rclone ${DEBUG_FLAG:-} copyto "${rclone_remote_host}:${remote_directory}" "/backup/${restore_name}/" || ( 324 | bashio::log.error "Error restoring backups from ${rclone_remote_host}:${remote_directory}!" 325 | touch "/tmp/rclone/failed" 326 | ) 327 | ) 328 | fi 329 | if bashio::fs.file_exists "/tmp/rclone/failed"; then 330 | rm -f "/tmp/rclone/failed" 331 | return "${__BASHIO_EXIT_NOK}" 332 | else 333 | return "${__BASHIO_EXIT_OK}" 334 | fi 335 | } 336 | 337 | function clone-to-remote { 338 | local ret="${__BASHIO_EXIT_OK}" 339 | 340 | copy-backup-to-remote || ret="${__BASHIO_EXIT_NOK}" 341 | rsync-folders || ret="${__BASHIO_EXIT_NOK}" 342 | rclone-backups || ret="${__BASHIO_EXIT_NOK}" 343 | 344 | return "${ret}" 345 | } 346 | 347 | function delete-local-backup { 348 | if bashio::config.equals "backup_keep_local" "all"; then 349 | bashio::log.debug "Keep all backups." 350 | return "${__BASHIO_EXIT_OK}" 351 | fi 352 | 353 | if ! bashio::api.supervisor POST /backups/reload; then 354 | bashio::log.warning "Failed to reload backups!" 355 | fi 356 | 357 | if bashio::config.is_empty "backup_keep_local" || bashio::config.equals "backup_keep_local" "null" || bashio::config.equals "keep_backup_local" "0"; then 358 | if bashio::var.has_value "$SLUG"; then 359 | bashio::log.notice "Deleting local backup: ${SLUG}" 360 | if ! bashio::api.supervisor DELETE /backups/${SLUG}; then 361 | bashio::log.error "Failed to delete backup: ${SLUG}" 362 | return "${__BASHIO_EXIT_NOK}" 363 | fi 364 | else 365 | bashio::log.debug "No current backup to delete." 366 | fi 367 | else 368 | local ret="${__BASHIO_EXIT_OK}" 369 | local -r backup_list=$(bashio::api.supervisor GET /backups) 370 | local -r last_date_to_keep=$(echo "${backup_list}" | jq ".backups[].date" | sort -r | \ 371 | head -n $(bashio::config "backup_keep_local") | tail -n 1 | xargs date -D "%Y-%m-%dT%T" +%s --date ) 372 | 373 | echo "${backup_list}" | jq -c ".backups[]" | while read -r backup; do 374 | if [[ $(echo "${backup}" | jq ".date" | xargs date -D "%Y-%m-%dT%T" +%s --date ) -lt ${last_date_to_keep} ]]; then 375 | local backup_slug=$(echo "${backup}" | jq -r .slug) 376 | bashio::log.notice "Deleting local backup: ${backup_slug}" 377 | if ! bashio::api.supervisor DELETE /backups/${backup_slug}; then 378 | bashio::log.error "Failed to delete backup: ${backup_slug}" 379 | ret="${__BASHIO_EXIT_NOK}" 380 | fi 381 | fi 382 | done 383 | return "${ret}" 384 | fi 385 | 386 | return "${__BASHIO_EXIT_OK}" 387 | } 388 | 389 | # general setup and backup 390 | set-debug-level 391 | migrate_config 392 | run_setup 393 | add-ssh-key 394 | create-local-backup || die "Local backup process failed! See log for details." 395 | clone-to-remote || die "Cloning backup(s) to remote host ${REMOTE_HOST} failed! See log for details." 396 | delete-local-backup || die "Removing local backup(s) failed! See log for details." 397 | 398 | bashio::log.info "Backup process done!" 399 | fire-event "ok" "Backup ${BACKUP_NAME} created." 400 | bashio::exit.ok --------------------------------------------------------------------------------