[{"data":1,"prerenderedAt":462},["ShallowReactive",2],{"blog-\u002Fblog\u002F2023\u002F10\u002Fuse-private-custom-nodes-with-flowfuse":3},{"id":4,"title":5,"body":6,"description":12,"extension":451,"meta":452,"navigation":457,"path":458,"seo":459,"stem":460,"__hash__":461},"blog\u002Fblog\u002F2023\u002F10\u002Fuse-private-custom-nodes-with-flowfuse.md","How to Use Private Custom Nodes in FlowFuse?",{"type":7,"value":8,"toc":440},"minimark",[9,13,38,41,46,49,54,64,68,71,76,83,113,119,128,134,138,141,148,157,160,164,169,187,192,208,212,221,225,235,238,253,258,266,279,349,353,367,374,378,381,397,406,409,414,422,431,436],[10,11,12],"p",{},"With version 1.12 of FlowFuse, it is now possible to use your custom nodes. In this article, we'll explain how to do that.",[14,15,18,19,18,26,18,29,37],"div",{"className":16},[17],"blog-update-notes","\n    ",[10,20,21,25],{},[22,23,24],"strong",{},"UPDATE:"," Since this article was published, we've made this even easier on FlowFuse!",[10,27,28],{},"Now, FlowFuse includes a private registry for all Team and Enterprise Tier customers, so there is no need to host and manage your own.",[10,30,31,32],{},"You can view our documentation on this feature ",[33,34,36],"a",{"href":35},"\u002Fdocs\u002Fuser\u002Fcustom-npm-packages\u002F","here"," \n",[10,39,40],{},"What do we mean by custom nodes? Typically, Node-RED nodes are hosted publicly on the npmjs registry, making them accessible to everyone for download and contribution. However, there are use cases where you may not want to share your developed nodes publicly. In such scenarios, it becomes necessary to run your own private Node-RED catalog and npm repository. This approach allows you to manage your custom nodes securely and efficiently.",[42,43,45],"h2",{"id":44},"step-1-setting-up-a-private-npm-repository","Step 1 - Setting Up a Private npm Repository",[10,47,48],{},"Before you can use custom nodes, you'll need a place to store them.",[50,51,53],"h3",{"id":52},"option-1-service-provider","Option 1 - Service Provider",[10,55,56,57,63],{},"Choose a public service provider, like ",[33,58,62],{"href":59,"rel":60},"https:\u002F\u002Fwww.npmjs.com\u002F",[61],"nofollow","npmjs",", that allows you to host private packages and upload your node module.",[50,65,67],{"id":66},"option-2-verdaccio","Option 2 - Verdaccio",[10,69,70],{},"Another option is to use Verdaccio, a lightweight private npm proxy registry that allows you to run your own registry.",[72,73,75],"h4",{"id":74},"installing-verdaccio","Installing Verdaccio",[77,78,79],"ol",{},[80,81,82],"li",{},"Install Verdaccio using npm:",[84,85,90],"pre",{"className":86,"code":87,"language":88,"meta":89,"style":89},"language-sh shiki shiki-themes github-light github-dark","npm install -g verdaccio\n","sh","",[91,92,93],"code",{"__ignoreMap":89},[94,95,98,102,106,110],"span",{"class":96,"line":97},"line",1,[94,99,101],{"class":100},"sScJk","npm",[94,103,105],{"class":104},"sZZnC"," install",[94,107,109],{"class":108},"sj4cs"," -g",[94,111,112],{"class":104}," verdaccio\n",[77,114,116],{"start":115},2,[80,117,118],{},"Run Verdaccio:",[84,120,122],{"className":86,"code":121,"language":88,"meta":89,"style":89},"verdaccio\n",[91,123,124],{"__ignoreMap":89},[94,125,126],{"class":96,"line":97},[94,127,121],{"class":100},[10,129,130,131],{},"This will start Verdaccio on ",[91,132,133],{},"http:\u002F\u002Flocalhost:4873",[72,135,137],{"id":136},"configuring-verdaccio","Configuring Verdaccio",[10,139,140],{},"The default configuration supports scoped packages and allows any user to access all packages, although only authenticated users can publish.",[10,142,143,144,147],{},"If necesarry you can edit the Verdaccio configuration file, usually found at ",[22,145,146],{},"~\u002F.config\u002Fverdaccio\u002Fconfig.yaml",".",[10,149,150,151,156],{},"Refer to the ",[33,152,155],{"href":153,"rel":154},"https:\u002F\u002Fverdaccio.org\u002Fdocs\u002Fconfiguration\u002F",[61],"documentation"," for all configuration options.",[10,158,159],{},"It is important that if you intend to use a private NPM registry with FlowFuse Cloud, the registry will need to be publicly exposed to the internet. Please make sure you understand how to secure it appropriately.",[72,161,163],{"id":162},"publish-your-package","Publish your package",[77,165,166],{},[80,167,168],{},"Create a user",[84,170,172],{"className":86,"code":171,"language":88,"meta":89,"style":89},"npm adduser --registry http:\u002F\u002Flocalhost:4873\u002F\n",[91,173,174],{"__ignoreMap":89},[94,175,176,178,181,184],{"class":96,"line":97},[94,177,101],{"class":100},[94,179,180],{"class":104}," adduser",[94,182,183],{"class":108}," --registry",[94,185,186],{"class":104}," http:\u002F\u002Flocalhost:4873\u002F\n",[77,188,189],{"start":115},[80,190,191],{},"Publish you package",[84,193,195],{"className":86,"code":194,"language":88,"meta":89,"style":89},"npm publish --registry http:\u002F\u002Flocalhost:4873\u002F\n",[91,196,197],{"__ignoreMap":89},[94,198,199,201,204,206],{"class":96,"line":97},[94,200,101],{"class":100},[94,202,203],{"class":104}," publish",[94,205,183],{"class":108},[94,207,186],{"class":104},[42,209,211],{"id":210},"step-2-creating-your-private-node-red-catalog","Step 2 - Creating Your Private Node-RED Catalog",[10,213,214,215,218,219,147],{},"There are several ways to generate your own ",[91,216,217],{},"catalogue.json",", which is necessary for Node-RED to understand which packages are available where. Below, we'll show you two of the many options to create and host a ",[91,220,217],{},[50,222,224],{"id":223},"option-1-web-app","Option 1 - Web App",[10,226,227,228,147],{},"To create and host a Node-RED catalog, we recommend the package ",[33,229,232],{"href":230,"rel":231},"https:\u002F\u002Fgithub.com\u002Fhardillb\u002Fnode-red-private-catalogue-builder",[61],[91,233,234],{},"node-red-private-catalogue-builder",[10,236,237],{},"The container accepts the following environment variables:",[239,240,241,244,247,250],"ul",{},[80,242,243],{},"PORT - Which port to listen on (defaults to 3000)",[80,245,246],{},"HOST - Which local IP Address to bind to (defaults to 0.0.0.0)",[80,248,249],{},"REGISTRY - A host and optional port number to connect to the NPM registry (defaults to http:\u002F registry:4873)",[80,251,252],{},"KEYWORD - The npm keyword to filter on (defaults to Node-RED)",[10,254,255],{},[22,256,257],{},"It presents 2 HTTP endpoints",[239,259,260,263],{},[80,261,262],{},"\u002Fupdate - a POST to this endpoint will trigger a rebuild of the catalogue",[80,264,265],{},"\u002Fcatalogue.json - a GET request returns the current catalogue",[10,267,268,269,272,273,278],{},"The ",[91,270,271],{},"\u002Fupdate"," endpoint can be used with the Verdaccio ",[33,274,277],{"href":275,"rel":276},"https:\u002F\u002Fverdaccio.org\u002Fdocs\u002Fnotifications",[61],"notification"," events to trigger the catalogue to automatically when nodes are added or updated.",[84,280,284],{"className":281,"code":282,"language":283,"meta":89,"style":89},"language-yaml shiki shiki-themes github-light github-dark","notify:\n  method: POST\n  headers: [{'Content-Type': 'application\u002Fjson'}]\n  endpoint: http:\u002F\u002Flocalhost:3000\u002Fupdate\n  content: '{\"name\": \"{{name}}\", \"versions\": \"{{versions}}\", \"dist-tags\": \"{{dist-tags}}\"}'\n","yaml",[91,285,286,296,307,327,338],{"__ignoreMap":89},[94,287,288,292],{"class":96,"line":97},[94,289,291],{"class":290},"s9eBZ","notify",[94,293,295],{"class":294},"sVt8B",":\n",[94,297,298,301,304],{"class":96,"line":115},[94,299,300],{"class":290},"  method",[94,302,303],{"class":294},": ",[94,305,306],{"class":104},"POST\n",[94,308,310,313,316,319,321,324],{"class":96,"line":309},3,[94,311,312],{"class":290},"  headers",[94,314,315],{"class":294},": [{",[94,317,318],{"class":104},"'Content-Type'",[94,320,303],{"class":294},[94,322,323],{"class":104},"'application\u002Fjson'",[94,325,326],{"class":294},"}]\n",[94,328,330,333,335],{"class":96,"line":329},4,[94,331,332],{"class":290},"  endpoint",[94,334,303],{"class":294},[94,336,337],{"class":104},"http:\u002F\u002Flocalhost:3000\u002Fupdate\n",[94,339,341,344,346],{"class":96,"line":340},5,[94,342,343],{"class":290},"  content",[94,345,303],{"class":294},[94,347,348],{"class":104},"'{\"name\": \"{{name}}\", \"versions\": \"{{versions}}\", \"dist-tags\": \"{{dist-tags}}\"}'\n",[50,350,352],{"id":351},"option-2-node-red","Option 2 - Node-RED",[10,354,355,356,363,364,366],{},"You can also use a FlowFuse Node-RED instance and the ",[33,357,360],{"href":358,"rel":359},"https:\u002F\u002Fflows.nodered.org\u002Fnode\u002Fnode-red-contrib-catalogue",[61],[91,361,362],{},"node-red-contrib-catalogue"," package to generate and host your ",[91,365,217],{}," file.",[368,369],"iframe",{"width":370,"height":370,"src":371,"allow":372,"style":373},"100%","https:\u002F\u002Fflows.nodered.org\u002Fflow\u002F1f01a92fdbd4172c75fcb88b44e64954\u002Fshare","clipboard-read; clipboard-write","border: none;",[42,375,377],{"id":376},"step-3-flowfuse-configuration","Step 3 - FlowFuse configuration",[10,379,380],{},"Next, you'll need to add all the details to your FlowFuse instance configuration.",[77,382,383],{},[80,384,385,386,389,390,389,393,396],{},"Add the Catalog: Go to your ",[22,387,388],{},"Instance"," -> ",[22,391,392],{},"Settings",[22,394,395],{},"Palette",". Here, you'll have the option to add a catalogue.json. You'll need to provide the URL from which the catalogue.json can be accessed.",[10,398,399,400],{},"For example: ",[22,401,402],{},[33,403,404],{"href":404,"rel":405},"https:\u002F\u002Fcatalogue.nodered.org\u002Fcatalogue.json",[61],[10,407,408],{},"It is import to remember that this URL must be accessible from the browser running the Node-RED editor and when used with FlowFuse (or any other Node-RED editor accessed via HTTPS) it must be served with HTTPS.",[77,410,411],{"start":115},[80,412,413],{},"Modify the npmrc File: You'll need to configure where to find the packages from the catalog, possibly specifying a scope.",[84,415,420],{"className":416,"code":418,"language":419},[417],"language-text","# Set a new registry for a scoped package\n@myscope:registry=https:\u002F\u002Fmycustomregistry.example.org\n","text",[91,421,418],{"__ignoreMap":89},[10,423,424,425,430],{},"If necessary, set authentication-related configurations. See the ",[33,426,429],{"href":427,"rel":428},"https:\u002F\u002Fdocs.npmjs.com\u002Fcli\u002Fv9\u002Fconfiguring-npm\u002Fnpmrc#auth-related-configuration",[61],"documentaion"," for details.",[77,432,433],{"start":309},[80,434,435],{},"Save and Restart Your Node-RED Instance: The new npm modules should now be visible in the Node-RED Palette Manager.",[437,438,439],"style",{},"html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .s9eBZ, html code.shiki .s9eBZ{--shiki-default:#22863A;--shiki-dark:#85E89D}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}",{"title":89,"searchDepth":115,"depth":115,"links":441},[442,446,450],{"id":44,"depth":115,"text":45,"children":443},[444,445],{"id":52,"depth":309,"text":53},{"id":66,"depth":309,"text":67},{"id":210,"depth":115,"text":211,"children":447},[448,449],{"id":223,"depth":309,"text":224},{"id":351,"depth":309,"text":352},{"id":376,"depth":115,"text":377},"md",{"navTitle":5,"excerpt":453},{"type":7,"value":454},[455],[10,456,12],{},true,"\u002Fblog\u002F2023\u002F10\u002Fuse-private-custom-nodes-with-flowfuse",{"title":5,"description":12},"blog\u002F2023\u002F10\u002Fuse-private-custom-nodes-with-flowfuse","K69IUuReqApArQ7TEyZ7ol7PfDYM7dTfX09msEiDSb4",1780132426057]