├── .gitignore
├── .travis.yml
├── CHANGELOG.md
├── LICENSE.md
├── README.md
├── build.sh
└── remote-backup
├── Dockerfile
├── config.json
└── run.sh
/.gitignore:
--------------------------------------------------------------------------------
1 | local_build.sh
2 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | sudo: required
2 | services:
3 | - docker
4 | script:
5 | - "$TRAVIS_BUILD_DIR/build.sh"
6 | env:
7 | global:
8 | secure: I1qaPNCHzZ0rntK1/aMMSCI50zhIdHO+V2UPwimUHmlQ8YdW1dUnuictFFoGEbp2S7owub9U4cwm5LHp8VjtrnDxoDEBuzb50RMTQ8vNWE4SAILawe9TWKfHQKqgCgONQsv9O4Bh8moqwDD+PrqnoGvqEsRjiS6Icx8jk1zCvy7WDzpgnZIHIzytAudRTNwVb/nIJWGMfG29ekxqLgX1YXQ6XsZfQm+JSt8a8dGLdYoYQZRbrriznanYkeMrBanwkKQgbmA1MirIwfcprvnXad1aX8l6/uKomvehc1PbUH6DXUqq8lzuu42gF+J9W3aL4YtbWYtzOItq2Hi0nnj26EvUyn1yIGzfCXv4j3eNA6cqplPKePZ9dYREx0bEiQP412T6w1WviRrhB4THSeCmn6HCkb/k2quTX4vLT1lQWOv4CRe0Qp5kHExbe2kGREJONiUsXU/6zKtT4S+iF9g5EalCaG8beFIwYllkbcSIsle/mfjHKTvwwQ8vI0cnRb7aKLI1pLgb6fQVIRN5ia+fwOvd/S/phy30wAzqtAjuxehbJ8dmnaS0Q21CRUmMAsRJ09x4KUTRMg0hBVib7JJ6jPQIvGgyILe4aJtBFZ5upxwPtk3eEc29RV/FbgJzPa7419boPflIpPY20a+VkfUpSjD4UcS/Xvd+6bjOecT9Fh4=
9 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Changelog
2 | All notable changes to this project will be documented in this file.
3 |
4 | The format is based on [Keep a Changelog][keep-a-changelog] this project adheres to [Semantic Versioning][semantic-versioning].
5 |
6 | ## [v0.3.0] (2018-03-12)
7 |
8 | [Full Changelog](https://github.com/mr-bjerre/hassio-remote-backup/compare/v0.2.1...v0.3.0)
9 |
10 | ### Added
11 |
12 | - New input `keep_local_backup` to control how many local snapshots there should be preserved.
13 |
14 | ## [v0.2.1] (2018-03-11)
15 |
16 | [Full Changelog](https://github.com/mr-bjerre/hassio-remote-backup/compare/v0.2.0...v0.2.1)
17 |
18 | ### Fixed
19 |
20 | - `config.json` in the [addons repository][addons-repo] was not aligned with the updates from v0.1.0 to v0.2.0. All backups created with v0.2.0 is password protected with the password _null_.
21 |
22 |
23 | ## [v0.2.0] (2018-03-07)
24 |
25 | [Full Changelog](https://github.com/mr-bjerre/hassio-remote-backup/compare/v0.1.0...v0.2.0)
26 |
27 | ### Added
28 |
29 | - Possibilty to contain the backup in a password protected zip file.
30 |
31 | ## [v0.1.0] (2018-03-06)
32 |
33 | ### Added
34 |
35 | - Initial release
36 |
37 | [keep-a-changelog]: http://keepachangelog.com/en/1.0.0/
38 | [semantic-versioning]: http://semver.org/spec/v2.0.0.html
39 | [addons-repo]: https://github.com/mr-bjerre/hassio-addons/blob/master/remote-backup/config.json
40 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018 Nicolai Bjerre Pedersen
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 | # Remote Backup
3 |
4 | [![GitHub Release][releases-shield]][releases]
5 | [![Build Status][travis-build-shield]][travis-build]
6 | [![GitHub license][license-shield]](LICENSE.md)
7 |
8 | > Automatically create Hass.io snapshots to remote server location using `SCP`.
9 |
10 |
11 |
12 | ## Table of Contents
13 |
14 | * [About](#about)
15 | * [Installation](#installation)
16 | * [Configuration](#configuration)
17 | * [Example](#example)
18 | * [Changelog & Releases](#changelog)
19 | * [Docker status](#docker)
20 |
21 | ## About
22 |
23 | When the add-on is started the following happens:
24 | 1. Snapshot are being created locally with a timestamp name, e.g.
25 | *Automatic backup 2018-03-04 04:00*.
26 | 1. The snapshot are copied to the specified remote location using `SCP`.
27 | 1. The local backup are removed locally again.
28 |
29 | _Note_ the filenames of the backup are given by their assigned slug.
30 |
31 | ## Installation
32 |
33 | 1. Add the add-ons repository to your Hass.io instance: `https://github.com/overkill32/hassio-addons`.
34 | 1. Install the Remote Backup add-on.
35 | 1. Configure the add-on with your SSH credentials and desired output directory
36 | (see configuration below).
37 |
38 | See my [repository of addons][hassio-addons] for more information.
39 |
40 | ## Configuration
41 |
42 | |Parameter|Required|Description|
43 | |---------|--------|-----------|
44 | |`ssh_host`|Yes|The hostname/url to the remote server.|
45 | |`ssh_port`|Yes|The port to use to `SCP` on to the server.|
46 | |`ssh_user`|Yes|Username to use for `SCP`.|
47 | |`ssh_key`|Yes|The ssh key to use. Not that it should *NOT* be password protected.|
48 | |`remote_directory`|Yes|The directory to put the backups on the remote server.|
49 | |`zip_password`|No|If set then the backup will be contained in a password protected zip|
50 | |`keep_local_backup`|No|Control how many local backups you want to preserve. Default (`""`) is to keep no local backups created from this addon. If `all` then all loocal backups will be preserved. A positive integer will determine how many of the latest backups will be preserved. Note this will delete other local backups created outside this addon.
51 |
52 | ## Example: daily backups at 4 AM
53 |
54 | Personally I've added the following automation to make a daily backup. It is password-protected and the last two weeks of snapshots are kept locally as well.
55 |
56 | _configuration.yaml_
57 | ```yaml
58 | automations:
59 | - alias: Daily Backup at 4 AM
60 | trigger:
61 | platform: time
62 | at: '4:00:00'
63 | action:
64 | - service: hassio.addon_start
65 | data:
66 | addon: ce20243c_remote_backup
67 | ```
68 |
69 | _Add-on configuration_:
70 | ```json
71 | {
72 | "ssh_host": "192.168.1.2",
73 | "ssh_port": 22,
74 | "ssh_user": "root",
75 | "ssh_key": [
76 | "-----BEGIN RSA PRIVATE KEY-----",
77 | "MIICXAIBAAKBgQDTkdD4ya/Qxz5xKaKojVIOVWjyeyEoEuAafAvYvppqmaBhyh4N",
78 | "5av4i87y8tdGusdq7V0Zj0+js4jEdvJRDrXJBrp1neLfsjkF6t1XLfrA51Ll9SXF",
79 | "...",
80 | "X+6r/gTvUEQv1ufAuUE5wKcq9FsbnTa3FOF0PdQDWl0=",
81 | "-----END RSA PRIVATE KEY-----"
82 | ],
83 | "remote_directory": "~/hassio-backups",
84 | "zip_password": "password_protect_it",
85 | "keep_local_backup": "14"
86 | }
87 | ```
88 |
89 | **Note**: _This is just an example, don't copy and past it! Create your own!_
90 |
91 | ## Changelog & Releases
92 |
93 | This repository keeps a [change log](CHANGELOG.md). The format of the log
94 | is based on [Keep a Changelog][keepchangelog].
95 |
96 | Releases are based on [Semantic Versioning][semver], and use the format
97 | of ``MAJOR.MINOR.PATCH``. In a nutshell, the version will be incremented
98 | based on the following:
99 |
100 | - ``MAJOR``: Incompatible or major changes.
101 | - ``MINOR``: Backwards-compatible new features and enhancements.
102 | - ``PATCH``: Backwards-compatible bugfixes and package updates.
103 |
104 |
105 | ## Docker status
106 |
107 | [![Docker Architecture][armhf-arch-shield]][armhf-dockerhub]
108 | [![Docker Version][armhf-version-shield]][armhf-microbadger]
109 | [![Docker Layers][armhf-layers-shield]][armhf-microbadger]
110 | [![Docker Pulls][armhf-pulls-shield]][armhf-dockerhub]
111 |
112 | [![Docker Architecture][aarch64-arch-shield]][aarch64-dockerhub]
113 | [![Docker Version][aarch64-version-shield]][aarch64-microbadger]
114 | [![Docker Layers][aarch64-layers-shield]][aarch64-microbadger]
115 | [![Docker Pulls][aarch64-pulls-shield]][aarch64-dockerhub]
116 |
117 | [![Docker Architecture][amd64-arch-shield]][amd64-dockerhub]
118 | [![Docker Version][amd64-version-shield]][amd64-microbadger]
119 | [![Docker Layers][amd64-layers-shield]][amd64-microbadger]
120 | [![Docker Pulls][amd64-pulls-shield]][amd64-dockerhub]
121 |
122 | [![Docker Architecture][i386-arch-shield]][i386-dockerhub]
123 | [![Docker Version][i386-version-shield]][i386-microbadger]
124 | [![Docker Layers][i386-layers-shield]][i386-microbadger]
125 | [![Docker Pulls][i386-pulls-shield]][i386-dockerhub]
126 |
127 |
128 | [aarch64-arch-shield]: https://img.shields.io/badge/architecture-aarch64-blue.svg
129 | [aarch64-dockerhub]: https://hub.docker.com/r/fixated/remote-backup-aarch64
130 | [aarch64-layers-shield]: https://images.microbadger.com/badges/image/fixated/remote-backup-aarch64.svg
131 | [aarch64-microbadger]: https://microbadger.com/images/fixated/remote-backup-aarch64
132 | [aarch64-pulls-shield]: https://img.shields.io/docker/pulls/fixated/remote-backup-aarch64.svg
133 | [aarch64-version-shield]: https://images.microbadger.com/badges/version/fixated/remote-backup-aarch64.svg
134 | [amd64-arch-shield]: https://img.shields.io/badge/architecture-amd64-blue.svg
135 | [amd64-dockerhub]: https://hub.docker.com/r/fixated/remote-backup-amd64
136 | [amd64-layers-shield]: https://images.microbadger.com/badges/image/fixated/remote-backup-amd64.svg
137 | [amd64-microbadger]: https://microbadger.com/images/fixated/remote-backup-amd64
138 | [amd64-pulls-shield]: https://img.shields.io/docker/pulls/fixated/remote-backup-amd64.svg
139 | [amd64-version-shield]: https://images.microbadger.com/badges/version/fixated/remote-backup-amd64.svg
140 | [armhf-arch-shield]: https://img.shields.io/badge/architecture-armhf-blue.svg
141 | [armhf-dockerhub]: https://hub.docker.com/r/fixated/remote-backup-armhf
142 | [armhf-layers-shield]: https://images.microbadger.com/badges/image/fixated/remote-backup-armhf.svg
143 | [armhf-microbadger]: https://microbadger.com/images/fixated/remote-backup-armhf
144 | [armhf-pulls-shield]: https://img.shields.io/docker/pulls/fixated/remote-backup-armhf.svg
145 | [armhf-version-shield]: https://images.microbadger.com/badges/version/fixated/remote-backup-armhf.svg
146 | [i386-arch-shield]: https://img.shields.io/badge/architecture-i386-blue.svg
147 | [i386-dockerhub]: https://hub.docker.com/r/fixated/remote-backup-i386
148 | [i386-layers-shield]: https://images.microbadger.com/badges/image/fixated/remote-backup-i386.svg
149 | [i386-microbadger]: https://microbadger.com/images/fixated/remote-backup-i386
150 | [i386-pulls-shield]: https://img.shields.io/docker/pulls/fixated/remote-backup-i386.svg
151 | [i386-version-shield]: https://images.microbadger.com/badges/version/fixated/remote-backup-i386.svg
152 |
153 | [license-shield]: https://img.shields.io/github/license/overkill32/hassio-remote-backup.svg
154 | [releases]: https://github.com/overkill32/hassio-remote-backup/releases
155 | [releases-shield]: https://img.shields.io/github/release/overkill32/hassio-remote-backup.svg
156 | [travis-build]: https://travis-ci.org/overkill32/hassio-remote-backup
157 | [travis-build-shield]: https://travis-ci.org/overkill32/hassio-remote-backup.svg?branch=master
158 |
159 | [keepchangelog]: http://keepachangelog.com/en/1.0.0/
160 | [semver]: http://semver.org/spec/v2.0.0.html
161 |
162 | [hassio-addons]: https://github.com/overkill32/hassio-addons
163 |
--------------------------------------------------------------------------------
/build.sh:
--------------------------------------------------------------------------------
1 | set -ev
2 | docker login -u "$DOCKER_USERNAME" -p "$DOCKER_PASSWORD"
3 |
4 | if [ -z ${TRAVIS_TAG} ]; then
5 | echo "Untagged build found. Building to test."
6 | docker run -it --rm --privileged --name "${ADDON_NAME}" \
7 | -v ~/.docker:/root/.docker \
8 | -v "$(pwd)":/docker \
9 | hassioaddons/build-env:latest \
10 | --target "${ADDON_NAME}" \
11 | --git \
12 | --all \
13 | --from "homeassistant/{arch}-base" \
14 | --author "Nicolai Bjerre Pedersen " \
15 | --doc-url "${GITHUB_URL}" \
16 | --image "fixated/${ADDON_NAME}-{arch}"
17 | else
18 | echo "New git tagged build found. Building to distribute."
19 | docker run -it --rm --privileged --name "${ADDON_NAME}" \
20 | -v ~/.docker:/root/.docker \
21 | -v "$(pwd)":/docker \
22 | hassioaddons/build-env:latest \
23 | --target "${ADDON_NAME}" \
24 | --git \
25 | --all \
26 | --push \
27 | --from "homeassistant/{arch}-base" \
28 | --author "Nicolai Bjerre Pedersen " \
29 | --doc-url "${GITHUB_URL}" \
30 | --image "fixated/${ADDON_NAME}-{arch}"
31 | fi
32 |
--------------------------------------------------------------------------------
/remote-backup/Dockerfile:
--------------------------------------------------------------------------------
1 | ARG BUILD_FROM
2 | FROM $BUILD_FROM
3 |
4 | # Add env
5 | ENV LANG C.UTF-8
6 |
7 | # Setup base
8 | RUN apk add --no-cache jq openssh-client zip
9 |
10 | # Hass.io CLI
11 | ARG BUILD_ARCH
12 | ARG CLI_VERSION
13 | RUN apk add --no-cache curl \
14 | && curl -Lso /usr/bin/hassio https://github.com/home-assistant/hassio-cli/releases/download/1.2.1/hassio_${BUILD_ARCH} \
15 | && chmod a+x /usr/bin/hassio
16 |
17 | # Copy data
18 | COPY run.sh /
19 | RUN chmod a+x /run.sh
20 |
21 | CMD [ "/run.sh" ]
22 |
23 | # Build arugments
24 | ARG BUILD_DATE
25 | ARG BUILD_REF
26 | ARG BUILD_VERSION
27 |
28 | # Labels
29 | LABEL \
30 | io.hass.name="Remote Backup" \
31 | io.hass.description="Automatically create Hass.io snapshots to remote server location using `SCP`." \
32 | io.hass.arch="${BUILD_ARCH}" \
33 | io.hass.type="addon" \
34 | io.hass.version=${BUILD_VERSION} \
35 | maintainer="Nicolai Bjerre Pedersen " \
36 | org.label-schema.description="Automatically create Hass.io snapshots to remote server location using `SCP`." \
37 | org.label-schema.build-date=${BUILD_DATE} \
38 | org.label-schema.name="Remote Backup" \
39 | org.label-schema.schema-version="1.0" \
40 | org.label-schema.usage="https://github.com/overkill32/hassio-remote-backup/tree/master/README.md" \
41 | org.label-schema.vcs-ref=${BUILD_REF} \
42 | org.label-schema.vcs-url="https://github.com/overkill32/hassio-remote-backup/" \
43 | org.label-schema.vendor="Hass.io add-ons by Nicolai"
44 |
--------------------------------------------------------------------------------
/remote-backup/config.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Remote Backup",
3 | "version": "dev",
4 | "slug": "remote_backup",
5 | "description": "Exploit snapshots and SCP to create remote backups to specified server",
6 | "url": "https://github.com/overkill32/hassio-remote-backup",
7 | "startup": "once",
8 | "boot": "manual",
9 | "hassio_api": true,
10 | "hassio_role": "backup",
11 | "map": ["backup:rw"],
12 | "arch": ["armhf", "armv7", "aarch64", "amd64", "i386"],
13 | "options": {
14 | "ssh_host": "",
15 | "ssh_port": 22,
16 | "ssh_user": "",
17 | "ssh_key": [],
18 | "remote_directory": "",
19 | "zip_password": "",
20 | "keep_local_backup": ""
21 | },
22 | "schema": {
23 | "ssh_host": "str",
24 | "ssh_port": "int",
25 | "ssh_user": "str",
26 | "ssh_key": ["str"],
27 | "remote_directory": "str",
28 | "zip_password": "str",
29 | "keep_local_backup": "match(^(all|[+]?\\d*)$)"
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/remote-backup/run.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | set -e
3 |
4 | CONFIG_PATH=/data/options.json
5 |
6 | # parse inputs from options
7 | SSH_HOST=$(jq --raw-output ".ssh_host" $CONFIG_PATH)
8 | SSH_PORT=$(jq --raw-output ".ssh_port" $CONFIG_PATH)
9 | SSH_USER=$(jq --raw-output ".ssh_user" $CONFIG_PATH)
10 | SSH_KEY=$(jq --raw-output ".ssh_key[]" $CONFIG_PATH)
11 | REMOTE_DIRECTORY=$(jq --raw-output ".remote_directory" $CONFIG_PATH)
12 | ZIP_PASSWORD=$(jq --raw-output '.zip_password' $CONFIG_PATH)
13 | KEEP_LOCAL_BACKUP=$(jq --raw-output '.keep_local_backup' $CONFIG_PATH)
14 |
15 | # create variables
16 | SSH_ID="${HOME}/.ssh/id"
17 |
18 | function add-ssh-key {
19 | echo "Adding SSH key"
20 | mkdir -p ~/.ssh
21 | (
22 | echo "Host remote"
23 | echo " IdentityFile ${HOME}/.ssh/id"
24 | echo " HostName ${SSH_HOST}"
25 | echo " User ${SSH_USER}"
26 | echo " Port ${SSH_PORT}"
27 | echo " StrictHostKeyChecking no"
28 | ) > "${HOME}/.ssh/config"
29 |
30 | while read -r line; do
31 | echo "$line" >> ${HOME}/.ssh/id
32 | done <<< "$SSH_KEY"
33 |
34 | chmod 600 "${HOME}/.ssh/config"
35 | chmod 600 "${HOME}/.ssh/id"
36 | }
37 |
38 | function copy-backup-to-remote {
39 |
40 | cd /backup/
41 | if [[ -z $ZIP_PASSWORD ]]; then
42 | echo "Copying ${slug}.tar to ${REMOTE_DIRECTORY} on ${SSH_HOST} using SCP"
43 | scp -F "${HOME}/.ssh/config" "${slug}.tar" remote:"${REMOTE_DIRECTORY}"
44 | else
45 | echo "Copying password-protected ${slug}.zip to ${REMOTE_DIRECTORY} on ${SSH_HOST} using SCP"
46 | zip -P "$ZIP_PASSWORD" "${slug}.zip" "${slug}".tar
47 | scp -F "${HOME}/.ssh/config" "${slug}.zip" remote:"${REMOTE_DIRECTORY}" && rm "${slug}.zip"
48 | fi
49 |
50 | }
51 |
52 | function delete-local-backup {
53 |
54 | hassio snapshots reload
55 |
56 | if [[ ${KEEP_LOCAL_BACKUP} == "all" ]]; then
57 | :
58 | elif [[ -z ${KEEP_LOCAL_BACKUP} ]]; then
59 | echo "Deleting local backup: ${slug}"
60 | hassio snapshots remove -name "${slug}"
61 | else
62 |
63 | last_date_to_keep=$(hassio snapshots list | jq .data.snapshots[].date | sort -r | \
64 | head -n "${KEEP_LOCAL_BACKUP}" | tail -n 1 | xargs date -D "%Y-%m-%dT%T" +%s --date )
65 |
66 | hassio snapshots list | jq -c .data.snapshots[] | while read backup; do
67 | if [[ $(echo ${backup} | jq .date | xargs date -D "%Y-%m-%dT%T" +%s --date ) -lt ${last_date_to_keep} ]]; then
68 | echo "Deleting local backup: $(echo ${backup} | jq -r .slug)"
69 | hassio snapshots remove -name "$(echo ${backup} | jq -r .slug)"
70 | fi
71 | done
72 |
73 | fi
74 | }
75 |
76 | function create-local-backup {
77 | name="Automated backup $(date +'%Y-%m-%d %H:%M')"
78 | echo "Creating local backup: \"${name}\""
79 | slug=$(hassio snapshots new --options name="${name}" | jq --raw-output '.data.slug')
80 | echo "Backup created: ${slug}"
81 | }
82 |
83 |
84 | add-ssh-key
85 | create-local-backup
86 | copy-backup-to-remote
87 | delete-local-backup
88 |
89 | echo "Backup process done!"
90 | exit 0
91 |
--------------------------------------------------------------------------------