Need backup function

node-red is powerful .there are very many nodes.
I use node-red to quick solve problems .node-red also like IDE to me,so if there have backup function ?!backup online code, backup status ,backup system!

it has git function so you can commit and push from editor, also You can just copy some files (mainly flows.json, flows_cred.json, package.json) using crontab or bacula or any oher backup software, it is node application at the end, so it is really easy to backup it just using files.

If not use git, I think best is to just switch to project mode and automatic backup project directory. You can do it by cron, or make a node which reads file and save it somewhere. Imho full automated backup solution is not needed in node-red core, because there a lot of backup reciepts sysops use, and no one method would be universal.

1 Like

@benefit_union, aside from the git function (which I personally use) mentioned above by @zba, I also use the following flows to back up locally on my rpi and to dropbox. You'll need to configure node-red-node-dropbox to your dropbox account to get the dropbox functionality.

Both use inject nodes. The first is an example of a manual backup and the second is using an inject node for automatic backups. Hopefully these are helpful.

I don't remember where I found these, but I believe they are from @cflurin and @Paul-Reed.

This one works perfect for local backups:

[{"id":"d700c9cba4f37fb6","type":"group","z":"edce5f4c305a1484","g":"e7b606491b142060","name":"Local Manual Backups","style":{"stroke":"#0070c0","fill":"#000000","label":true,"color":"#000000"},"nodes":["ddf9752546965985","49ad438fd1bb9535","86698c867ee0f85e","5628e78c92568763"],"x":1114,"y":779,"w":512,"h":122},{"id":"ddf9752546965985","type":"inject","z":"edce5f4c305a1484","g":"d700c9cba4f37fb6","name":"backup","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"start","payload":"","payloadType":"date","x":1210,"y":820,"wires":[["49ad438fd1bb9535"]]},{"id":"49ad438fd1bb9535","type":"dsm","z":"edce5f4c305a1484","g":"d700c9cba4f37fb6","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+'node-red.zip';\",\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 + 'node-red.zip';\",\n            \"cmd += pre + 'flows_'+sm.hostname+'.json';\",\n            \"cmd += pre + 'flows_'+sm.hostname+'_cred.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 + 'context/*';\",\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 = timestamp().slice(0,-4).replace(/:/g,'');\",\n            \"msg.filename = sm.hostname+'/' + sm.ts + '_nr.zip';\",\n            \"msg.localFilename = sm.udir+'node-red.zip';\",\n            \"sm.fill = 'green';\",\n            \"sm.text = sm.ts;\"\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":1360,"y":840,"wires":[["5628e78c92568763"]]},{"id":"86698c867ee0f85e","type":"inject","z":"edce5f4c305a1484","g":"d700c9cba4f37fb6","name":"reset","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"reset","payload":"","payloadType":"date","x":1210,"y":860,"wires":[["49ad438fd1bb9535"]]},{"id":"5628e78c92568763","type":"debug","z":"edce5f4c305a1484","g":"d700c9cba4f37fb6","name":"debug 1113","active":false,"tosidebar":true,"console":false,"tostatus":true,"complete":"true","targetType":"full","statusVal":"payload","statusType":"auto","x":1510,"y":840,"wires":[]}]

And here is the dropbox flow:

[{"id":"105eb39d95cd7953","type":"group","z":"edce5f4c305a1484","name":"DropBox Automatic Daily Backups","style":{"stroke":"#0070c0","fill":"#777777","label":true,"color":"#000000"},"nodes":["de7d7ce9c179c080","9b0888b2e975a14c","bdfd5898c608c080","0a40c275d8ec51f4"],"x":1074,"y":1579,"w":512,"h":122},{"id":"de7d7ce9c179c080","type":"inject","z":"edce5f4c305a1484","g":"105eb39d95cd7953","name":"reset","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"reset","payload":"","payloadType":"date","x":1190,"y":1660,"wires":[["9b0888b2e975a14c"]]},{"id":"9b0888b2e975a14c","type":"dsm","z":"edce5f4c305a1484","g":"105eb39d95cd7953","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+'node-red.zip';\",\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 + 'node-red.zip';\",\n            \"cmd += pre + 'flows*.json';\",\n            \"cmd += pre + '.config*.json';\",\n            \"cmd += pre + 'settings.js';\",\n            \"cmd += pre + 'package.json';\",\n            \"cmd += pre + 'package-lock.json';\",\n            \"cmd += pre + '.config.modules.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.day = sm.days[sm.ts.getDay()];\",\n            \"msg.filename = sm.day + '_nodered.zip';\",\n            \"msg.localFilename = sm.udir+'node-red.zip';\",\n            \"sm.fill = 'green';\",\n            \"sm.text = sm.day;\"\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":1340,"y":1640,"wires":[["0a40c275d8ec51f4"]]},{"id":"bdfd5898c608c080","type":"inject","z":"edce5f4c305a1484","g":"105eb39d95cd7953","name":"backup","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"15 03 * * *","once":false,"onceDelay":0.1,"topic":"start","payload":"","payloadType":"date","x":1180,"y":1620,"wires":[["9b0888b2e975a14c"]]},{"id":"0a40c275d8ec51f4","type":"dropbox out","z":"edce5f4c305a1484","g":"105eb39d95cd7953","dropbox":"","filename":"","localFilename":"","name":"","x":1500,"y":1640,"wires":[]}]

See node-RED Backup Flow for original flow & description.

1 Like

FWIW, here is my local backup flow (for Linux).

I backup everything except for ~/.node-red/node_modules and the default backup file is ~/nodered.tar.gz.

On a Raspberry Pi which has the read-only filesystem enabled, I backup instead to an sshfs mount onto another machine, where a Node-red flow watched the backup directory and performs backup file rotation etc.

[{"id":"f8272cf6024174cd","type":"group","z":"7f20ad1a9174e987","name":"Backup Node-red","style":{"label":true},"nodes":["cf19faaabdfb2dbe","fb47ca1393ddc5aa","3c4d7bf52fe7f7f6","fcbfc58d8799f180","6218b2d2ddf29d4b","902b50d96cc6fbdc"],"x":14,"y":19,"w":852,"h":142},{"id":"cf19faaabdfb2dbe","type":"exec","z":"7f20ad1a9174e987","g":"f8272cf6024174cd","command":"","addpay":"payload","append":"","useSpawn":"false","timer":"","winHide":false,"oldrc":false,"name":"","x":590,"y":80,"wires":[["fb47ca1393ddc5aa"],["3c4d7bf52fe7f7f6"],[]]},{"id":"fb47ca1393ddc5aa","type":"debug","z":"7f20ad1a9174e987","g":"f8272cf6024174cd","name":"Backup stats","active":true,"tosidebar":true,"console":false,"tostatus":true,"complete":"payload","targetType":"msg","statusVal":"payload","statusType":"auto","x":750,"y":60,"wires":[]},{"id":"3c4d7bf52fe7f7f6","type":"debug","z":"7f20ad1a9174e987","g":"f8272cf6024174cd","name":"Errors","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":730,"y":120,"wires":[]},{"id":"fcbfc58d8799f180","type":"inject","z":"7f20ad1a9174e987","g":"f8272cf6024174cd","name":"Node-red location & backup target","props":[{"p":"nodereddirectory","v":".node-red","vt":"str"},{"p":"backupfilename","v":"$moment().format(\"YYYYMMDD.HHmm\") & \"nr.tar.gz\"","vt":"jsonata"},{"p":"backupfilename","v":"nodered.tar.gz","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","x":200,"y":80,"wires":[["6218b2d2ddf29d4b"]]},{"id":"6218b2d2ddf29d4b","type":"template","z":"7f20ad1a9174e987","g":"f8272cf6024174cd","name":"Backup script","field":"payload","fieldType":"msg","format":"handlebars","syntax":"mustache","template":"# To override defaults pass these in as msg properties NB Bash does not see these mustaches\nNODEREDDIR={{{nodereddirectory}}}   \nBACKUPTO={{{backupfilename}}}\n\n# Default location\nif [ -z $NODEREDDIR ]\nthen\nNODEREDDIR=.node-red\nfi\n\n# Default backup file\nif [ -z $BACKUPTO ]\nthen\n   BACKUPTO=nodered.tar.gz\nfi\n\n# Don't overwrite backupfile\n#if [ -s \"$BACKUPTO\" ]\n#then\n#  echo \"Error: $BACKUPTO already exists\" >&2\n#  exit 1\n#fi\n\nARCHIVER=\"tar -czf $BACKUPTO --numeric-owner --exclude=node_modules*\"\n$($ARCHIVER $NODEREDDIR)   # Do the backup\n\nCOUNTFILES=\"$(tar -tvf $BACKUPTO | wc -l)\"\nFILESIZE=\"$(du -h $BACKUPTO | sed -e 's/\\s.*//')\"\nprintf \"%s files %s in %s\" $COUNTFILES $FILESIZE $BACKUPTO","output":"str","x":440,"y":80,"wires":[["cf19faaabdfb2dbe","902b50d96cc6fbdc"]]},{"id":"902b50d96cc6fbdc","type":"debug","z":"7f20ad1a9174e987","g":"f8272cf6024174cd","name":"Backup script","active":false,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","statusVal":"","statusType":"auto","x":460,"y":120,"wires":[]}]

I've previously shared some BASH scripts to do backups, you run them via CRON on Linux servers.

Also, you don't need to switch to projects to use GIT.

thanks all of you. U have solve most question of me.I write this topic for sometime I editting code in function on web browser if I close the node-red cmd and I lost my editing code.
Do you have this ?

Do we have the code you were editing?

No, and I suspect you don't either.

In future you should probably arrange for Node-red to run automatically as a service when the computer is booted up.

You should only lose it if you have not Deployed.

Thanks for posting that. I've used that bit of code quite a bit since your post about it.

1 Like

Got it. Thanks