How to restore a snapshot

This guide has been updated to use the much easier method introduced in version 0.116, if you are running an older version of Home Assistant than this you can check the edit history of this post for the old instructions.

Note: this guide assumes you have copied the snapshot off your home assistant server before the problem occurred. So snapshot regularly and copy the snapshot eleswhere regularly. There are addons to do this automatically for you, here are a few:

To a NAS: Samba Backup: Create and store snapshots on a Samba share

To Goggle Drive: Add-on: Home Assistant Google Drive Backup

To DropBox: Hass.io Add-on: Upload hassio snapshots to Dropbox

To NextCloud or S3: [New Addon] Snap-Shipper - Webdav and S3 backups (and probably other ways to later on)

If you have not done this, all is not lost. You may be able to recover the snapshot but it is beyond the scope of this guide.

1) Fix the issue that caused the crash.

There is little point restoring if it is just going to happen again.

For hardware this may be easy, e.g. replace a pi power supply or SD card.

For configuration issues, if you know what caused the crash you can make a copy of your snapshot and extract the relevant file using winrar, 7zip or some other compression software that allows decompressing .tar files. Edit the file and return it to the correct place in the snapshot. If you’ve done something incorrectly you still have the original snapshot to try again. Never edit this, only edit a copy. Alternatively, restore a snapshot that is older than when the issue was introduced.

Should you have protected your snapshot with a password, you may notice that you can’t extract individual files from it. With a little python script (kudos to @Taapie for writing the script -> here) you can decrypt your snapshot and then extract individual files as explained above.

This requires Python 3 and the cryptography package.

Create a file called decrypt.py in the same directory as the .tar file you want to decrypt with the following content:

Click to expand!
#!/usr/bin/env python3

import sys
import getopt
import hashlib
import tarfile
import glob
import os
import shutil

from pathlib import Path

from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives.ciphers import (
  Cipher,
  algorithms,
  modes,
)

def _password_to_key(password):
  password = password.encode()
  for _ in range(100):
      password = hashlib.sha256(password).digest()
  return password[:16]

def _generate_iv(key, salt):
  temp_iv = key + salt
  for _ in range(100):
      temp_iv = hashlib.sha256(temp_iv).digest()
  return temp_iv[:16]

class SecureTarFile:
  def __init__(self, filename, password):
      self._file = None
      self._name = Path(filename)

      self._tar = None
      self._tar_mode = "r|gz"

      self._aes = None
      self._key = _password_to_key(password)

      self._decrypt = None

  def __enter__(self):
      self._file = self._name.open("rb")

      cbc_rand = self._file.read(16)

      self._aes = Cipher(
          algorithms.AES(self._key),
          modes.CBC(_generate_iv(self._key, cbc_rand)),
          backend=default_backend(),
      )

      self._decrypt = self._aes.decryptor()

      self._tar = tarfile.open(fileobj=self, mode=self._tar_mode)
      return self._tar

  def __exit__(self, exc_type, exc_value, traceback):
      if self._tar:
          self._tar.close()
      if self._file:
          self._file.close()

  def read(self, size = 0):
      return self._decrypt.update(self._file.read(size))

  @property
  def path(self):
      return self._name

  @property
  def size(self):
      if not self._name.is_file():
          return 0
      return round(self._name.stat().st_size / 1_048_576, 2)  # calc mbyte

def _extract_tar(filename):
  _dirname = '.'.join(filename.split('.')[:-1])

  try:
      shutil.rmtree('_dirname')
  except FileNotFoundError:
      pass

  print(f'Extracting {filename}...')
  _tar  = tarfile.open(name=filename, mode="r")
  _tar.extractall(path=_dirname)

  return _dirname

def _extract_secure_tar(filename, password):
  _dirname = '.'.join(filename.split('.')[:-2])
  print(f'Extracting secure tar {filename.split("/")[-1]}...')
  try:
      with SecureTarFile(filename, password) as _tar:
          _tar.extractall(path=_dirname)
  except tarfile.ReadError:
      print("Unable to extract SecureTar - maybe your password is wrong or the tar is not password encrypted?")
      sys.exit(5)

  return _dirname

def print_usage():
  print(f'{sys.argv[0]} -i <inputfile> -p <password>')

def main():
  _inputfile = None
  _password=None

  try:
      opts, args = getopt.getopt(sys.argv[1:],"hi:p:")
  except getopt.GetoptError:
      print_usage()
      sys.exit(2)
  for opt, arg in opts:
      if opt == '-h':
          print_usage()
          sys.exit()
      elif opt in ("-i"):
          _inputfile = arg
      elif opt in ("-p"):
          _password = arg

  if not _inputfile:
      print ("Missing inputfile")
      print_usage()
      sys.exit(3)

  if not _password:
      print ("Missing password")
      print_usage()
      sys.exit(4)

  _dirname = _extract_tar(_inputfile)
  for _secure_tar in glob.glob(f'{_dirname}/*.tar.gz'):
      _extract_secure_tar(_secure_tar, _password)
      os.remove(_secure_tar)

  print("Done")

if __name__ == "__main__":
  main()

Then execute the following command:

python3 decrypt.py -i name-of-your-file.tar -p yourpassword

You should now have a decrypted archive that you can extract as usual.

2) Flash a fresh copy of home assistant to an SD card, or install using your preferred method

If it has been a while since you have done this the install instructions are here: https://www.home-assistant.io/hassio/installation/ alternative installation instructions are available in this community guide category.

3) Boot up home assistant, browse for your snapshot from the login page and restore

After a bit of time and a restart you should now have home assittant looking exactly like it did when the snapshot was taken.

Common issues:

The home assistant database or MariaDB database sometimes does not restore correctly. You can chose to repair this (search the forum for instructions) or delete it and start fresh. Home Assistant now has the ability to archive the database and create a new one on start up for the default database if corruption is detected but it does not always work as intended.

If you password protect your snapshot there is no easy way to recover individual files from it without first restoring the whole thing.

8 Likes

Great instructions @tom_l !

Can I just add another option for backups which I use which is the backup to DropBox:

A great addition. Go for it.

Edit: I had some other minor changes to make so I have also added the DropBox backup link.

1 Like

Since installation of 0.116.0 I got a lot of issues (mainly recorder) in the logs, decided to wait for an update, solutions seemed to be work in progress…
However after restarting my home-assistant install it was not reachable anymore. I could not get it to work again, so started with fresh install using whiskerz proxmox instruction, that worked fine.

Now let’s use the upload snapshot function… that results in:


(I get that message in Chrome, the new Edge does not report any issue).

:frowning:

How to proceed…?? I’ve tried restoring 116.0 and 115.x snapshots

edit: using 549mb sized snapshots

Next step I tried, completing the install of HA and Samba, copy back the backup. Then It complained:
[supervisor.snapshots.snapshot] Can't read snapshot tarfile /data/backup/e0ddd720.tar: "filename './snapshot.json' not found". It did execute the restore succesfully though.

12-10: I’ve checked the tar file, there is a snapshot.json in it and readable.

1 Like

For anyone else with this issue it should be fixed soon:

2 Likes

Can you post links to either/both of these procedures?
The best result to my searches is this thread…lol.

I have an sql error (searched that as well) that keeps reoccurring in my logs ever since I enabled the notification sensor in the android app. I don’t use MariaDB for historical purposes (use influxdb for that) so I would like to attempt a repair and if that fails just a fresh start. Any pointers would be appreciated.

1 Like

Thanks @tom_l
Sorry for not being clear in my initial reply. I’m not using the default db but MariaDB.
I found the solution in a github issue:

Switching the db url as follows resolved my issue.

db_url: mysql://db_user:[email protected]/homeassistant?charset= utf8mb4

Where do I put the snapshot file in order to locate it upon booting the new install?

Anywhere you can browse to on or from the machine you are using to connect to home assistant.

I never get that restoring from snapshot page after the dialog box closes when I hit restore. Then when I try going to the page again I get a “empty reply” from HA.

help!!

Attempting to restore a snapshot from HA on ubuntu to Pi4. Every time I attempt to restore the snapshot the notice “Fetch Failed” comes up. I have done this several times. separate Pi’s and separate sd cards. Does anyone have any ideas?

I am seeing the same issue here trying to restore on a Pi4.

Hi Tom, the snap-shipper add-on now also supports S3 storage.

May I add this to the guidelines on how to restore individual files from password protected snapshots?

1 Like

Please do.

I am trying to do a fresh install after 2021.2 seem trashed my setup… but after upload snapshot tar, I am no seeing the checkbox shows up to select restore. Is there bug?

I am on pi 4, 4GB, using hassio 5.10 32-bit. My snapshot is from 2021.1

Do you see the snapshot in HA - Supervisor -> snapshot? If not, then first restart HA. Once you see it, you should be able to click on the backup and select restore.

Since I ran into multiple issues on 2021.2, so I ended up downgrade to 2021.1.4.

After that I can upload the snapshot, then the selection shows up. But nothing seem to happen when I click “restore all”. There is no restore in progress box showing, not sure if there is action in the background, but there is no indication on the GUI.

So, I login from console, and saw the snapshot uploaded. I finished the restore from console.

I am running over wifi, using Chrome 88 on Fedora