How to create automatic backups of hub database

This is essentially what I would be doing ... but enabling authentication breaks it.

Planning is not paranoia....it’s planning. If my hub died, I wouldn’t freak out if I had to recreate it from scratch. The backups are an excellent help.

As long as you're cool passing your password in plain text, this should work. Once authentication was turned on, HE now required stateful sessions.
This script is a .PS1 as well. I tested on my system and it fired off fine. Just update with your creds.
Let me know how all goes and if you need any 'tweaks'.

$Body = @{
    username = 'YOUR_NAME_HERE'
    password = 'YOUR_PW_HERE'
}
$url = "http://XXX.XXX.XXX.XXX/hub/backupDB?fileName=latest"
$output = "C:\YOURFOLDER\hubitat backup $(get-date -f yyyy-MM-dd-HHmmss).lzf"
$LoginResponse = Invoke-WebRequest 'http://XXX.XXX.XXX.XXX/login' -SessionVariable 'Session' -Body $Body -Method 'POST'

$Session

$ProfileResponse = Invoke-WebRequest $url -OutFile $output -WebSession $Session
$ProfileResponse
4 Likes

For those looking for the Curl way:

curl -c cookie.txt -d "username=myusername" -d "password=mypassword" http://{hub name or IP}/login
curl -sb cookie.txt http://{hub name or IP}/hub/backupDB?fileName=latest -o "/some/dir/myHubBackup$(date +%Y%m%d%H%M).lzf"

The first line hits the hub, does the login and saves the resulting JSESSIONID in a file called cookie.txt
The second line uses the saved JSESSIONID and causes the hub to build a backup file and downloads it under a filename with date&time appended.

1 Like

I've been following this thread with great interest. Seems that having a backup and replacing hub keeping the same stick is an easy recovery, however what happens when you have to replace the stick and rejoin all your devices?

Thanks @john.hart3706, I modified your PowerShell script to make it little bit more secure, configurable and added a retention policy, it will keep the last X backups and delete the rest, if less than X it will not delete any file...

$HubitatHost = "IP or Hostname"
$BackupPath = "Drive:\BackupFolder\SubFolder"
$RetentionPolicy = 30
$Protocol = "HTTPS"
$DisableCertificateValidation = $true


# Get Backup User Credentials
$BackupCredentials = "$BackupPath\BackupCredentials.xml"
If (!(Test-Path $BackupCredentials)) {
    $Credentials =  Get-Credential
    $Credentials | Export-CliXml -Path $BackupCredentials
} Else {
    Try {
        $Credentials = Import-CliXml -Path $BackupCredentials
    } Catch {
        Throw "Error reading credentials file, it may have been generatd with a diferent computer/account, try deleting the file and recreating it."
    }
}

# Sets Security Protocol to TLS 1.2 and certificate validation preference.
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
If ($DisableCertificateValidation) { [System.Net.ServicePointManager]::ServerCertificateValidationCallback = { $true } }

# Request Login Session
$Body = @{
    username = $Credentials.UserName
    password  = ([System.Runtime.InteropServices.Marshal]::PtrToStringAuto([System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($Credentials.Password)))
}

$url = "$Protocol`://$HubitatHost/hub/backupDB?fileName=latest"
$output = "$BackupPath\HubitatBackup_$(get-date -f yyyy-MM-dd-HHmmss).lzf"
$LoginResponse = Invoke-WebRequest "$Protocol`://$HubitatHost/login" -SessionVariable 'Session' -Body $Body -Method 'POST'

# Check if Login was successful
If ($LoginResponse.BaseResponse.ResponseUri -eq "$Protocol`://$HubitatHost/login") {
    Throw "Error Logging In to Hubitat, please check credentials."
}

# Download the Backup file
$ProfileResponse = Invoke-WebRequest $url -OutFile $output -WebSession $Session

# Apply Retention Policy
gci $BackupPath -Recurse| where {$_.extension -eq ".lzf" -and -not $_.PsIsContainer} | sort CreationTime -desc | select -Skip $RetentionPolicy | Remove-Item -Force

First time it runs it will ask for credentials and save them in an encrypted file with the backups. To change the credentials just delete the "BackupCredentials.xml" file and run manually again.

It will also check that it is able to login successfully or otherwise you'll end with a bunch of useless backup files containing the login page error.

Please note: The credentials file can only be used in the computer it was generated by the user who generated it. This will not stop anybody who knows what they’re doing from decrypting your password or from reusing your encrypted password if they are able to compromise your login. The whole point of converting your password to a SecureString and storing it in a file is to keep it out of plain text in your scripts so that it’s not as easily discovered.

Furthermore, because of the login mechanism currently implemented and the fact that Hubitat does not currently implement SSL, the password is still sent in plain text...

EDIT: Added support for HTTPS that was added to HE Firmware 2.0.5 but as the certificate is Self-Siged and does not include a host name, the script disables certificate validation. This is not ideal but much better as the password is not sent in clear text.

10 Likes

Very Cool! Now that looks like a complete solution. I Like It!!

this community continues to amaze me. really excellent work @john.hart3706 & @gparra, can't wait to give it a shot this afternoon.

Works. Excellent.

1 Like

Glad to hear it! :smile:

Thanks to all of the instructions! I now have my Synology NAS pulling the backup every night!

How you did it? I have an Asustor but I have no idea how to make it to pull the backup :pensive:

Synology has a task manager that runs user scripts. Does Asustor have that?

I have no idea but thanks for the info, probably I can install something similar or maybe it has it

Thanks.

More reason for mDNS support so I don't need to wire IP addresses into my scripts.

Hi All,

I modified my PowerShell script above (link) to add support for SSL which was added to HE since firmware 2.0.5.

Credentials are not sent in clear text anymore which is a lot better, certificate validation has to be disabled though due to the self-signed cert. If/when HE gives us the ability to upload our own cert this can be further improved...

4 Likes

Here is another linux variant for getting the db using curl and wget.

curl -c cookie.txt -d username=USERNAME -d password=PASSWORD http://HUB-IP/login
wget --load-cookies=cookie.txt --content-disposition -P /YOUR_HOME/hubitat-backups/ http://HUB-IP/hub/backupDB?fileName=latest

My cron looks like this.
First line runs the cron at 4am and makes sure I'm in ~/ then retrieves the cookie and finally the backup db.

00 4 * * * cd; curl -c cookie.txt -d username=USERNAME -d password=PASSWORD http://HUB-IP/login; wget --load-cookies=cookie.txt --content-disposition -P /home/USERNAME/Dropbox/hubitat-backups/ http://HUB-IP/hub/backupDB?fileName=latest

This line deletes backups older then 5 days.

@daily find /home/USERNAME/Dropbox/hubitat-backups/ -mindepth 1 -type f -mtime +5 -delete

3 Likes

Could this be done in python or node red? I have both running in dockers and would love to get regular backups working.

check out https://curl.trillworks.com/

I use nodeRed for my daily backups.

The Get Backup node is an http request node performing a GET to

http://<hubip>/hub/backupDB?fileName=latest

and returning a binary buffer that is passed to the FileIn node to save to disk.