From 186d0619def1e6d4539e17ad5cde0772aad563f0 Mon Sep 17 00:00:00 2001 From: Nicolai Bjerre Pedersen Date: Tue, 6 Mar 2018 19:23:20 +0100 Subject: [PATCH] Initial release. --- .gitignore | 1 + .travis.yml | 8 +++ CHANGELOG.md | 7 ++ LICENSE.md | 21 ++++++ README.md | 141 ++++++++++++++++++++++++++++++++++++++ distribute.sh | 13 ++++ remote-backup/Dockerfile | 43 ++++++++++++ remote-backup/config.json | 26 +++++++ remote-backup/run.sh | 60 ++++++++++++++++ 9 files changed, 320 insertions(+) create mode 100644 .gitignore create mode 100644 .travis.yml create mode 100644 CHANGELOG.md create mode 100644 LICENSE.md create mode 100644 README.md create mode 100755 distribute.sh create mode 100644 remote-backup/Dockerfile create mode 100644 remote-backup/config.json create mode 100755 remote-backup/run.sh diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..8c661a9 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +local_build.sh diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..b867663 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,8 @@ +sudo: required +services: +- docker +script: +- "$TRAVIS_BUILD_DIR/distribute.sh" +env: + global: + secure: I1qaPNCHzZ0rntK1/aMMSCI50zhIdHO+V2UPwimUHmlQ8YdW1dUnuictFFoGEbp2S7owub9U4cwm5LHp8VjtrnDxoDEBuzb50RMTQ8vNWE4SAILawe9TWKfHQKqgCgONQsv9O4Bh8moqwDD+PrqnoGvqEsRjiS6Icx8jk1zCvy7WDzpgnZIHIzytAudRTNwVb/nIJWGMfG29ekxqLgX1YXQ6XsZfQm+JSt8a8dGLdYoYQZRbrriznanYkeMrBanwkKQgbmA1MirIwfcprvnXad1aX8l6/uKomvehc1PbUH6DXUqq8lzuu42gF+J9W3aL4YtbWYtzOItq2Hi0nnj26EvUyn1yIGzfCXv4j3eNA6cqplPKePZ9dYREx0bEiQP412T6w1WviRrhB4THSeCmn6HCkb/k2quTX4vLT1lQWOv4CRe0Qp5kHExbe2kGREJONiUsXU/6zKtT4S+iF9g5EalCaG8beFIwYllkbcSIsle/mfjHKTvwwQ8vI0cnRb7aKLI1pLgb6fQVIRN5ia+fwOvd/S/phy30wAzqtAjuxehbJ8dmnaS0Q21CRUmMAsRJ09x4KUTRMg0hBVib7JJ6jPQIvGgyILe4aJtBFZ5upxwPtk3eEc29RV/FbgJzPa7419boPflIpPY20a+VkfUpSjD4UcS/Xvd+6bjOecT9Fh4= diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..69ef2ec --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,7 @@ +# Changelog +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) +and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). + +## [1.0.0] - 2018-03-05 \ No newline at end of file diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000..463f43b --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2018 Nicolai Bjerre Pedersen + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..fa5843f --- /dev/null +++ b/README.md @@ -0,0 +1,141 @@ + +# Remote Backup + +[![GitHub Release][releases-shield]][releases] +[![Build Status][travis-build-shield]][travis-build] +[![GitHub license][license-shield]](LICENSE.md) + +> Automatically create Hass.io snapshots to remote server location using `SCP`. + +
+ +## Table of Contents + +* [About](#about) +* [Installation](#installation) +* [Configuration](#configuration) +* [Example](#example) +* [Docker status](#docker) + +## About + +When the add-on is started the following happens: +1. Snapshot are being created locally with a timestamp name, e.g. +*Automatic backup 2018-03-04 04:00*. +1. The snapshot are copied to the specified remote location using `SCP`. +1. The local backup are removed locally again. + +_Note_ the filenames of the backup are given by their assigned slug. + +## Installation + +1. Add the add-ons repository to your Hass.io instance: `https://github.com/mr-bjerre/hassio-addons`. +1. Install the Remote Backup add-on. +1. Configure the add-on with your SSH credentials and desired output directory +(see configuration below). + +See my [repository of addons][hassio-addons] for more information. + +## Configuration + +|Parameter|Required|Description| +|---------|--------|-----------| +|`ssh_host`|Yes|The hostname/url to the remote server.| +|`ssh_port`|Yes|The port to use to `SCP` on to the server.| +|`ssh_user`|Yes|Username to use for `SCP`.| +|`ssh_key`|Yes|The ssh key to use. Not that it should *NOT* be password protected.| +|`remote_directory`|Yes|The directory to put the backups on the remote server.| + +## Example: daily backups at 4 AM + +Personally I've added the following automation to make a daily backup: + +_configuration.yaml_ +```yaml +automations: + - alias: Daily Backup at 4 AM + trigger: + platform: time + at: '4:00:00' + action: + - service: hassio.addon_start + data: + addon: ce20243c_remote_backup +``` + +_Add-on configuration_: +```json +{ + "ssh_host": "192.168.1.2", + "ssh_port": 22, + "ssh_user": "root", + "ssh_key": [ +"-----BEGIN RSA PRIVATE KEY-----", +"MIICXAIBAAKBgQDTkdD4ya/Qxz5xKaKojVIOVWjyeyEoEuAafAvYvppqmaBhyh4N", +"5av4i87y8tdGusdq7V0Zj0+js4jEdvJRDrXJBrp1neLfsjkF6t1XLfrA51Ll9SXF", +"...", +"X+6r/gTvUEQv1ufAuUE5wKcq9FsbnTa3FOF0PdQDWl0=", +"-----END RSA PRIVATE KEY-----" + ], + "remote_directory": "~/hassio-backups" +} +``` + +**Note**: _This is just an example, don't copy and past it! Create your own!_ + + +## Docker status + +[![Docker Architecture][armhf-arch-shield]][armhf-dockerhub] +[![Docker Version][armhf-version-shield]][armhf-microbadger] +[![Docker Layers][armhf-layers-shield]][armhf-microbadger] +[![Docker Pulls][armhf-pulls-shield]][armhf-dockerhub] + +[![Docker Architecture][aarch64-arch-shield]][aarch64-dockerhub] +[![Docker Version][aarch64-version-shield]][aarch64-microbadger] +[![Docker Layers][aarch64-layers-shield]][aarch64-microbadger] +[![Docker Pulls][aarch64-pulls-shield]][aarch64-dockerhub] + +[![Docker Architecture][amd64-arch-shield]][amd64-dockerhub] +[![Docker Version][amd64-version-shield]][amd64-microbadger] +[![Docker Layers][amd64-layers-shield]][amd64-microbadger] +[![Docker Pulls][amd64-pulls-shield]][amd64-dockerhub] + +[![Docker Architecture][i386-arch-shield]][i386-dockerhub] +[![Docker Version][i386-version-shield]][i386-microbadger] +[![Docker Layers][i386-layers-shield]][i386-microbadger] +[![Docker Pulls][i386-pulls-shield]][i386-dockerhub] + + +[aarch64-arch-shield]: https://img.shields.io/badge/architecture-aarch64-blue.svg +[aarch64-dockerhub]: https://hub.docker.com/r/fixated/remote-backup-aarch64 +[aarch64-layers-shield]: https://images.microbadger.com/badges/image/fixated/remote-backup-aarch64.svg +[aarch64-microbadger]: https://microbadger.com/images/fixated/remote-backup-aarch64 +[aarch64-pulls-shield]: https://img.shields.io/docker/pulls/fixated/remote-backup-aarch64.svg +[aarch64-version-shield]: https://images.microbadger.com/badges/version/fixated/remote-backup-aarch64.svg +[amd64-arch-shield]: https://img.shields.io/badge/architecture-amd64-blue.svg +[amd64-dockerhub]: https://hub.docker.com/r/fixated/remote-backup-amd64 +[amd64-layers-shield]: https://images.microbadger.com/badges/image/fixated/remote-backup-amd64.svg +[amd64-microbadger]: https://microbadger.com/images/fixated/remote-backup-amd64 +[amd64-pulls-shield]: https://img.shields.io/docker/pulls/fixated/remote-backup-amd64.svg +[amd64-version-shield]: https://images.microbadger.com/badges/version/fixated/remote-backup-amd64.svg +[armhf-arch-shield]: https://img.shields.io/badge/architecture-armhf-blue.svg +[armhf-dockerhub]: https://hub.docker.com/r/fixated/remote-backup-armhf +[armhf-layers-shield]: https://images.microbadger.com/badges/image/fixated/remote-backup-armhf.svg +[armhf-microbadger]: https://microbadger.com/images/fixated/remote-backup-armhf +[armhf-pulls-shield]: https://img.shields.io/docker/pulls/fixated/remote-backup-armhf.svg +[armhf-version-shield]: https://images.microbadger.com/badges/version/fixated/remote-backup-armhf.svg +[i386-arch-shield]: https://img.shields.io/badge/architecture-i386-blue.svg +[i386-dockerhub]: https://hub.docker.com/r/fixated/remote-backup-i386 +[i386-layers-shield]: https://images.microbadger.com/badges/image/fixated/remote-backup-i386.svg +[i386-microbadger]: https://microbadger.com/images/fixated/remote-backup-i386 +[i386-pulls-shield]: https://img.shields.io/docker/pulls/fixated/remote-backup-i386.svg +[i386-version-shield]: https://images.microbadger.com/badges/version/fixated/remote-backup-i386.svg + +[license-shield]: https://img.shields.io/github/license/mr-bjerre/hassio-remote-backup.svg +[releases]: https://github.com/mr-bjerre/hassio-remote-backup/releases +[releases-shield]: https://img.shields.io/github/release/mr-bjerre/hassio-remote-backup.svg +[travis-build]: https://travis-ci.org/mr-bjerre/hassio-remote-backup +[travis-build-shield]: https://travis-ci.org/mr-bjerre/hassio-remote-backup.svg?branch=master + +[hassio-addons]: https://github.com/mr-bjerre/hassio-addons diff --git a/distribute.sh b/distribute.sh new file mode 100755 index 0000000..c6eb8d6 --- /dev/null +++ b/distribute.sh @@ -0,0 +1,13 @@ +set -ev +docker login -u "$DOCKER_USERNAME" -p "$DOCKER_PASSWORD" +docker run -it --rm --privileged --name "${ADDON_NAME}" \ + -v ~/.docker:/root/.docker \ + -v "$(pwd)":/docker \ + hassioaddons/build-env:latest \ + --target "${ADDON_NAME}" \ + --git \ + --all \ + --push \ + --from "homeassistant/{arch}-base" \ + --author "Nicolai Bjerre Pedersen " \ + --doc-url "${GITHUB_URL}" diff --git a/remote-backup/Dockerfile b/remote-backup/Dockerfile new file mode 100644 index 0000000..9a1ff96 --- /dev/null +++ b/remote-backup/Dockerfile @@ -0,0 +1,43 @@ +ARG BUILD_FROM +FROM $BUILD_FROM + +# Add env +ENV LANG C.UTF-8 + +# Setup base +RUN apk add --no-cache jq openssh-client + +# Hass.io CLI +ARG BUILD_ARCH +ARG CLI_VERSION +RUN apk add --no-cache curl \ + && curl -Lso /usr/bin/hassio https://github.com/home-assistant/hassio-cli/releases/download/1.2.1/hassio_${BUILD_ARCH} \ + && chmod a+x /usr/bin/hassio + +# Copy data +COPY run.sh / +RUN chmod a+x /run.sh + +CMD [ "/run.sh" ] + +# Build arugments +ARG BUILD_DATE +ARG BUILD_REF +ARG BUILD_VERSION + +# Labels +LABEL \ + io.hass.name="Remote Backup" \ + io.hass.description="Automatically create Hass.io snapshots to remote server location using `SCP`." \ + io.hass.arch="${BUILD_ARCH}" \ + io.hass.type="addon" \ + io.hass.version=${BUILD_VERSION} \ + maintainer="Nicolai Bjerre Pedersen " \ + org.label-schema.description="Automatically create Hass.io snapshots to remote server location using `SCP`." \ + org.label-schema.build-date=${BUILD_DATE} \ + org.label-schema.name="Remote Backup" \ + org.label-schema.schema-version="1.0" \ + org.label-schema.usage="https://github.com/mr-bjerre/hassio-remote-backup/tree/master/README.md" \ + org.label-schema.vcs-ref=${BUILD_REF} \ + org.label-schema.vcs-url="https://github.com/mr-bjerre/hassio-remote-backup/" \ + org.label-schema.vendor="Hass.io add-ons by Nicolai" diff --git a/remote-backup/config.json b/remote-backup/config.json new file mode 100644 index 0000000..47b711a --- /dev/null +++ b/remote-backup/config.json @@ -0,0 +1,26 @@ +{ + "name": "Remote Backup", + "version": "0.1.0", + "slug": "remote_backup", + "description": "Exploit snapshots and SCP to create remote backups to specified server", + "url": "https://github.com/mr-bjerre/hassio-remote-backup", + "startup": "once", + "boot": "manual", + "hassio_api": true, + "map": ["backup:rw"], + "image": "fixated/remote-backup-{arch}", + "options": { + "ssh_host": "", + "ssh_port": 22, + "ssh_user": "", + "ssh_key": [], + "remote_directory": "" + }, + "schema": { + "ssh_host": "str", + "ssh_port": "int", + "ssh_user": "str", + "ssh_key": ["str"], + "remote_directory": "str" + } +} diff --git a/remote-backup/run.sh b/remote-backup/run.sh new file mode 100755 index 0000000..baf7f16 --- /dev/null +++ b/remote-backup/run.sh @@ -0,0 +1,60 @@ +#!/bin/bash + +CONFIG_PATH=/data/options.json + +# parse inputs from options +SSH_HOST=$(jq --raw-output ".ssh_host" $CONFIG_PATH) +SSH_PORT=$(jq --raw-output ".ssh_port" $CONFIG_PATH) +SSH_USER=$(jq --raw-output ".ssh_user" $CONFIG_PATH) +SSH_KEY=$(jq --raw-output ".ssh_key[]" $CONFIG_PATH) +REMOTE_DIRECTORY=$(jq --raw-output ".remote_directory" $CONFIG_PATH) +REPEAT=$(jq --raw-output '.repeat' $CONFIG_PATH) + +# create variables +SSH_ID="${HOME}/.ssh/id" + +function add-ssh-key { + echo "Adding SSH key" + mkdir -p ~/.ssh + ( + echo "Host remote" + echo " IdentityFile ${HOME}/.ssh/id" + echo " HostName ${SSH_HOST}" + echo " User ${SSH_USER}" + echo " Port ${SSH_PORT}" + echo " StrictHostKeyChecking no" + ) > "${HOME}/.ssh/config" + + while read -r line; do + echo "$line" >> ${HOME}/.ssh/id + done <<< "$SSH_KEY" + + chmod 600 "${HOME}/.ssh/config" + chmod 600 "${HOME}/.ssh/id" +} + +function copy-backup-to-remote { + echo "Copying ${slug} to ${REMOTE_DIRECTORY} on ${SSH_HOST} using SCP" + scp -F "${HOME}/.ssh/config" "/backup/${slug}.tar" remote:"${REMOTE_DIRECTORY}" +} + +function delete-local-backup { + hassio snapshots remove -name "${slug}" + echo "Deleted local backup: ${slug}" +} + +function create-local-backup { + name="Automated backup $(date +'%Y-%m-%d %H:%M')" + echo "Creating local backup: \"${name}\"" + slug=$(hassio snapshots new --options name="${name}" | jq --raw-output '.data.slug') + echo "Backup created: ${slug}" +} + + +add-ssh-key +create-local-backup +copy-backup-to-remote +delete-local-backup + +echo "Backup process done!" +exit 0