Automated nightly backups to S3

I want to backup my HA config every night and upload it to S3. I’m surprised this isn’t a supported feature out of the box, and bewildered by how difficult it was to setup.

An automation starts the backup, waits a minute, then calls a shell command which runs a bash script inside the SSH addon to copy the latest backup to /share. That file copy fires a folder_watcher event, which triggers an automation to upload this file to S3 using minio addon.

The SSH workaround is because automations run inside the homeassistant Docker container, which does not have access to /backup. The SSH addon has access to both places, so it can copy the tar file to /share.

There is no way to know the backup filename directly, that’s why I have to use the folder_watcher event.

To setup SSH access you need to generate a key pair inside the homeassistant container and store it somewhere outside the home directory so that it persists across software updates. Then add the public key to the SSH addon.

ssh-keygen -t ecdsa -f /config/shell_scripts/id_ecdsa

This is my shell script at /config/shell_scripts/

mkdir -p /share/backups
cp /backup/$(ls -t /backup/ | head -1) /share/backups/

In configuration.yaml:

  copy_backup_to_share: >
    ssh -o UserKnownHostsFile=/config/shell_scripts/known_hosts 
    [email protected] 
    -i /config/shell_scripts/id_ecdsa 

  - folder: '/share/backups'
      - '*.tar'

And automations.yaml:

- alias: Utility - nightly backup
  - platform: time
    at: 03:00:00
  - service: hassio.backup_partial
      homeassistant: true
  - delay:
      minutes: 1
  - service: shell_command.copy_backup_to_share
  mode: single

- alias: Utility - upload backups to S3
  description: 'run when tar is finished copying to /share/backups'
  - platform: event
    event_type: folder_watcher
      event_type: closed
  - service: notify.mobile_app_pro_llama
      title: System backup at {{ now().strftime('%H:%M:%S') }}
      message: '{{ }}'
  - service: minio.put
      bucket: my-bucket
      file_path: '{{ }}'
      key: backups/{{ }}
  mode: single

You can vote here to make this easier: