node-RED Backup Flow

I read a post a few days ago by @Trying_to_learn about losing his node-RED flow, which had taken him no doubt many hours to construct, and as his backup was on the same machine - he lost that too.
So... I've spent a few days looking at off-site storage, and stumbled upon node-red-contrib-dsm which was written by @cflurin complete with an example flow to perform automated backups to dropbox.


I played about with the configuration, and made some changes to the way that the backups are stored, basically to stop dropbox from filling up, yet conduct a nightly backup and be able to retrieve any one of those backups for 30 days (30 backups). The older ones are automatically weeded by dropbox, so it's 'fit & forget'.
Instead of the backups being named as a timestamp, they are named as the day of the week -, etc.
Looking at the dropbox web dashboard, you will only see 7 files (the current 7 days), but if you go to 'Version History', you can see & download the previous versions of that day, so for example every Monday's backup for the past 30 days.

Anyway, here's the flow, it uses node-red-contrib-dsm, node-red-node-dropbox and a couple of inject nodes.
Also you need to ensure that zip is installed, try zip --help and if help isn't displayed, then install it as sudo apt-get install zip unzip.
The flow should work out of the box, once you've configured the dropbox node (leave the Filename & Local Filename boxes empty).
PS The inject node is set to run the flow 3.15am every night.

[{"id":"ac51c586.8c6a48","type":"dropbox out","z":"b3b413d1.05b1b","dropbox":"","filename":"","localFilename":"","name":"","x":470,"y":1290,"wires":[]},{"id":"fc160f5e.0d6af","type":"inject","z":"b3b413d1.05b1b","name":"backup","topic":"start","payload":"","payloadType":"date","repeat":"","crontab":"15 03 * * *","once":false,"onceDelay":0.1,"x":172,"y":1270,"wires":[["860656c2.a3c6a8"]]},{"id":"1b04cc97.6b57d3","type":"inject","z":"b3b413d1.05b1b","name":"reset","topic":"reset","payload":"","payloadType":"date","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":180,"y":1310,"wires":[["860656c2.a3c6a8"]]},{"id":"860656c2.a3c6a8","type":"dsm","z":"b3b413d1.05b1b","name":"backup","sm_config":"{\n    \"currentState\": \"step1\",\n    \"states\": {\n        \"step1\": {\n            \"start\": \"step2\",\n            \"reset\": \"step1\"\n        },\n        \"step2\": {\n            \"zip\": \"step3\",\n            \"reset\": \"step1\"\n        },\n        \"step3\": {\n            \"upload\": \"step1\",\n            \"reset\": \"step1\"\n        }\n    },\n    \"data\": {\n    },\n    \"methods\": {\n        \"init\": [\n            \"sm.udir = RED.settings.userDir + '/';\",\n            \"sm.exec = require('child_process').exec;\",\n            \"sm.hostname = require('os').hostname();\",\n            \"sm.unlink = require('fs').unlink;\"\n        ],\n        \"start\": [\n            \"/* delete old zip file */\",\n            \"var zipfile = sm.udir+'';\",\n            \n            \"sm.fill = 'grey';\",\n            \"sm.text = 'deleting';\",\n            \"output = false;\",\n\n            \"sm.unlink(zipfile, function (err) {\",\n            \"   if (err) {\",\n            \"       node.warn('no file '+zipfile);\",\n            \"   }\",\n            \"   resume('zip', msg);\",\n            \"});\"\n        ],\n        \"zip\": [\n            \"var pre = ' ' + sm.udir;\",\n            \"var cmd = 'zip -r';\",\n            \"cmd += pre + '';\",\n            \"cmd += pre + 'flows*.json';\",\n            \"cmd += pre + '.config.json';\",\n            \"cmd += pre + '.sessions.json';\",\n            \"cmd += pre + 'settings.js';\",\n            \"cmd += pre + 'package.json';\",\n            \"cmd += pre + 'package-lock.json';\",\n            \"cmd += pre + 'lib/*';\",\n\n            \"sm.fill = 'grey';\",\n            \"sm.text = 'zipping';\",\n            \"output = false;\",\n            \n            \"sm.exec(cmd, function(error, stdout, stderr) {\",\n            \"   if (error) {\",\n            \"       node.warn(error);\",\n            \"   } else {\",\n            \"       resume('upload', msg);\",\n            \"   }\",\n            \"});\"\n        ],\n        \"upload\": [\n            \"sm.ts = new Date();\",\n            \"sm.days = ['Sunday','Monday','Tuesday','Wednesday','Thursday','Friday','Saturday'];\",\n            \" = sm.days[sm.ts.getDay()];\",\n            \"msg.filename = + '';\",\n            \"msg.localFilename = sm.udir+'';\",\n            \"sm.fill = 'green';\",\n            \"sm.text =;\"\n        ],\n        \"reset\": [\n            \"sm.fill = 'grey';\",\n            \"sm.text = 'reset';\",\n            \"output = false;\"\n        ],\n        \"status\": {\n            \"fill\": {\n                \"get\": \"sm.fill\"\n            },\n            \"shape\": \"dot\",\n            \"text\": {\n                \"get\": \"sm.text\"\n            }\n        }\n    }\n}","x":325,"y":1290,"wires":[["ac51c586.8c6a48"]]}]

@Paul-Reed Nice, but I have a suggestion, why not run the flow every hour or half hour and compare it to the previous version. If they are different, save the new one then while developing you would have multiple backups to fall back to if you mess something up (not like I've ever done that...more than a few dozen or more times :rofl:)

As the DSM saves the zip file in the /node-red user directory, you would probably need to regularly check the size of the zip file, and if it's changed, then upload that file to dropbox.
However, I like this because of its simplicity, and maybe if it starts to get too complicated, some users may be deterred from using it.

Users could always trigger a backup at anytime, just by clicking the inject node.


I'm using the version from the dsm-wiki for months on 3 Rpis. Two of them are running without any changes for weeks, so I only manually backup node-red by changes.

1 Like

This topic was automatically closed after 60 days. New replies are no longer allowed.