Node-RED flow to update Netlify DNS

This flow dynamically update a third level domain of a domain whose DNS are managed by Netlify.

Config

To work properly it needs a few parameters in global.config.ddns

When node start it should contains 3 keys:

  • access_token generated from Netlify
  • formatted_domain with dot replaced by underscore (eg. "test.com" -> "test_com")
  • full_domain (eg. "home.test.com")

At runtime the flow should add another key publicIPv4 with the actual public ipv4

How it works

The flow run every minute. It checks for changes in the public ip in order to proceed. It get the list of entries for the specified domain then check for the target subdomain, if it exists is removed, finally it creates an entry with the public ip.

[{"id":"4b8f5ca3.b122a4","type":"subflow","name":"Public IP","info":"","category":"","in":[{"x":60,"y":80,"wires":[{"id":"d51ecdb2.d831c"}]}],"out":[{"x":820,"y":80,"wires":[{"id":"c884ac05.45668","port":0}]}],"env":[],"color":"#DDAA99"},{"id":"771e18a3.e6bf98","type":"ip","z":"4b8f5ca3.b122a4","name":"ip","https":false,"timeout":"5000","internalIPv4":false,"internalIPv6":false,"publicIPv4":true,"publicIPv6":false,"x":350,"y":80,"wires":[["86eb080e.29fc48"]]},{"id":"86eb080e.29fc48","type":"change","z":"4b8f5ca3.b122a4","name":"","rules":[{"t":"move","p":"payload.publicIPv4","pt":"msg","to":"params.publicIPv4","tot":"msg"},{"t":"move","p":"params","pt":"msg","to":"payload","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":500,"y":80,"wires":[["c884ac05.45668"]]},{"id":"c884ac05.45668","type":"rbe","z":"4b8f5ca3.b122a4","name":"","func":"rbe","gap":"","start":"","inout":"out","property":"payload.publicIPv4","x":670,"y":80,"wires":[[]]},{"id":"d51ecdb2.d831c","type":"change","z":"4b8f5ca3.b122a4","name":"","rules":[{"t":"move","p":"payload","pt":"msg","to":"params","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":190,"y":80,"wires":[["771e18a3.e6bf98"]]},{"id":"7399db46.7e5a34","type":"subflow","name":"Format","info":"","category":"","in":[{"x":60,"y":80,"wires":[{"id":"9055dfc2.b061a"}]}],"out":[{"x":340,"y":80,"wires":[{"id":"9055dfc2.b061a","port":0}]}],"env":[],"color":"#DDAA99"},{"id":"9055dfc2.b061a","type":"function","z":"7399db46.7e5a34","name":"Format","func":"const newMsg = {};\nconst config = msg.payload;\nconst formattedPayload = {};\nObject.keys(config).forEach(key => {\n   switch (key) {\n    case 'domain': formattedPayload[key] = config[key].replace('.', '_'); break;\n    default: formattedPayload[key] = config[key]; break;\n   }\n});\nnewMsg.params = formattedPayload;\nreturn newMsg;","outputs":1,"noerr":0,"x":200,"y":80,"wires":[[]]},{"id":"4e432359.e55b1c","type":"tab","label":"DDNS","disabled":false,"info":""},{"id":"5a728f35.23a47","type":"http request","z":"4e432359.e55b1c","name":"Domains List","method":"GET","ret":"obj","paytoqs":false,"url":"https://api.netlify.com/api/v1/dns_zones/{{params.formatted_domain}}/dns_records?access_token={{params.access_token}}","tls":"","persist":false,"proxy":"","authType":"","x":630,"y":260,"wires":[["9e81e3f2.bf5dd","74740ac2.46e144"]]},{"id":"9e81e3f2.bf5dd","type":"debug","z":"4e432359.e55b1c","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","x":850,"y":260,"wires":[]},{"id":"5451bea6.d4a8f","type":"http request","z":"4e432359.e55b1c","name":"Delete Old Domain","method":"DELETE","ret":"txt","paytoqs":false,"url":"https://api.netlify.com/api/v1/dns_zones/{{params.formatted_domain}}/dns_records/{{params.id}}?access_token={{params.access_token}}","tls":"","persist":false,"proxy":"","authType":"","x":650,"y":320,"wires":[["3eba80db.11f0f","8e3b81a9.ff843"]]},{"id":"74740ac2.46e144","type":"function","z":"4e432359.e55b1c","name":"","func":"const newMsg = {};\nconst config = global.get('config.ddns');\nconst payload = {};\nObject.keys(config).forEach(key => {\n    payload[key] = config[key];\n});\nmsg.payload.forEach(sub => {\n    if (sub.hostname === config.full_domain) {\n       payload.id =  sub.id;\n    }\n});\n\nnewMsg.payload = payload;\nif(payload.id){\n    return [newMsg, null];\n}else{\n    return [null, newMsg];\n}","outputs":2,"noerr":0,"x":130,"y":320,"wires":[["95ae65ca.b790e8"],["e7fb5a2.f497aa8"]]},{"id":"e2bd0046.71359","type":"inject","z":"4e432359.e55b1c","name":"Config","topic":"","payload":"config.ddns","payloadType":"global","repeat":"","crontab":"","once":false,"onceDelay":0.1,"x":130,"y":600,"wires":[["8912d950.17bda8"]]},{"id":"8912d950.17bda8","type":"debug","z":"4e432359.e55b1c","name":"Log Config","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"payload","targetType":"msg","x":330,"y":600,"wires":[]},{"id":"3eba80db.11f0f","type":"debug","z":"4e432359.e55b1c","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","x":850,"y":320,"wires":[]},{"id":"8a27a29b.dd5bb","type":"subflow:7399db46.7e5a34","z":"4e432359.e55b1c","name":"Format","env":[],"x":320,"y":260,"wires":[["5a728f35.23a47"]]},{"id":"95ae65ca.b790e8","type":"subflow:7399db46.7e5a34","z":"4e432359.e55b1c","name":"","env":[],"x":320,"y":320,"wires":[["5451bea6.d4a8f"]]},{"id":"3882ba0e.ddcec6","type":"http request","z":"4e432359.e55b1c","name":"Create New Domain","method":"POST","ret":"obj","paytoqs":false,"url":"https://api.netlify.com/api/v1/dns_zones/{{params.formatted_domain}}/dns_records?access_token={{params.access_token}}","tls":"","persist":false,"proxy":"","authType":"","x":660,"y":380,"wires":[["96033cb3.99054"]]},{"id":"e7fb5a2.f497aa8","type":"subflow:7399db46.7e5a34","z":"4e432359.e55b1c","name":"","env":[],"x":320,"y":380,"wires":[["e8511f13.7ed32"]]},{"id":"8e3b81a9.ff843","type":"function","z":"4e432359.e55b1c","name":"","func":"const newMsg = {};\nconst config = global.get('config.ddns');\nconst payload = {};\nObject.keys(config).forEach(key => {\n    payload[key] = config[key];\n});\nnewMsg.payload = payload;\nreturn newMsg;\n","outputs":1,"noerr":0,"x":130,"y":380,"wires":[["e7fb5a2.f497aa8"]]},{"id":"96033cb3.99054","type":"debug","z":"4e432359.e55b1c","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","x":850,"y":380,"wires":[]},{"id":"65f557fb.7c6818","type":"debug","z":"4e432359.e55b1c","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","x":610,"y":440,"wires":[]},{"id":"e8511f13.7ed32","type":"change","z":"4e432359.e55b1c","name":"set sub","rules":[{"t":"set","p":"payload","pt":"msg","to":"{\"type\":\"A\",\"ttl\":60,\"priority\":null,\"weight\":null,\"port\":null,\"flag\":null,\"tag\":null,\"id\":null,\"site_id\":null,\"dns_zone_id\":null,\"errors\":[],\"managed\":false}","tot":"json"},{"t":"set","p":"payload.hostname","pt":"msg","to":"params.full_domain","tot":"msg"},{"t":"set","p":"payload.value","pt":"msg","to":"params.publicIPv4","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":460,"y":380,"wires":[["3882ba0e.ddcec6","65f557fb.7c6818"]]},{"id":"a7936b7c.d531f8","type":"debug","z":"4e432359.e55b1c","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"true","targetType":"full","x":850,"y":200,"wires":[]},{"id":"5df9d7b2.05cc88","type":"inject","z":"4e432359.e55b1c","name":"START","topic":"","payload":"config.ddns","payloadType":"global","repeat":"60","crontab":"","once":false,"onceDelay":0.1,"x":140,"y":200,"wires":[["64ca96cc.93e738"]]},{"id":"64ca96cc.93e738","type":"subflow:4b8f5ca3.b122a4","z":"4e432359.e55b1c","name":"Public IP","env":[],"x":320,"y":200,"wires":[["e7c0d612.3e23f8"]]},{"id":"e7c0d612.3e23f8","type":"change","z":"4e432359.e55b1c","name":"Save IP","rules":[{"t":"set","p":"config.ddns.publicIPv4","pt":"global","to":"payload.publicIPv4","tot":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":460,"y":200,"wires":[["a7936b7c.d531f8","8a27a29b.dd5bb"]]},{"id":"729c449f.51122c","type":"comment","z":"4e432359.e55b1c","name":"Netlifly DNS Updater","info":"# Description\nThis flow dynamically update a third level domain of a domain whose DNS are managed by _Netlify_.\n\n## Config\nTo work properly it needs a few parameters in `global.config.ddns`\n\nWhen node start it should contains 3 keys:\n - **access_token** generated from Netlify\n - **formatted_domain** with dot replaced by underscore (eg. \"test.com\" -> \"test_com\")\n - **full_domain** (eg. \"home.test.com\")\n \nAt runtime the flow should add another key **publicIPv4** with the actual public ipv4\n\n## How it works\nThe flow run every minute. It checks for changes in the public ip in order to proceed. It get the list of entries for the specified domain then check for the target subdomain, if it exists is removed, finally it creates an entry with the public ip.","x":150,"y":60,"wires":[]}]

Flow Info

Created 5 years, 5 months ago
Updated 5 years, 3 months ago
Rating: not yet rated

Owner

Actions

Rate:

Node Types

Core
  • change (x4)
  • comment (x1)
  • debug (x6)
  • function (x3)
  • http request (x3)
  • inject (x2)
  • rbe (x1)
Other
  • ip (x1)
  • subflow (x2)
  • subflow:4b8f5ca3.b122a4 (x1)
  • subflow:7399db46.7e5a34 (x3)
  • tab (x1)

Tags

  • dns
  • ddns
  • netlify
Copy this flow JSON to your clipboard and then import into Node-RED using the Import From > Clipboard (Ctrl-I) menu option