[{"data":1,"prerenderedAt":3325},["ShallowReactive",2],{"docs-\u002Fdocs\u002Fadmin\u002Fhardening\u002Fkubernetes\u002F":3,"featureCatalog":2482,"docs-nav":2877},{"id":4,"title":5,"body":6,"description":16,"extension":2471,"layout":2472,"meta":2473,"navGroup":2472,"navGroupOrder":2472,"navOrder":2472,"navTitle":5,"navigation":2474,"originalPath":2475,"path":2476,"redirect":2472,"seo":2477,"stem":2478,"updated":2479,"version":2480,"__hash__":2481},"docs\u002Fdocs\u002Fadmin\u002Fhardening\u002Fkubernetes.md","Kubernetes Hardening",{"type":7,"value":8,"toc":2452},"minimark",[9,13,17,35,40,43,46,69,74,88,108,111,141,148,154,258,268,386,392,499,505,611,631,657,814,826,832,839,844,921,933,942,1095,1100,1114,1263,1269,1375,1385,1589,1603,1816,1846,1850,1853,1863,1871,1875,1878,1882,1889,1892,1909,1922,1925,1948,1952,1955,1990,2005,2009,2038,2041,2063,2067,2113,2117,2371,2381,2385,2388,2448],[10,11,5],"h1",{"id":12},"kubernetes-hardening",[14,15,16],"p",{},"This guide walks you through the best ways to secure a Kubernetes cluster running FlowFuse. Locking down your cluster shrinks your attack surface and keeps things contained if a single component gets compromised.\nThese tips work best when implemented together, so roll out as many of them as your environment allows.",[18,19,23,28],"div",{"className":20},[21,22],"ff-callout","ff-callout--note",[14,24,27],{"className":25},[26],"ff-callout__title","Note",[18,29,32],{"className":30},[31],"ff-callout__content",[14,33,34],{},"These are general hardening recommendations. Adapt them to your organisation's security policies and your cluster's specific configuration.",[36,37,39],"h2",{"id":38},"network-policies","Network Policies",[14,41,42],{},"By default, Kubernetes allows unrestricted network traffic between all pods, across all namespaces. Any pod can reach any other pod on any port. This flat network model means that a single compromised pod, for example a vulnerable instance, can be used to reach and attack every other workload in the cluster.",[14,44,45],{},"Network Policies let you enforce the principle of least privilege at the network layer: a pod should only be able to talk to the workloads it genuinely needs. Restricting traffic contains lateral movement, so a breach in one component cannot trivially spread to others.",[18,47,50,54],{"className":48},[21,49],"ff-callout--warning",[14,51,53],{"className":52},[26],"Warning",[18,55,57],{"className":56},[31],[14,58,59,63,64,68],{},[60,61,62],"strong",{},"Do not treat the policies below as a copy-and-paste solution."," They are illustrative examples, tied to the assumptions of the environment they were written for - namespace names, the ingress controller, the CNI, service ports, which components are deployed, and where operators live. Applied blindly they will either break platform traffic or leave gaps you believe are closed. Network Policies are one of the easiest things in Kubernetes to get subtly wrong: a rule that ",[65,66,67],"em",{},"looks"," correct can silently drop traffic (wrong port direction, Service vs pod port, a missing return path) or silently allow it (an unenforced CNI, an overly broad selector). Implement them deliberately, with a working understanding of how traffic actually flows in your cluster - pod-to-pod, cross-namespace, ingress, egress, and DNS. Roll out one policy at a time, start in a non-production environment, verify each addition against real traffic (and check the affected pods' logs and Service endpoints), and confirm your CNI actually enforces policies before relying on them for security.",[70,71,73],"h3",{"id":72},"flowfuse-and-network-policies","FlowFuse and Network Policies",[14,75,76,77,81,82,87],{},"FlowFuse runs the platform (namespace of your choice, selected during Helm chart installation) and the hosted Node-RED instances (configured with the ",[78,79,80],"code",{},"forge.projectNamespace"," Helm chart value) in separate namespaces. If you enforce Network Policies, you must explicitly allow the traffic FlowFuse needs - otherwise the instances cannot reach the platform. See ",[83,84,86],"a",{"href":85},"\u002Fdocs\u002Finstall\u002Fkubernetes#i-use-kubernetes-network-policies-how-can-i-configure-them","I use Kubernetes Network Policies, how can I configure them?"," for the required policy.",[18,89,91,94],{"className":90},[21,22],[14,92,27],{"className":93},[26],[18,95,97],{"className":96},[31],[14,98,99,100,103,104,107],{},"The following examples assume the default namespaces ",[78,101,102],{},"flowfuse",", as a core application namespace, and ",[78,105,106],{},"projects"," for Hosted Instances namespace. If you have configured different namespaces, replace them accordingly.",[14,109,110],{},"The two namespaces have very different trust levels, so they are hardened differently:",[112,113,114,126],"ul",{},[115,116,117,121,122,125],"li",{},[60,118,119],{},[78,120,102],{}," runs trusted first-party components (core app, MQTT broker, private registry, local database). Here we restrict ",[60,123,124],{},"inbound"," traffic only — deny all ingress, then allow the connections the platform needs. Egress is left open so the platform can reach external services (licensing, npm registry, SMTP, etc.) without maintaining a brittle allow-list.",[115,127,128,132,133,136,137,140],{},[60,129,130],{},[78,131,106],{}," runs Node-RED instances executing ",[60,134,135],{},"user-supplied flows"," - untrusted code. Here we lock down ",[60,138,139],{},"both ingress and egress"," to contain a malicious or compromised flow: it should reach only the platform services it legitimately needs, and nothing else.",[70,142,144,145,147],{"id":143},"core-platform-namespace-flowfuse","Core platform namespace (",[78,146,102],{},")",[14,149,150,153],{},[60,151,152],{},"1. Deny all inbound traffic."," Egress is intentionally not restricted here.",[155,156,161],"pre",{"className":157,"code":158,"language":159,"meta":160,"style":160},"language-yaml shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","apiVersion: networking.k8s.io\u002Fv1\nkind: NetworkPolicy\nmetadata:\n  name: default-deny-ingress\n  namespace: flowfuse\nspec:\n  podSelector: {}\n  policyTypes:\n    - Ingress\n","yaml","",[78,162,163,180,191,200,211,222,230,241,249],{"__ignoreMap":160},[164,165,168,172,176],"span",{"class":166,"line":167},"line",1,[164,169,171],{"class":170},"swJcz","apiVersion",[164,173,175],{"class":174},"sMK4o",":",[164,177,179],{"class":178},"sfazB"," networking.k8s.io\u002Fv1\n",[164,181,183,186,188],{"class":166,"line":182},2,[164,184,185],{"class":170},"kind",[164,187,175],{"class":174},[164,189,190],{"class":178}," NetworkPolicy\n",[164,192,194,197],{"class":166,"line":193},3,[164,195,196],{"class":170},"metadata",[164,198,199],{"class":174},":\n",[164,201,203,206,208],{"class":166,"line":202},4,[164,204,205],{"class":170},"  name",[164,207,175],{"class":174},[164,209,210],{"class":178}," default-deny-ingress\n",[164,212,214,217,219],{"class":166,"line":213},5,[164,215,216],{"class":170},"  namespace",[164,218,175],{"class":174},[164,220,221],{"class":178}," flowfuse\n",[164,223,225,228],{"class":166,"line":224},6,[164,226,227],{"class":170},"spec",[164,229,199],{"class":174},[164,231,233,236,238],{"class":166,"line":232},7,[164,234,235],{"class":170},"  podSelector",[164,237,175],{"class":174},[164,239,240],{"class":174}," {}\n",[164,242,244,247],{"class":166,"line":243},8,[164,245,246],{"class":170},"  policyTypes",[164,248,199],{"class":174},[164,250,252,255],{"class":166,"line":251},9,[164,253,254],{"class":174},"    -",[164,256,257],{"class":178}," Ingress\n",[14,259,260,263,264,267],{},[60,261,262],{},"2. Allow inbound from the ingress controller"," so users can reach the application (namespace usually ",[78,265,266],{},"traefik","):",[155,269,271],{"className":157,"code":270,"language":159,"meta":160,"style":160},"apiVersion: networking.k8s.io\u002Fv1\nkind: NetworkPolicy\nmetadata:\n  name: allow-ingress-from-traefik\n  namespace: flowfuse\nspec:\n  podSelector: {}\n  policyTypes:\n    - Ingress\n  ingress:\n    - from:\n        - namespaceSelector:\n            matchLabels:\n              kubernetes.io\u002Fmetadata.name: traefik\n",[78,272,273,281,289,295,304,312,318,326,332,338,346,356,367,375],{"__ignoreMap":160},[164,274,275,277,279],{"class":166,"line":167},[164,276,171],{"class":170},[164,278,175],{"class":174},[164,280,179],{"class":178},[164,282,283,285,287],{"class":166,"line":182},[164,284,185],{"class":170},[164,286,175],{"class":174},[164,288,190],{"class":178},[164,290,291,293],{"class":166,"line":193},[164,292,196],{"class":170},[164,294,199],{"class":174},[164,296,297,299,301],{"class":166,"line":202},[164,298,205],{"class":170},[164,300,175],{"class":174},[164,302,303],{"class":178}," allow-ingress-from-traefik\n",[164,305,306,308,310],{"class":166,"line":213},[164,307,216],{"class":170},[164,309,175],{"class":174},[164,311,221],{"class":178},[164,313,314,316],{"class":166,"line":224},[164,315,227],{"class":170},[164,317,199],{"class":174},[164,319,320,322,324],{"class":166,"line":232},[164,321,235],{"class":170},[164,323,175],{"class":174},[164,325,240],{"class":174},[164,327,328,330],{"class":166,"line":243},[164,329,246],{"class":170},[164,331,199],{"class":174},[164,333,334,336],{"class":166,"line":251},[164,335,254],{"class":174},[164,337,257],{"class":178},[164,339,341,344],{"class":166,"line":340},10,[164,342,343],{"class":170},"  ingress",[164,345,199],{"class":174},[164,347,349,351,354],{"class":166,"line":348},11,[164,350,254],{"class":174},[164,352,353],{"class":170}," from",[164,355,199],{"class":174},[164,357,359,362,365],{"class":166,"line":358},12,[164,360,361],{"class":174},"        -",[164,363,364],{"class":170}," namespaceSelector",[164,366,199],{"class":174},[164,368,370,373],{"class":166,"line":369},13,[164,371,372],{"class":170},"            matchLabels",[164,374,199],{"class":174},[164,376,378,381,383],{"class":166,"line":377},14,[164,379,380],{"class":170},"              kubernetes.io\u002Fmetadata.name",[164,382,175],{"class":174},[164,384,385],{"class":178}," traefik\n",[14,387,388,391],{},[60,389,390],{},"3. Allow inbound from the Hosted Instances"," so Node-RED instances can reach the MQTT broker, core app and the private registry:",[155,393,395],{"className":157,"code":394,"language":159,"meta":160,"style":160},"apiVersion: networking.k8s.io\u002Fv1\nkind: NetworkPolicy\nmetadata:\n  name: allow-ingress-from-projects\n  namespace: flowfuse\nspec:\n  podSelector: {}\n  policyTypes:\n    - Ingress\n  ingress:\n    - from:\n        - namespaceSelector:\n            matchLabels:\n              kubernetes.io\u002Fmetadata.name: projects\n",[78,396,397,405,413,419,428,436,442,450,456,462,468,476,484,490],{"__ignoreMap":160},[164,398,399,401,403],{"class":166,"line":167},[164,400,171],{"class":170},[164,402,175],{"class":174},[164,404,179],{"class":178},[164,406,407,409,411],{"class":166,"line":182},[164,408,185],{"class":170},[164,410,175],{"class":174},[164,412,190],{"class":178},[164,414,415,417],{"class":166,"line":193},[164,416,196],{"class":170},[164,418,199],{"class":174},[164,420,421,423,425],{"class":166,"line":202},[164,422,205],{"class":170},[164,424,175],{"class":174},[164,426,427],{"class":178}," allow-ingress-from-projects\n",[164,429,430,432,434],{"class":166,"line":213},[164,431,216],{"class":170},[164,433,175],{"class":174},[164,435,221],{"class":178},[164,437,438,440],{"class":166,"line":224},[164,439,227],{"class":170},[164,441,199],{"class":174},[164,443,444,446,448],{"class":166,"line":232},[164,445,235],{"class":170},[164,447,175],{"class":174},[164,449,240],{"class":174},[164,451,452,454],{"class":166,"line":243},[164,453,246],{"class":170},[164,455,199],{"class":174},[164,457,458,460],{"class":166,"line":251},[164,459,254],{"class":174},[164,461,257],{"class":178},[164,463,464,466],{"class":166,"line":340},[164,465,343],{"class":170},[164,467,199],{"class":174},[164,469,470,472,474],{"class":166,"line":348},[164,471,254],{"class":174},[164,473,353],{"class":170},[164,475,199],{"class":174},[164,477,478,480,482],{"class":166,"line":358},[164,479,361],{"class":174},[164,481,364],{"class":170},[164,483,199],{"class":174},[164,485,486,488],{"class":166,"line":369},[164,487,372],{"class":170},[164,489,199],{"class":174},[164,491,492,494,496],{"class":166,"line":377},[164,493,380],{"class":170},[164,495,175],{"class":174},[164,497,498],{"class":178}," projects\n",[14,500,501,504],{},[60,502,503],{},"4. Allow traffic between the platform's own components"," in this namespace - the core app connecting to the database, broker and registry, plus broker clustering. As these are all trusted first-party components, we allow intra-namespace traffic:",[155,506,508],{"className":157,"code":507,"language":159,"meta":160,"style":160},"apiVersion: networking.k8s.io\u002Fv1\nkind: NetworkPolicy\nmetadata:\n  name: allow-intra-namespace\n  namespace: flowfuse\nspec:\n  podSelector: {}\n  policyTypes:\n    - Ingress\n  ingress:\n    - from:\n        - namespaceSelector:\n            matchLabels:\n              kubernetes.io\u002Fmetadata.name: flowfuse\n",[78,509,510,518,526,532,541,549,555,563,569,575,581,589,597,603],{"__ignoreMap":160},[164,511,512,514,516],{"class":166,"line":167},[164,513,171],{"class":170},[164,515,175],{"class":174},[164,517,179],{"class":178},[164,519,520,522,524],{"class":166,"line":182},[164,521,185],{"class":170},[164,523,175],{"class":174},[164,525,190],{"class":178},[164,527,528,530],{"class":166,"line":193},[164,529,196],{"class":170},[164,531,199],{"class":174},[164,533,534,536,538],{"class":166,"line":202},[164,535,205],{"class":170},[164,537,175],{"class":174},[164,539,540],{"class":178}," allow-intra-namespace\n",[164,542,543,545,547],{"class":166,"line":213},[164,544,216],{"class":170},[164,546,175],{"class":174},[164,548,221],{"class":178},[164,550,551,553],{"class":166,"line":224},[164,552,227],{"class":170},[164,554,199],{"class":174},[164,556,557,559,561],{"class":166,"line":232},[164,558,235],{"class":170},[164,560,175],{"class":174},[164,562,240],{"class":174},[164,564,565,567],{"class":166,"line":243},[164,566,246],{"class":170},[164,568,199],{"class":174},[164,570,571,573],{"class":166,"line":251},[164,572,254],{"class":174},[164,574,257],{"class":178},[164,576,577,579],{"class":166,"line":340},[164,578,343],{"class":170},[164,580,199],{"class":174},[164,582,583,585,587],{"class":166,"line":348},[164,584,254],{"class":174},[164,586,353],{"class":170},[164,588,199],{"class":174},[164,590,591,593,595],{"class":166,"line":358},[164,592,361],{"class":174},[164,594,364],{"class":170},[164,596,199],{"class":174},[164,598,599,601],{"class":166,"line":369},[164,600,372],{"class":170},[164,602,199],{"class":174},[164,604,605,607,609],{"class":166,"line":377},[164,606,380],{"class":170},[164,608,175],{"class":174},[164,610,221],{"class":178},[18,612,614,617],{"className":613},[21,22],[14,615,27],{"className":616},[26],[18,618,620],{"className":619},[31],[14,621,622,623,626,627,630],{},"The Helm chart also ships a ",[78,624,625],{},"flowforge-database-policy"," that permits the core app → database connection when using the embedded database. The ",[78,628,629],{},"allow-intra-namespace"," rule above is a superset of it; keep both if you prefer defence in depth.",[14,632,633,636,637,640,641,644,645,648,649,652,653,656],{},[60,634,635],{},"5. Allow inbound from the EMQX operator"," - The MQTT broker cluster is managed by the EMQX operator, which usually runs in its own namespace (",[78,638,639],{},"emqx-operator"," by default) and polls the broker's management API (port ",[78,642,643],{},"18083",") to set a pod ",[65,646,647],{},"readiness gate",". If this is blocked, the check times out, the readiness gate never turns true, the broker pods are marked ",[78,650,651],{},"NotReady",", their Service endpoints go empty, and every broker client fails to connect with a ",[78,654,655],{},"503"," error response. This rule is required for the operator to manage the broker cluster correctly:",[155,658,660],{"className":157,"code":659,"language":159,"meta":160,"style":160},"apiVersion: networking.k8s.io\u002Fv1\nkind: NetworkPolicy\nmetadata:\n  name: allow-ingress-from-emqx-operator\n  namespace: flowfuse\nspec:\n  podSelector:\n    matchLabels:\n      apps.emqx.io\u002Finstance: emqx\n  policyTypes:\n    - Ingress\n  ingress:\n    - from:\n        - namespaceSelector:\n            matchLabels:\n              kubernetes.io\u002Fmetadata.name: emqx-operator\n      ports:\n        - protocol: TCP\n          port: 18083\n",[78,661,662,670,678,684,693,701,707,713,720,730,736,742,748,756,764,771,781,789,802],{"__ignoreMap":160},[164,663,664,666,668],{"class":166,"line":167},[164,665,171],{"class":170},[164,667,175],{"class":174},[164,669,179],{"class":178},[164,671,672,674,676],{"class":166,"line":182},[164,673,185],{"class":170},[164,675,175],{"class":174},[164,677,190],{"class":178},[164,679,680,682],{"class":166,"line":193},[164,681,196],{"class":170},[164,683,199],{"class":174},[164,685,686,688,690],{"class":166,"line":202},[164,687,205],{"class":170},[164,689,175],{"class":174},[164,691,692],{"class":178}," allow-ingress-from-emqx-operator\n",[164,694,695,697,699],{"class":166,"line":213},[164,696,216],{"class":170},[164,698,175],{"class":174},[164,700,221],{"class":178},[164,702,703,705],{"class":166,"line":224},[164,704,227],{"class":170},[164,706,199],{"class":174},[164,708,709,711],{"class":166,"line":232},[164,710,235],{"class":170},[164,712,199],{"class":174},[164,714,715,718],{"class":166,"line":243},[164,716,717],{"class":170},"    matchLabels",[164,719,199],{"class":174},[164,721,722,725,727],{"class":166,"line":251},[164,723,724],{"class":170},"      apps.emqx.io\u002Finstance",[164,726,175],{"class":174},[164,728,729],{"class":178}," emqx\n",[164,731,732,734],{"class":166,"line":340},[164,733,246],{"class":170},[164,735,199],{"class":174},[164,737,738,740],{"class":166,"line":348},[164,739,254],{"class":174},[164,741,257],{"class":178},[164,743,744,746],{"class":166,"line":358},[164,745,343],{"class":170},[164,747,199],{"class":174},[164,749,750,752,754],{"class":166,"line":369},[164,751,254],{"class":174},[164,753,353],{"class":170},[164,755,199],{"class":174},[164,757,758,760,762],{"class":166,"line":377},[164,759,361],{"class":174},[164,761,364],{"class":170},[164,763,199],{"class":174},[164,765,767,769],{"class":166,"line":766},15,[164,768,372],{"class":170},[164,770,199],{"class":174},[164,772,774,776,778],{"class":166,"line":773},16,[164,775,380],{"class":170},[164,777,175],{"class":174},[164,779,780],{"class":178}," emqx-operator\n",[164,782,784,787],{"class":166,"line":783},17,[164,785,786],{"class":170},"      ports",[164,788,199],{"class":174},[164,790,792,794,797,799],{"class":166,"line":791},18,[164,793,361],{"class":174},[164,795,796],{"class":170}," protocol",[164,798,175],{"class":174},[164,800,801],{"class":178}," TCP\n",[164,803,805,808,810],{"class":166,"line":804},19,[164,806,807],{"class":170},"          port",[164,809,175],{"class":174},[164,811,813],{"class":812},"sbssI"," 18083\n",[18,815,817,820],{"className":816},[21,22],[14,818,27],{"className":819},[26],[18,821,823],{"className":822},[31],[14,824,825],{},"The same pattern applies to any other operator, admission webhook, or metrics controller that must reach pods in this namespace: allow ingress from its namespace, or its readiness\u002Freconcile checks will silently break your Services. If a Service unexpectedly loses its endpoints after applying policies, check the managing controller's logs for connection timeouts.",[70,827,829,830,147],{"id":828},"hosted-instances-namespace-projects","Hosted Instances namespace (",[78,831,106],{},[14,833,834,835,838],{},"This namespace runs untrusted user flows, so we deny ",[60,836,837],{},"both"," directions by default and add back only what an instance legitimately needs.",[14,840,841],{},[60,842,843],{},"1. Deny all inbound and outbound traffic:",[155,845,847],{"className":157,"code":846,"language":159,"meta":160,"style":160},"apiVersion: networking.k8s.io\u002Fv1\nkind: NetworkPolicy\nmetadata:\n  name: default-deny-all\n  namespace: projects\nspec:\n  podSelector: {}\n  policyTypes:\n    - Ingress\n    - Egress\n",[78,848,849,857,865,871,880,888,894,902,908,914],{"__ignoreMap":160},[164,850,851,853,855],{"class":166,"line":167},[164,852,171],{"class":170},[164,854,175],{"class":174},[164,856,179],{"class":178},[164,858,859,861,863],{"class":166,"line":182},[164,860,185],{"class":170},[164,862,175],{"class":174},[164,864,190],{"class":178},[164,866,867,869],{"class":166,"line":193},[164,868,196],{"class":170},[164,870,199],{"class":174},[164,872,873,875,877],{"class":166,"line":202},[164,874,205],{"class":170},[164,876,175],{"class":174},[164,878,879],{"class":178}," default-deny-all\n",[164,881,882,884,886],{"class":166,"line":213},[164,883,216],{"class":170},[164,885,175],{"class":174},[164,887,498],{"class":178},[164,889,890,892],{"class":166,"line":224},[164,891,227],{"class":170},[164,893,199],{"class":174},[164,895,896,898,900],{"class":166,"line":232},[164,897,235],{"class":170},[164,899,175],{"class":174},[164,901,240],{"class":174},[164,903,904,906],{"class":166,"line":243},[164,905,246],{"class":170},[164,907,199],{"class":174},[164,909,910,912],{"class":166,"line":251},[164,911,254],{"class":174},[164,913,257],{"class":178},[164,915,916,918],{"class":166,"line":340},[164,917,254],{"class":174},[164,919,920],{"class":178}," Egress\n",[14,922,923,926,927,929,930,932],{},[60,924,925],{},"Instance isolation comes for free here."," With no rule permitting ",[78,928,106],{}," → ",[78,931,106],{}," traffic, Node-RED instances cannot reach another in either direction. A separate \"deny pod-to-pod\" policy is not needed since a compromised instance already cannot talk to its neighbours.",[14,934,935,938,939,267],{},[60,936,937],{},"2. Allow DNS resolution"," (cluster DNS, usually in ",[78,940,941],{},"kube-system",[155,943,945],{"className":157,"code":944,"language":159,"meta":160,"style":160},"apiVersion: networking.k8s.io\u002Fv1\nkind: NetworkPolicy\nmetadata:\n  name: allow-dns\n  namespace: projects\nspec:\n  podSelector: {}\n  policyTypes:\n    - Egress\n  egress:\n    - to:\n        - namespaceSelector:\n            matchLabels:\n              kubernetes.io\u002Fmetadata.name: kube-system\n      ports:\n        - protocol: UDP\n          port: 53\n        - protocol: TCP\n          port: 53\n",[78,946,947,955,963,969,978,986,992,1000,1006,1012,1019,1028,1036,1042,1051,1057,1068,1077,1087],{"__ignoreMap":160},[164,948,949,951,953],{"class":166,"line":167},[164,950,171],{"class":170},[164,952,175],{"class":174},[164,954,179],{"class":178},[164,956,957,959,961],{"class":166,"line":182},[164,958,185],{"class":170},[164,960,175],{"class":174},[164,962,190],{"class":178},[164,964,965,967],{"class":166,"line":193},[164,966,196],{"class":170},[164,968,199],{"class":174},[164,970,971,973,975],{"class":166,"line":202},[164,972,205],{"class":170},[164,974,175],{"class":174},[164,976,977],{"class":178}," allow-dns\n",[164,979,980,982,984],{"class":166,"line":213},[164,981,216],{"class":170},[164,983,175],{"class":174},[164,985,498],{"class":178},[164,987,988,990],{"class":166,"line":224},[164,989,227],{"class":170},[164,991,199],{"class":174},[164,993,994,996,998],{"class":166,"line":232},[164,995,235],{"class":170},[164,997,175],{"class":174},[164,999,240],{"class":174},[164,1001,1002,1004],{"class":166,"line":243},[164,1003,246],{"class":170},[164,1005,199],{"class":174},[164,1007,1008,1010],{"class":166,"line":251},[164,1009,254],{"class":174},[164,1011,920],{"class":178},[164,1013,1014,1017],{"class":166,"line":340},[164,1015,1016],{"class":170},"  egress",[164,1018,199],{"class":174},[164,1020,1021,1023,1026],{"class":166,"line":348},[164,1022,254],{"class":174},[164,1024,1025],{"class":170}," to",[164,1027,199],{"class":174},[164,1029,1030,1032,1034],{"class":166,"line":358},[164,1031,361],{"class":174},[164,1033,364],{"class":170},[164,1035,199],{"class":174},[164,1037,1038,1040],{"class":166,"line":369},[164,1039,372],{"class":170},[164,1041,199],{"class":174},[164,1043,1044,1046,1048],{"class":166,"line":377},[164,1045,380],{"class":170},[164,1047,175],{"class":174},[164,1049,1050],{"class":178}," kube-system\n",[164,1052,1053,1055],{"class":166,"line":766},[164,1054,786],{"class":170},[164,1056,199],{"class":174},[164,1058,1059,1061,1063,1065],{"class":166,"line":773},[164,1060,361],{"class":174},[164,1062,796],{"class":170},[164,1064,175],{"class":174},[164,1066,1067],{"class":178}," UDP\n",[164,1069,1070,1072,1074],{"class":166,"line":783},[164,1071,807],{"class":170},[164,1073,175],{"class":174},[164,1075,1076],{"class":812}," 53\n",[164,1078,1079,1081,1083,1085],{"class":166,"line":791},[164,1080,361],{"class":174},[164,1082,796],{"class":170},[164,1084,175],{"class":174},[164,1086,801],{"class":178},[164,1088,1089,1091,1093],{"class":166,"line":804},[164,1090,807],{"class":170},[164,1092,175],{"class":174},[164,1094,1076],{"class":812},[14,1096,1097,175],{},[60,1098,1099],{},"3. Allow traffic with the ingress controller",[112,1101,1102,1108],{},[115,1103,1104,1107],{},[60,1105,1106],{},"Ingress:"," users reach the Node-RED editor and dashboards",[115,1109,1110,1113],{},[60,1111,1112],{},"Egress:"," allow a Hosted Instance to reach the core app and private npm registry through the ingress controller",[155,1115,1117],{"className":157,"code":1116,"language":159,"meta":160,"style":160},"apiVersion: networking.k8s.io\u002Fv1\nkind: NetworkPolicy\nmetadata:\n  name: allow-traefik\n  namespace: projects\nspec:\n  podSelector: {}\n  policyTypes:\n    - Ingress\n    - Egress\n  ingress:\n    - from:\n        - namespaceSelector:\n            matchLabels:\n              kubernetes.io\u002Fmetadata.name: traefik\n  egress:\n    - to:\n        - namespaceSelector:\n            matchLabels:\n              kubernetes.io\u002Fmetadata.name: traefik\n",[78,1118,1119,1127,1135,1141,1150,1158,1164,1172,1178,1184,1190,1196,1204,1212,1218,1226,1232,1240,1248,1254],{"__ignoreMap":160},[164,1120,1121,1123,1125],{"class":166,"line":167},[164,1122,171],{"class":170},[164,1124,175],{"class":174},[164,1126,179],{"class":178},[164,1128,1129,1131,1133],{"class":166,"line":182},[164,1130,185],{"class":170},[164,1132,175],{"class":174},[164,1134,190],{"class":178},[164,1136,1137,1139],{"class":166,"line":193},[164,1138,196],{"class":170},[164,1140,199],{"class":174},[164,1142,1143,1145,1147],{"class":166,"line":202},[164,1144,205],{"class":170},[164,1146,175],{"class":174},[164,1148,1149],{"class":178}," allow-traefik\n",[164,1151,1152,1154,1156],{"class":166,"line":213},[164,1153,216],{"class":170},[164,1155,175],{"class":174},[164,1157,498],{"class":178},[164,1159,1160,1162],{"class":166,"line":224},[164,1161,227],{"class":170},[164,1163,199],{"class":174},[164,1165,1166,1168,1170],{"class":166,"line":232},[164,1167,235],{"class":170},[164,1169,175],{"class":174},[164,1171,240],{"class":174},[164,1173,1174,1176],{"class":166,"line":243},[164,1175,246],{"class":170},[164,1177,199],{"class":174},[164,1179,1180,1182],{"class":166,"line":251},[164,1181,254],{"class":174},[164,1183,257],{"class":178},[164,1185,1186,1188],{"class":166,"line":340},[164,1187,254],{"class":174},[164,1189,920],{"class":178},[164,1191,1192,1194],{"class":166,"line":348},[164,1193,343],{"class":170},[164,1195,199],{"class":174},[164,1197,1198,1200,1202],{"class":166,"line":358},[164,1199,254],{"class":174},[164,1201,353],{"class":170},[164,1203,199],{"class":174},[164,1205,1206,1208,1210],{"class":166,"line":369},[164,1207,361],{"class":174},[164,1209,364],{"class":170},[164,1211,199],{"class":174},[164,1213,1214,1216],{"class":166,"line":377},[164,1215,372],{"class":170},[164,1217,199],{"class":174},[164,1219,1220,1222,1224],{"class":166,"line":766},[164,1221,380],{"class":170},[164,1223,175],{"class":174},[164,1225,385],{"class":178},[164,1227,1228,1230],{"class":166,"line":773},[164,1229,1016],{"class":170},[164,1231,199],{"class":174},[164,1233,1234,1236,1238],{"class":166,"line":783},[164,1235,254],{"class":174},[164,1237,1025],{"class":170},[164,1239,199],{"class":174},[164,1241,1242,1244,1246],{"class":166,"line":791},[164,1243,361],{"class":174},[164,1245,364],{"class":170},[164,1247,199],{"class":174},[164,1249,1250,1252],{"class":166,"line":804},[164,1251,372],{"class":170},[164,1253,199],{"class":174},[164,1255,1257,1259,1261],{"class":166,"line":1256},20,[164,1258,380],{"class":170},[164,1260,175],{"class":174},[164,1262,385],{"class":178},[14,1264,1265,1268],{},[60,1266,1267],{},"4. Allow inbound from the platform"," so the core app can manage and health-check instances:",[155,1270,1272],{"className":157,"code":1271,"language":159,"meta":160,"style":160},"apiVersion: networking.k8s.io\u002Fv1\nkind: NetworkPolicy\nmetadata:\n  name: allow-ingress-from-flowfuse\n  namespace: projects\nspec:\n  podSelector: {}\n  policyTypes:\n    - Ingress\n  ingress:\n    - from:\n        - namespaceSelector:\n            matchLabels:\n              kubernetes.io\u002Fmetadata.name: flowfuse\n",[78,1273,1274,1282,1290,1296,1305,1313,1319,1327,1333,1339,1345,1353,1361,1367],{"__ignoreMap":160},[164,1275,1276,1278,1280],{"class":166,"line":167},[164,1277,171],{"class":170},[164,1279,175],{"class":174},[164,1281,179],{"class":178},[164,1283,1284,1286,1288],{"class":166,"line":182},[164,1285,185],{"class":170},[164,1287,175],{"class":174},[164,1289,190],{"class":178},[164,1291,1292,1294],{"class":166,"line":193},[164,1293,196],{"class":170},[164,1295,199],{"class":174},[164,1297,1298,1300,1302],{"class":166,"line":202},[164,1299,205],{"class":170},[164,1301,175],{"class":174},[164,1303,1304],{"class":178}," allow-ingress-from-flowfuse\n",[164,1306,1307,1309,1311],{"class":166,"line":213},[164,1308,216],{"class":170},[164,1310,175],{"class":174},[164,1312,498],{"class":178},[164,1314,1315,1317],{"class":166,"line":224},[164,1316,227],{"class":170},[164,1318,199],{"class":174},[164,1320,1321,1323,1325],{"class":166,"line":232},[164,1322,235],{"class":170},[164,1324,175],{"class":174},[164,1326,240],{"class":174},[164,1328,1329,1331],{"class":166,"line":243},[164,1330,246],{"class":170},[164,1332,199],{"class":174},[164,1334,1335,1337],{"class":166,"line":251},[164,1336,254],{"class":174},[164,1338,257],{"class":178},[164,1340,1341,1343],{"class":166,"line":340},[164,1342,343],{"class":170},[164,1344,199],{"class":174},[164,1346,1347,1349,1351],{"class":166,"line":348},[164,1348,254],{"class":174},[164,1350,353],{"class":170},[164,1352,199],{"class":174},[164,1354,1355,1357,1359],{"class":166,"line":358},[164,1356,361],{"class":174},[164,1358,364],{"class":170},[164,1360,199],{"class":174},[164,1362,1363,1365],{"class":166,"line":369},[164,1364,372],{"class":170},[164,1366,199],{"class":174},[164,1368,1369,1371,1373],{"class":166,"line":377},[164,1370,380],{"class":170},[164,1372,175],{"class":174},[164,1374,221],{"class":178},[14,1376,1377,1380,1381,1384],{},[60,1378,1379],{},"5. Allow outbound to the platform services"," - the MQTT broker, core app and private npm registry. Instances ",[60,1382,1383],{},"should not"," connect to the database directly, so it is deliberately not allowed:",[155,1386,1388],{"className":157,"code":1387,"language":159,"meta":160,"style":160},"apiVersion: networking.k8s.io\u002Fv1\nkind: NetworkPolicy\nmetadata:\n  name: allow-egress-to-flowfuse\n  namespace: projects\nspec:\n  podSelector: {}\n  policyTypes:\n    - Egress\n  egress:\n    - to:\n        - namespaceSelector:\n            matchLabels:\n              kubernetes.io\u002Fmetadata.name: flowfuse\n      ports:\n        - protocol: TCP\n          port: 1883   # MQTT broker\n        - protocol: TCP\n          port: 1884   # MQTT over WebSocket\n        - protocol: TCP\n          port: 3000   # core app pod port\n        - protocol: TCP\n          port: 4873   # private npm registry\n",[78,1389,1390,1398,1406,1412,1421,1429,1435,1443,1449,1455,1461,1469,1477,1483,1491,1497,1507,1520,1530,1542,1552,1565,1576],{"__ignoreMap":160},[164,1391,1392,1394,1396],{"class":166,"line":167},[164,1393,171],{"class":170},[164,1395,175],{"class":174},[164,1397,179],{"class":178},[164,1399,1400,1402,1404],{"class":166,"line":182},[164,1401,185],{"class":170},[164,1403,175],{"class":174},[164,1405,190],{"class":178},[164,1407,1408,1410],{"class":166,"line":193},[164,1409,196],{"class":170},[164,1411,199],{"class":174},[164,1413,1414,1416,1418],{"class":166,"line":202},[164,1415,205],{"class":170},[164,1417,175],{"class":174},[164,1419,1420],{"class":178}," allow-egress-to-flowfuse\n",[164,1422,1423,1425,1427],{"class":166,"line":213},[164,1424,216],{"class":170},[164,1426,175],{"class":174},[164,1428,498],{"class":178},[164,1430,1431,1433],{"class":166,"line":224},[164,1432,227],{"class":170},[164,1434,199],{"class":174},[164,1436,1437,1439,1441],{"class":166,"line":232},[164,1438,235],{"class":170},[164,1440,175],{"class":174},[164,1442,240],{"class":174},[164,1444,1445,1447],{"class":166,"line":243},[164,1446,246],{"class":170},[164,1448,199],{"class":174},[164,1450,1451,1453],{"class":166,"line":251},[164,1452,254],{"class":174},[164,1454,920],{"class":178},[164,1456,1457,1459],{"class":166,"line":340},[164,1458,1016],{"class":170},[164,1460,199],{"class":174},[164,1462,1463,1465,1467],{"class":166,"line":348},[164,1464,254],{"class":174},[164,1466,1025],{"class":170},[164,1468,199],{"class":174},[164,1470,1471,1473,1475],{"class":166,"line":358},[164,1472,361],{"class":174},[164,1474,364],{"class":170},[164,1476,199],{"class":174},[164,1478,1479,1481],{"class":166,"line":369},[164,1480,372],{"class":170},[164,1482,199],{"class":174},[164,1484,1485,1487,1489],{"class":166,"line":377},[164,1486,380],{"class":170},[164,1488,175],{"class":174},[164,1490,221],{"class":178},[164,1492,1493,1495],{"class":166,"line":766},[164,1494,786],{"class":170},[164,1496,199],{"class":174},[164,1498,1499,1501,1503,1505],{"class":166,"line":773},[164,1500,361],{"class":174},[164,1502,796],{"class":170},[164,1504,175],{"class":174},[164,1506,801],{"class":178},[164,1508,1509,1511,1513,1516],{"class":166,"line":783},[164,1510,807],{"class":170},[164,1512,175],{"class":174},[164,1514,1515],{"class":812}," 1883",[164,1517,1519],{"class":1518},"sHwdD","   # MQTT broker\n",[164,1521,1522,1524,1526,1528],{"class":166,"line":791},[164,1523,361],{"class":174},[164,1525,796],{"class":170},[164,1527,175],{"class":174},[164,1529,801],{"class":178},[164,1531,1532,1534,1536,1539],{"class":166,"line":804},[164,1533,807],{"class":170},[164,1535,175],{"class":174},[164,1537,1538],{"class":812}," 1884",[164,1540,1541],{"class":1518},"   # MQTT over WebSocket\n",[164,1543,1544,1546,1548,1550],{"class":166,"line":1256},[164,1545,361],{"class":174},[164,1547,796],{"class":170},[164,1549,175],{"class":174},[164,1551,801],{"class":178},[164,1553,1555,1557,1559,1562],{"class":166,"line":1554},21,[164,1556,807],{"class":170},[164,1558,175],{"class":174},[164,1560,1561],{"class":812}," 3000",[164,1563,1564],{"class":1518},"   # core app pod port\n",[164,1566,1568,1570,1572,1574],{"class":166,"line":1567},22,[164,1569,361],{"class":174},[164,1571,796],{"class":170},[164,1573,175],{"class":174},[164,1575,801],{"class":178},[164,1577,1579,1581,1583,1586],{"class":166,"line":1578},23,[164,1580,807],{"class":170},[164,1582,175],{"class":174},[164,1584,1585],{"class":812}," 4873",[164,1587,1588],{"class":1518},"   # private npm registry\n",[14,1590,1591,1594,1595,1598,1599,1602],{},[60,1592,1593],{},"6. (Optional) Allow outbound to the public internet."," Thanks to the ",[78,1596,1597],{},"default-deny-all"," policy, instances ",[60,1600,1601],{},"do not have"," access to the Internet. If your flows need to call external APIs, add the rule below. It allows outbound to the internet while excluding private ranges:",[155,1604,1606],{"className":157,"code":1605,"language":159,"meta":160,"style":160},"apiVersion: networking.k8s.io\u002Fv1\nkind: NetworkPolicy\nmetadata:\n  name: allow-egress-external\n  namespace: projects\nspec:\n  podSelector: {}\n  policyTypes:\n    - Egress\n  egress:\n    - to:\n        - ipBlock:\n            cidr: 0.0.0.0\u002F0\n            except:\n              - 10.0.0.0\u002F8         # RFC1918 private range\n              - 172.16.0.0\u002F12      # RFC1918 private range\n              - 192.168.0.0\u002F16     # RFC1918 private range\n              - 169.254.0.0\u002F16     # link-local: blocks the cloud metadata endpoint (169.254.169.254) and node-local DNS\n              - 100.64.0.0\u002F10      # CGNAT range used internally by some managed clusters (GKE, EKS) \n              \n      ports:\n        - protocol: TCP\n          port: 443\n        - protocol: TCP\n          port: 80\n",[78,1607,1608,1616,1624,1630,1639,1647,1653,1661,1667,1673,1679,1687,1696,1706,1713,1724,1734,1744,1754,1764,1770,1776,1786,1795,1806],{"__ignoreMap":160},[164,1609,1610,1612,1614],{"class":166,"line":167},[164,1611,171],{"class":170},[164,1613,175],{"class":174},[164,1615,179],{"class":178},[164,1617,1618,1620,1622],{"class":166,"line":182},[164,1619,185],{"class":170},[164,1621,175],{"class":174},[164,1623,190],{"class":178},[164,1625,1626,1628],{"class":166,"line":193},[164,1627,196],{"class":170},[164,1629,199],{"class":174},[164,1631,1632,1634,1636],{"class":166,"line":202},[164,1633,205],{"class":170},[164,1635,175],{"class":174},[164,1637,1638],{"class":178}," allow-egress-external\n",[164,1640,1641,1643,1645],{"class":166,"line":213},[164,1642,216],{"class":170},[164,1644,175],{"class":174},[164,1646,498],{"class":178},[164,1648,1649,1651],{"class":166,"line":224},[164,1650,227],{"class":170},[164,1652,199],{"class":174},[164,1654,1655,1657,1659],{"class":166,"line":232},[164,1656,235],{"class":170},[164,1658,175],{"class":174},[164,1660,240],{"class":174},[164,1662,1663,1665],{"class":166,"line":243},[164,1664,246],{"class":170},[164,1666,199],{"class":174},[164,1668,1669,1671],{"class":166,"line":251},[164,1670,254],{"class":174},[164,1672,920],{"class":178},[164,1674,1675,1677],{"class":166,"line":340},[164,1676,1016],{"class":170},[164,1678,199],{"class":174},[164,1680,1681,1683,1685],{"class":166,"line":348},[164,1682,254],{"class":174},[164,1684,1025],{"class":170},[164,1686,199],{"class":174},[164,1688,1689,1691,1694],{"class":166,"line":358},[164,1690,361],{"class":174},[164,1692,1693],{"class":170}," ipBlock",[164,1695,199],{"class":174},[164,1697,1698,1701,1703],{"class":166,"line":369},[164,1699,1700],{"class":170},"            cidr",[164,1702,175],{"class":174},[164,1704,1705],{"class":178}," 0.0.0.0\u002F0\n",[164,1707,1708,1711],{"class":166,"line":377},[164,1709,1710],{"class":170},"            except",[164,1712,199],{"class":174},[164,1714,1715,1718,1721],{"class":166,"line":766},[164,1716,1717],{"class":174},"              -",[164,1719,1720],{"class":178}," 10.0.0.0\u002F8",[164,1722,1723],{"class":1518},"         # RFC1918 private range\n",[164,1725,1726,1728,1731],{"class":166,"line":773},[164,1727,1717],{"class":174},[164,1729,1730],{"class":178}," 172.16.0.0\u002F12",[164,1732,1733],{"class":1518},"      # RFC1918 private range\n",[164,1735,1736,1738,1741],{"class":166,"line":783},[164,1737,1717],{"class":174},[164,1739,1740],{"class":178}," 192.168.0.0\u002F16",[164,1742,1743],{"class":1518},"     # RFC1918 private range\n",[164,1745,1746,1748,1751],{"class":166,"line":791},[164,1747,1717],{"class":174},[164,1749,1750],{"class":178}," 169.254.0.0\u002F16",[164,1752,1753],{"class":1518},"     # link-local: blocks the cloud metadata endpoint (169.254.169.254) and node-local DNS\n",[164,1755,1756,1758,1761],{"class":166,"line":804},[164,1757,1717],{"class":174},[164,1759,1760],{"class":178}," 100.64.0.0\u002F10",[164,1762,1763],{"class":1518},"      # CGNAT range used internally by some managed clusters (GKE, EKS) \n",[164,1765,1766],{"class":166,"line":1256},[164,1767,1769],{"class":1768},"sTEyZ","              \n",[164,1771,1772,1774],{"class":166,"line":1554},[164,1773,786],{"class":170},[164,1775,199],{"class":174},[164,1777,1778,1780,1782,1784],{"class":166,"line":1567},[164,1779,361],{"class":174},[164,1781,796],{"class":170},[164,1783,175],{"class":174},[164,1785,801],{"class":178},[164,1787,1788,1790,1792],{"class":166,"line":1578},[164,1789,807],{"class":170},[164,1791,175],{"class":174},[164,1793,1794],{"class":812}," 443\n",[164,1796,1798,1800,1802,1804],{"class":166,"line":1797},24,[164,1799,361],{"class":174},[164,1801,796],{"class":170},[164,1803,175],{"class":174},[164,1805,801],{"class":178},[164,1807,1809,1811,1813],{"class":166,"line":1808},25,[164,1810,807],{"class":170},[164,1812,175],{"class":174},[164,1814,1815],{"class":812}," 80\n",[14,1817,1818,1819,1822,1823,1826,1827,1830,1831,1834,1835,1837,1838,1841,1842,1845],{},"The ",[78,1820,1821],{},"except"," list is what makes this rule safe: it blocks instances from reaching internal networks even while internet access is open. Note the ",[78,1824,1825],{},"169.254.0.0\u002F16"," entry in particular as it blocks the cloud metadata endpoint (",[78,1828,1829],{},"169.254.169.254","), which would otherwise let a compromised flow retrieve the node's cloud IAM credentials. ",[78,1832,1833],{},"100.64.0.0\u002F10"," covers the CGNAT range that some managed Kubernetes providers use internally. Include it if your cluster does. Note that excluding ",[78,1836,1825],{}," also blocks node-local DNS cache, which runs on a link-local address. If your cluster uses it, add an egress rule allowing UDP\u002FTCP ",[78,1839,1840],{},"53"," to that address (commonly ",[78,1843,1844],{},"169.254.20.10",") so DNS keeps resolving.",[36,1847,1849],{"id":1848},"tls-for-ingress","TLS for Ingress",[14,1851,1852],{},"Without TLS, all traffic between users and the platform, including login credentials, session cookies, API tokens and flow data, travels in plaintext. Anyone able to observe the network path (a compromised router, a shared Wi-Fi network, a malicious intermediary) can read or tamper with it. Enabling TLS encrypts this traffic and lets clients verify they are talking to the genuine platform, protecting against eavesdropping and man-in-the-middle attacks. Serving the platform over HTTPS is a baseline requirement for any production deployment.",[14,1854,1855,1856,1862],{},"FlowFuse supports TLS termination either at a cloud Load Balancer or at the Kubernetes Ingress Controller (via ",[83,1857,1861],{"href":1858,"rel":1859},"https:\u002F\u002Fcert-manager.io\u002Fdocs\u002F",[1860],"nofollow","Cert-Manager","). Full configuration steps are in the installation guide:",[112,1864,1865],{},[115,1866,1867],{},[83,1868,1870],{"href":1869},"\u002Fdocs\u002Finstall\u002Fkubernetes#i-would-like-to-secure-the-platform-with-https-how-can-i-do-that","I would like to secure the platform with HTTPS, how can I do that?",[36,1872,1874],{"id":1873},"database-hardening","Database Hardening",[14,1876,1877],{},"FlowFuse stores all its data in a PostgreSQL database. The database is a critical component of the platform, and if it is compromised, an attacker can read or modify all data. The following recommendations reduce the risk of compromise and limit the impact if it does happen.",[70,1879,1881],{"id":1880},"use-a-dedicated-least-privilege-database-user","Use a dedicated, least-privilege database user",[14,1883,1884,1885,1888],{},"The FlowFuse application should connect using a dedicated database user that owns only its own database — never the PostgreSQL superuser (",[78,1886,1887],{},"postgres","). If the application's credentials are leaked, a scoped user limits the blast radius to the FlowFuse database rather than the entire database server.",[14,1890,1891],{},"Create a dedicated user and database, for example:",[155,1893,1897],{"className":1894,"code":1895,"language":1896,"meta":160,"style":160},"language-sql shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","CREATE USER flowfuse WITH PASSWORD 'a-strong-generated-password';\nCREATE DATABASE flowforge OWNER flowfuse;\n","sql",[78,1898,1899,1904],{"__ignoreMap":160},[164,1900,1901],{"class":166,"line":167},[164,1902,1903],{},"CREATE USER flowfuse WITH PASSWORD 'a-strong-generated-password';\n",[164,1905,1906],{"class":166,"line":182},[164,1907,1908],{},"CREATE DATABASE flowforge OWNER flowfuse;\n",[14,1910,1911,1912,1917,1918,1921],{},"Then configure FlowFuse to connect with these credentials. See ",[83,1913,1916],{"href":1914,"rel":1915},"https:\u002F\u002Fflowfuse.com\u002Fdocs\u002Finstall\u002Fkubernetes\u002F#how-to-use-external-database-server%3F",[1860],"How to use external database server?"," for how to configure the connection in ",[78,1919,1920],{},"customization.yml",".",[14,1923,1924],{},"Additional recommendations:",[112,1926,1927,1932,1938],{},[115,1928,1929],{},[60,1930,1931],{},"Use a strong, randomly generated password",[115,1933,1934,1937],{},[60,1935,1936],{},"Require TLS for database connections"," so credentials and data are encrypted in transit between the platform and the database",[115,1939,1940,1943,1944,1947],{},[60,1941,1942],{},"Restrict network access"," to the database so only the FlowFuse platform can reach it (see ",[83,1945,39],{"href":1946},"#network-policies",", or your cloud provider's firewall \u002F security group rules for managed databases)",[70,1949,1951],{"id":1950},"backups","Backups",[14,1953,1954],{},"Regular backups protect against data loss from accidental deletion, corruption, or a failed upgrade. A hardened deployment is not complete without a tested backup strategy.",[112,1956,1957,1963],{},[115,1958,1959,1962],{},[60,1960,1961],{},"External \u002F managed database:"," use your database provider's backup and point-in-time-recovery features",[115,1964,1965,1968,1969,1972,1973,1976,1977,1980,1981,1984,1985],{},[60,1966,1967],{},"Embedded database:"," if you use the Helm chart's internal PostgreSQL (",[78,1970,1971],{},"forge.localPostgresql: true","), you can schedule backups with a Kubernetes CronJob running ",[78,1974,1975],{},"pg_dump",". A ready-to-use ",[78,1978,1979],{},"CronJob"," + ",[78,1982,1983],{},"PersistentVolumeClaim"," example is provided in the installation guide: ",[83,1986,1989],{"href":1987,"rel":1988},"https:\u002F\u002Fflowfuse.com\u002Fdocs\u002Finstall\u002Fkubernetes\u002F#how-to-backup-embedded-database%3F",[1860],"How to backup embedded database?",[18,1991,1993,1996],{"className":1992},[21,49],[14,1994,53],{"className":1995},[26],[18,1997,1999],{"className":1998},[31],[14,2000,2001,2004],{},[60,2002,2003],{},"Test your restores."," A backup is only useful if it can be restored. Periodically verify that you can restore from a backup into a clean database.",[36,2006,2008],{"id":2007},"rbac-role-based-access-control","RBAC (Role-Based Access Control)",[14,2010,2011,2012,2015,2016,2019,2020,2023,2024,2023,2027,2023,2030,2033,2034,2037],{},"Kubernetes RBAC controls ",[65,2013,2014],{},"who"," (users, groups, service accounts) can perform ",[65,2017,2018],{},"what"," actions (verbs like ",[78,2021,2022],{},"get",", ",[78,2025,2026],{},"list",[78,2028,2029],{},"create",[78,2031,2032],{},"delete",") on ",[65,2035,2036],{},"which"," resources. RBAC is the primary mechanism for enforcing least privilege inside the cluster.",[14,2039,2040],{},"The core objects are:",[112,2042,2043,2057],{},[115,2044,2045,2048,2049,2052,2053,2056],{},[60,2046,2047],{},"Role \u002F ClusterRole"," - a set of permissions. A ",[78,2050,2051],{},"Role"," is namespace-scoped; a ",[78,2054,2055],{},"ClusterRole"," applies cluster-wide.",[115,2058,2059,2062],{},[60,2060,2061],{},"RoleBinding \u002F ClusterRoleBinding"," - grants a Role or ClusterRole to a subject (user, group or service account).",[70,2064,2066],{"id":2065},"least-privilege-principles","Least-privilege principles",[112,2068,2069,2081,2091,2103],{},[115,2070,2071,2074,2075,2023,2078,147],{},[60,2072,2073],{},"Grant the minimum."," Give each user and service account only the permissions they actually need, scoped to the narrowest namespace and resource set that works. Avoid broad wildcards (",[78,2076,2077],{},"verbs: [\"*\"]",[78,2079,2080],{},"resources: [\"*\"]",[115,2082,2083,2090],{},[60,2084,2085,2086,2089],{},"Never grant ",[78,2087,2088],{},"cluster-admin"," casually."," Reserve it for a small number of trusted administrators, day-to-day operations rarely need it",[115,2092,2093,2102],{},[60,2094,2095,2096,2098,2099,2101],{},"Prefer namespaced ",[78,2097,2051],{},"s over ",[78,2100,2055],{},"s"," unless a permission genuinely must span the whole cluster",[115,2104,2105,2108,2109,2112],{},[60,2106,2107],{},"Audit regularly."," Review bindings periodically and remove access that is no longer needed. Command like ",[78,2110,2111],{},"kubectl auth can-i --list"," may help you inspect effective permissions",[70,2114,2116],{"id":2115},"example-a-read-only-namespaced-role","Example: a read-only namespaced Role",[155,2118,2120],{"className":157,"code":2119,"language":159,"meta":160,"style":160},"apiVersion: rbac.authorization.k8s.io\u002Fv1\nkind: Role\nmetadata:\n  namespace: flowfuse\n  name: pod-reader\nrules:\n  - apiGroups: [\"\"]\n    resources: [\"pods\", \"pods\u002Flog\"]\n    verbs: [\"get\", \"list\", \"watch\"]\n---\napiVersion: rbac.authorization.k8s.io\u002Fv1\nkind: RoleBinding\nmetadata:\n  name: read-pods\n  namespace: flowfuse\nsubjects:\n  - kind: User\n    name: user@example.com\n    apiGroup: rbac.authorization.k8s.io\nroleRef:\n  kind: Role\n  name: pod-reader\n  apiGroup: rbac.authorization.k8s.io\n",[78,2121,2122,2131,2140,2146,2154,2163,2170,2189,2219,2253,2259,2267,2276,2282,2291,2299,2306,2318,2328,2338,2345,2354,2362],{"__ignoreMap":160},[164,2123,2124,2126,2128],{"class":166,"line":167},[164,2125,171],{"class":170},[164,2127,175],{"class":174},[164,2129,2130],{"class":178}," rbac.authorization.k8s.io\u002Fv1\n",[164,2132,2133,2135,2137],{"class":166,"line":182},[164,2134,185],{"class":170},[164,2136,175],{"class":174},[164,2138,2139],{"class":178}," Role\n",[164,2141,2142,2144],{"class":166,"line":193},[164,2143,196],{"class":170},[164,2145,199],{"class":174},[164,2147,2148,2150,2152],{"class":166,"line":202},[164,2149,216],{"class":170},[164,2151,175],{"class":174},[164,2153,221],{"class":178},[164,2155,2156,2158,2160],{"class":166,"line":213},[164,2157,205],{"class":170},[164,2159,175],{"class":174},[164,2161,2162],{"class":178}," pod-reader\n",[164,2164,2165,2168],{"class":166,"line":224},[164,2166,2167],{"class":170},"rules",[164,2169,199],{"class":174},[164,2171,2172,2175,2178,2180,2183,2186],{"class":166,"line":232},[164,2173,2174],{"class":174},"  -",[164,2176,2177],{"class":170}," apiGroups",[164,2179,175],{"class":174},[164,2181,2182],{"class":174}," [",[164,2184,2185],{"class":174},"\"\"",[164,2187,2188],{"class":174},"]\n",[164,2190,2191,2194,2196,2198,2201,2204,2206,2209,2212,2215,2217],{"class":166,"line":243},[164,2192,2193],{"class":170},"    resources",[164,2195,175],{"class":174},[164,2197,2182],{"class":174},[164,2199,2200],{"class":174},"\"",[164,2202,2203],{"class":178},"pods",[164,2205,2200],{"class":174},[164,2207,2208],{"class":174},",",[164,2210,2211],{"class":174}," \"",[164,2213,2214],{"class":178},"pods\u002Flog",[164,2216,2200],{"class":174},[164,2218,2188],{"class":174},[164,2220,2221,2224,2226,2228,2230,2232,2234,2236,2238,2240,2242,2244,2246,2249,2251],{"class":166,"line":251},[164,2222,2223],{"class":170},"    verbs",[164,2225,175],{"class":174},[164,2227,2182],{"class":174},[164,2229,2200],{"class":174},[164,2231,2022],{"class":178},[164,2233,2200],{"class":174},[164,2235,2208],{"class":174},[164,2237,2211],{"class":174},[164,2239,2026],{"class":178},[164,2241,2200],{"class":174},[164,2243,2208],{"class":174},[164,2245,2211],{"class":174},[164,2247,2248],{"class":178},"watch",[164,2250,2200],{"class":174},[164,2252,2188],{"class":174},[164,2254,2255],{"class":166,"line":340},[164,2256,2258],{"class":2257},"sBMFI","---\n",[164,2260,2261,2263,2265],{"class":166,"line":348},[164,2262,171],{"class":170},[164,2264,175],{"class":174},[164,2266,2130],{"class":178},[164,2268,2269,2271,2273],{"class":166,"line":358},[164,2270,185],{"class":170},[164,2272,175],{"class":174},[164,2274,2275],{"class":178}," RoleBinding\n",[164,2277,2278,2280],{"class":166,"line":369},[164,2279,196],{"class":170},[164,2281,199],{"class":174},[164,2283,2284,2286,2288],{"class":166,"line":377},[164,2285,205],{"class":170},[164,2287,175],{"class":174},[164,2289,2290],{"class":178}," read-pods\n",[164,2292,2293,2295,2297],{"class":166,"line":766},[164,2294,216],{"class":170},[164,2296,175],{"class":174},[164,2298,221],{"class":178},[164,2300,2301,2304],{"class":166,"line":773},[164,2302,2303],{"class":170},"subjects",[164,2305,199],{"class":174},[164,2307,2308,2310,2313,2315],{"class":166,"line":783},[164,2309,2174],{"class":174},[164,2311,2312],{"class":170}," kind",[164,2314,175],{"class":174},[164,2316,2317],{"class":178}," User\n",[164,2319,2320,2323,2325],{"class":166,"line":791},[164,2321,2322],{"class":170},"    name",[164,2324,175],{"class":174},[164,2326,2327],{"class":178}," user@example.com\n",[164,2329,2330,2333,2335],{"class":166,"line":804},[164,2331,2332],{"class":170},"    apiGroup",[164,2334,175],{"class":174},[164,2336,2337],{"class":178}," rbac.authorization.k8s.io\n",[164,2339,2340,2343],{"class":166,"line":1256},[164,2341,2342],{"class":170},"roleRef",[164,2344,199],{"class":174},[164,2346,2347,2350,2352],{"class":166,"line":1554},[164,2348,2349],{"class":170},"  kind",[164,2351,175],{"class":174},[164,2353,2139],{"class":178},[164,2355,2356,2358,2360],{"class":166,"line":1567},[164,2357,205],{"class":170},[164,2359,175],{"class":174},[164,2361,2162],{"class":178},[164,2363,2364,2367,2369],{"class":166,"line":1578},[164,2365,2366],{"class":170},"  apiGroup",[164,2368,175],{"class":174},[164,2370,2337],{"class":178},[14,2372,2373,2374,2377,2378,2380],{},"This grants the user ",[78,2375,2376],{},"user@example.com"," read-only access to pods and their logs in the ",[78,2379,102],{}," namespace - and nothing else.",[36,2382,2384],{"id":2383},"other-high-level-best-practices","Other High-Level Best Practices",[14,2386,2387],{},"The following practices further reduce the attack surface of your cluster:",[112,2389,2390,2396,2402,2418,2424,2430,2436,2442],{},[115,2391,2392,2395],{},[60,2393,2394],{},"Keep Kubernetes and node images patched."," Run a supported Kubernetes version and apply security updates to the control plane, nodes, and container images promptly",[115,2397,2398,2401],{},[60,2399,2400],{},"Manage secrets properly."," Store credentials in Kubernetes Secrets (ideally with encryption at rest enabled, or an external secrets manager such as HashiCorp Vault or a cloud KMS). Never commit secrets to version control",[115,2403,2404,2407,2408,2411,2412,2417],{},[60,2405,2406],{},"Apply Pod Security Standards."," Enforce the ",[78,2409,2410],{},"restricted"," ",[83,2413,2416],{"href":2414,"rel":2415},"https:\u002F\u002Fkubernetes.io\u002Fdocs\u002Fconcepts\u002Fsecurity\u002Fpod-security-standards\u002F",[1860],"Pod Security Standard"," where possible: run containers as non-root, drop unnecessary Linux capabilities, use a read-only root filesystem, and disallow privilege escalation",[115,2419,2420,2423],{},[60,2421,2422],{},"Set resource requests and limits."," CPU and memory limits prevent a single workload — such as a runaway flow — from starving others and provide a defence against resource-exhaustion denial-of-service",[115,2425,2426,2429],{},[60,2427,2428],{},"Enable audit logging."," Kubernetes audit logs record who did what and when, which is essential for detecting and investigating incidents",[115,2431,2432,2435],{},[60,2433,2434],{},"Limit access to the cluster API and nodes."," Restrict the API server to trusted networks, avoid exposing the Kubelet, and disable SSH access to nodes where you can",[115,2437,2438,2441],{},[60,2439,2440],{},"Scan images for vulnerabilities."," Use image scanning in your CI pipeline and admission control to block images with known critical vulnerabilities",[115,2443,2444,2447],{},[60,2445,2446],{},"Use namespaces for isolation."," Separating workloads into namespaces makes RBAC and Network Policies easier to reason about and enforce",[2449,2450,2451],"style",{},"html pre.shiki code .swJcz, html code.shiki .swJcz{--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}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 .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}html pre.shiki code .sHwdD, html code.shiki .sHwdD{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#546E7A;--shiki-default-font-style:italic;--shiki-dark:#676E95;--shiki-dark-font-style:italic}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}",{"title":160,"searchDepth":202,"depth":202,"links":2453},[2454,2461,2462,2466,2470],{"id":38,"depth":182,"text":39,"children":2455},[2456,2457,2459],{"id":72,"depth":193,"text":73},{"id":143,"depth":193,"text":2458},"Core platform namespace (flowfuse)",{"id":828,"depth":193,"text":2460},"Hosted Instances namespace (projects)",{"id":1848,"depth":182,"text":1849},{"id":1873,"depth":182,"text":1874,"children":2463},[2464,2465],{"id":1880,"depth":193,"text":1881},{"id":1950,"depth":193,"text":1951},{"id":2007,"depth":182,"text":2008,"children":2467},[2468,2469],{"id":2065,"depth":193,"text":2066},{"id":2115,"depth":193,"text":2116},{"id":2383,"depth":182,"text":2384},"md",null,{},true,"admin\u002Fhardening\u002Fkubernetes.md","\u002Fdocs\u002Fadmin\u002Fhardening\u002Fkubernetes",{"title":5,"description":16},"docs\u002Fadmin\u002Fhardening\u002Fkubernetes","2026-07-27 10:07:37 +0100","2.33.2","uID5B5GpgDM33p3JOak2HmjL-UK6DgeE5EPsQirj5wc",{"id":2483,"extension":2484,"meta":2485,"sections":2486,"stem":2875,"__hash__":2876},"featureCatalog\u002Ffeature-catalog.yml","yml",{},[2487,2538,2639,2701,2778,2857],{"id":2488,"title":2489,"features":2490},"ai-automation","AI & Automation",[2491,2501,2511,2521,2527,2533],{"id":2492,"title":2493,"description":2494,"docsLink":2495,"changelog":2496,"tiers":2500},"flowfuse-expert-ai","FlowFuse Expert AI","Build industrial apps with agents, and query the state of the factory with an agent. Adapt your current hardware and machines so agentic work can be done against them, without ripping and replacing what's already on the plant floor.","\u002Fdocs\u002Fuser\u002Fexpert\u002F",[2497],{"url":2498,"release":2499},"\u002Fchangelog\u002F2026\u002F02\u002Fff-expert-update-banner\u002F","2.28",{"edge":2474,"hub":2474,"fleet":2474},{"id":2502,"title":2503,"description":2504,"docsLink":2505,"changelog":2506,"subfeature":2474,"showOnPricing":2509,"tiers":2510},"flowfuse-expert-support-mode","Support Mode","Chat-based assistance for FlowFuse and Node-RED, including Node-RED instance management through natural language.","\u002Fdocs\u002Fuser\u002Fexpert\u002Fchat\u002F#support-mode",[2507],{"url":2508,"release":2499},"\u002Fchangelog\u002F2026\u002F02\u002Fff-expert-debug-log-context\u002F",false,{"edge":2474,"hub":2474,"fleet":2474},{"id":2512,"title":2513,"description":2514,"docsLink":2515,"changelog":2516,"subfeature":2474,"showOnPricing":2509,"tiers":2520},"flowfuse-expert-application-building","Application Building","Describe what you want to build and FlowFuse Expert assembles it on your workspace, adding tabs, wiring nodes, and configuring properties.","\u002Fdocs\u002Fuser\u002Fexpert\u002Fchat\u002F",[2517],{"url":2518,"release":2519},"\u002Fchangelog\u002F2026\u002F05\u002Fexpert-application-building\u002F","2.30",{"edge":2474,"hub":2474,"fleet":2474},{"id":2522,"title":2523,"description":2524,"docsLink":2525,"subfeature":2474,"beta":2474,"showOnPricing":2509,"tiers":2526},"flowfuse-expert-insights-mode","Insights Mode","Connects FlowFuse Expert to MCP servers in your Node-RED instances, enabling real-time data queries and actions through a single chat interface.","\u002Fdocs\u002Fuser\u002Fexpert\u002Fchat\u002F#insights-mode",{"edge":2474,"hub":2474,"fleet":2474},{"id":2528,"title":2529,"description":2530,"docsLink":2531,"tiers":2532},"mcp-servers","Agentic Operations","Expose your Node-RED flows as tools an AI agent can call directly, so agents can query the state of the factory or trigger actions without custom integration work.","\u002Fnode-red\u002Fflowfuse\u002Fmcp\u002F",{"edge":2474,"hub":2474,"fleet":2474},{"id":2534,"title":2535,"description":2536,"tiers":2537},"onnx-integration","ONNX Integration","Run trained machine learning models directly in your flows, including on edge hardware, without sending data out to an external inference service.",{"edge":2474,"hub":2474,"fleet":2474},{"id":2539,"title":2540,"features":2541},"build","Build",[2542,2548,2554,2564,2570,2576,2580,2586,2592,2600,2606,2610,2614,2623,2631],{"id":2543,"title":2544,"description":2545,"docsLink":2546,"tiers":2547},"edge-development","Edge Development","Develop and test Node-RED flows directly on edge devices with a remote editor proxy.","\u002Fdocs\u002Fdevice-agent\u002Fquickstart\u002F",{"edge":2474,"hub":2509,"fleet":2474},{"id":2549,"title":2550,"description":2551,"docsLink":2552,"tiers":2553},"private-npm-registry","Custom Node-RED Nodes","Create and manage your own private npm registry for Node-RED nodes, so you can share custom nodes across your team and devices without publishing them publicly.","\u002Fdocs\u002Fuser\u002Fcustom-npm-packages\u002F",{"edge":2474,"hub":2474,"fleet":2474},{"id":2555,"title":2556,"description":2557,"docsLink":2558,"changelog":2559,"tiers":2563},"flowfuse-tables","FlowFuse Tables","A managed PostgreSQL database for every application, so you can store and query structured data without standing up and maintaining your own database.","\u002Fdocs\u002Fuser\u002Fff-tables\u002F",[2560],{"url":2561,"release":2562},"\u002Fchangelog\u002F2026\u002F07\u002Fexpert-tables-automation\u002F","2.33",{"edge":2474,"hub":2474,"fleet":2474},{"id":2565,"title":2566,"description":2567,"docsLink":2568,"tiers":2569},"persistent-files","File Storage","Store and retrieve files from your Node-RED flows, with automatic replication and backup across your devices and hosted instances.","\u002Fdocs\u002Finstall\u002Ffile-storage\u002F",{"edge":2474,"hub":2474,"fleet":2474},{"id":2571,"title":2572,"description":2573,"docsLink":2574,"showOnPricing":2509,"tiers":2575},"persistent-context","Persistent Context","In-memory values defined in a Node-RED flow persist across project restarts and upgrades.","\u002Fdocs\u002Fuser\u002Fpersistent-context\u002F",{"edge":2474,"hub":2474,"fleet":2474},{"id":2577,"title":2578,"showOnPricing":2509,"tiers":2579},"static-assets","Static Assets",{"edge":2474,"hub":2474,"fleet":2474},{"id":2581,"title":2582,"description":2583,"docsLink":2584,"tiers":2585},"team-library","Team Library","Set up standard nodes and flows that can be shared with all team members across your organisation.","\u002Fdocs\u002Fuser\u002Fshared-library\u002F",{"edge":2474,"hub":2474,"fleet":2474},{"id":2587,"title":2588,"description":2589,"docsLink":2590,"tiers":2591},"personalised-multi-user-dashboards","Personalised Multi-User Dashboards","Build applications that provide unique data to each logged-in user using personalised multi-user dashboards.","https:\u002F\u002Fdashboard.flowfuse.com\u002Fuser\u002Fmulti-tenancy.html",{"edge":2474,"hub":2474,"fleet":2474},{"id":2593,"title":2594,"description":2595,"changelog":2596,"subfeature":2474,"showOnPricing":2509,"tiers":2599},"dashboards-view","Dashboards View","Browse and open every dashboard across your team from a dedicated Dashboards view, at both team and application level, without leaving FlowFuse.",[2597],{"url":2598,"release":2562},"\u002Fchangelog\u002F2026\u002F07\u002Fteam-and-application-dashboards\u002F",{"edge":2474,"hub":2474,"fleet":2474},{"id":2601,"title":2602,"description":2603,"docsLink":2604,"tiers":2605},"blueprints-converge","Blueprints","Ready-made starting points for your apps, from cross-team Converge templates to OT and IT specific blueprints.","\u002Fdocs\u002Fuser\u002Fconcepts\u002F#blueprint",{"edge":2474,"hub":2474,"fleet":2474},{"id":2607,"title":2608,"subfeature":2474,"showOnPricing":2509,"tiers":2609},"blueprints-ot-apps","Blueprints - OT APPS",{"edge":2474,"hub":2509,"fleet":2474},{"id":2611,"title":2612,"subfeature":2474,"showOnPricing":2509,"tiers":2613},"blueprints-it-apps","Blueprints - IT APPS",{"edge":2509,"hub":2474,"fleet":2509},{"id":2615,"title":2616,"description":2617,"changelog":2618,"showOnPricing":2509,"tiers":2622},"immersive-editor-snapshots","Snapshot Details in Immersive Editor","View and manage snapshot details directly inside the immersive editor without leaving your editing session.",[2619],{"url":2620,"release":2621},"\u002Fchangelog\u002F2026\u002F03\u002Fsnapshot-detail-modal-immersive-editor\u002F","2.29",{"edge":2474,"hub":2474,"fleet":2474},{"id":2624,"title":2625,"description":2626,"changelog":2627,"showOnPricing":2509,"tiers":2630},"immersive-editor-drawer","Customisable Immersive Editor Drawer","Pin, move, resize, or full-screen the immersive editor drawer. Your preferences are remembered between sessions.",[2628],{"url":2629,"release":2519},"\u002Fchangelog\u002F2026\u002F04\u002Fimmersive-editor-drawer\u002F",{"edge":2474,"hub":2474,"fleet":2474},{"id":2632,"title":2633,"description":2634,"changelog":2635,"showOnPricing":2509,"tiers":2638},"embedded-editor-tab-title","Embedded Editor Browser Tab Title","The browser tab title updates to reflect the active Node-RED canvas tab when working in the embedded editor.",[2636],{"url":2637,"release":2621},"\u002Fchangelog\u002F2026\u002F03\u002Fembedded-editor-tab-title\u002F",{"edge":2474,"hub":2474,"fleet":2474},{"id":2640,"title":2641,"features":2642},"deploy","Deploy",[2643,2649,2658,2664,2670,2676,2682,2688,2693],{"id":2644,"title":2645,"description":2646,"docsLink":2647,"tiers":2648},"hosted-instances","Cloud Instances","Run Node-RED instances managed and hosted by FlowFuse.","\u002Fdocs\u002Fuser\u002Fintroduction\u002F#creating-a-node-red-instance",{"edge":2474,"hub":2474,"fleet":2474},{"id":2650,"title":2651,"description":2652,"docsLink":2653,"changelog":2654,"tiers":2657},"edge-devices","Edge Instances","Deploy and mange your Node-RED instances on edge PLCs and gateways, with full visibility and control from the cloud.","\u002Fdocs\u002Fdevice-agent\u002Fintroduction\u002F",[2655],{"url":2656,"release":2499},"\u002Fchangelog\u002F2026\u002F02\u002Fdevice-agent-nodejs-options\u002F",{"edge":2474,"hub":2509,"fleet":2474},{"id":2659,"title":2660,"description":2661,"docsLink":2662,"tiers":2663},"custom-hostnames","Custom Hostnames","Access your Node-RED application via your own domain name.","\u002Fdocs\u002Fuser\u002Fcustom-hostnames\u002F",{"edge":2509,"hub":2474,"fleet":2509},{"id":2665,"title":2666,"description":2667,"docsLink":2668,"tiers":2669},"mqtt-broker","MQTT Broker","Manage and create MQTT clients to transport data for efficient messaging and communication within your applications.","\u002Fdocs\u002Fuser\u002Fteambroker\u002F",{"edge":2474,"hub":2509,"fleet":2474},{"id":2671,"title":2672,"description":2673,"docsLink":2674,"showOnPricing":2509,"tiers":2675},"project-nodes","Project Nodes aka seamless project comms","FlowFuse Project Nodes enable the passing of data and messages between your Node-RED projects.","\u002Fdocs\u002Fuser\u002Fprojectnodes\u002F",{"edge":2474,"hub":2474,"fleet":2474},{"id":2677,"title":2678,"description":2679,"docsLink":2680,"tiers":2681},"devops-pipelines","DevOps Pipelines","Set up different environments for development, testing, and production Node-RED instances to support a full software delivery lifecycle.","\u002Fdocs\u002Fuser\u002Fdevops-pipelines\u002F",{"edge":2474,"hub":2474,"fleet":2474},{"id":2683,"title":2684,"description":2685,"docsLink":2686,"tiers":2687},"git-integration","Git Integration","Back up your flows to a remote Git repository through a DevOps Pipeline. Supports GitHub and Azure DevOps repositories.","\u002Fdocs\u002Fuser\u002Fdevops-pipelines\u002F#git-repository-stage",{"edge":2509,"hub":2474,"fleet":2509},{"id":2689,"title":2690,"description":2691,"docsLink":2686,"subfeature":2474,"showOnPricing":2509,"tiers":2692},"git-integration-github","GitHub","Push and pull snapshots to GitHub repositories through DevOps Pipeline Git Stages.",{"edge":2509,"hub":2474,"fleet":2509},{"id":2694,"title":2695,"description":2696,"docsLink":2686,"changelog":2697,"subfeature":2474,"showOnPricing":2509,"tiers":2700},"git-integration-azure","Azure DevOps","Push and pull snapshots to Azure DevOps repositories through DevOps Pipeline Git Stages.",[2698],{"url":2699,"release":2621},"\u002Fchangelog\u002F2026\u002F03\u002Fazure-dev-ops-gitops\u002F",{"edge":2509,"hub":2474,"fleet":2509},{"id":2702,"title":2703,"features":2704},"operate-maintain","Operate & Maintain",[2705,2711,2717,2722,2730,2734,2738,2743,2749,2755,2760,2766,2770,2774],{"id":2706,"title":2707,"description":2708,"docsLink":2709,"tiers":2710},"snapshots","Snapshots & Version History","Automatic snapshots on remote devices and hosted instances, plus a full version history timeline so you can roll back to any prior state.","\u002Fdocs\u002Fuser\u002Fsnapshots\u002F",{"edge":2474,"hub":2474,"fleet":2474},{"id":2712,"title":2713,"description":2714,"docsLink":2715,"subfeature":2474,"showOnPricing":2509,"tiers":2716},"auto-snapshot-remote","Auto Snapshot (Remote)","Automatically capture a snapshot every time a remote instance is deployed, so you always have a recoverable history of what was running on each device.","\u002Fdocs\u002Fuser\u002Fsnapshots\u002F#auto-snapshots",{"edge":2474,"hub":2474,"fleet":2474},{"id":2718,"title":2719,"description":2720,"docsLink":2715,"subfeature":2474,"showOnPricing":2509,"tiers":2721},"auto-snapshot-hosted","Auto Snapshot (Hosted)","Automatically capture a snapshot every time a hosted instance is deployed, so you always have a recoverable history of what was running.",{"edge":2474,"hub":2474,"fleet":2474},{"id":2723,"title":2724,"description":2725,"changelog":2726,"subfeature":2474,"showOnPricing":2509,"tiers":2729},"snapshot-comparison","Snapshot Comparison","Compare two snapshots side-by-side with a navigable diff view. Step through every changed, added, or deleted node and see property and code diffs.",[2727],{"url":2728,"release":2621},"\u002Fchangelog\u002F2026\u002F04\u002Fsnapshot-diff-viewer\u002F",{"edge":2474,"hub":2474,"fleet":2474},{"id":2731,"title":2732,"subfeature":2474,"showOnPricing":2509,"tiers":2733},"version-history-timeline","Version History Timeline",{"edge":2474,"hub":2474,"fleet":2474},{"id":2735,"title":2736,"tiers":2737},"unlimited-workflow-executions","Unlimited Workflow Executions",{"edge":2474,"hub":2474,"fleet":2474},{"id":2739,"title":2740,"description":2741,"tiers":2742},"device-fleet-updates","Device Fleet Updates","Connect to edge devices to quickly assess and update logic. Debug one device and roll out improvements to your fleet in minutes, securely without requiring full device access for your whole organisation.",{"edge":2474,"hub":2509,"fleet":2474},{"id":2744,"title":2745,"description":2746,"docsLink":2747,"tiers":2748},"device-group-management","Device Group Management","Logically group devices assigned to an application and integrate device groups into your DevOps Pipeline for coordinated fleet updates.","\u002Fdocs\u002Fuser\u002Fdevice-groups\u002F",{"edge":2474,"hub":2509,"fleet":2474},{"id":2750,"title":2751,"description":2752,"docsLink":2753,"tiers":2754},"high-availability","High Availability","Leverage horizontal scaling for reliable and scalable processing of your data through Node-RED.","\u002Fdocs\u002Fuser\u002Fhigh-availability\u002F",{"edge":2509,"hub":2474,"fleet":2509},{"id":2756,"title":2757,"description":2758,"tiers":2759},"performance-monitoring","Performance Monitoring & Alerts","Track CPU, memory, and event loop performance across your instances and devices, with email alerts when something needs your attention.",{"edge":2474,"hub":2474,"fleet":2474},{"id":2761,"title":2762,"description":2763,"docsLink":2764,"subfeature":2474,"showOnPricing":2509,"tiers":2765},"instance-monitoring","Instance Monitoring","Enable alerts to be sent via email when your Node-RED instances encounter issues.","\u002Fdocs\u002Fuser\u002Finstance-settings\u002F#alerts",{"edge":2474,"hub":2474,"fleet":2474},{"id":2767,"title":2768,"subfeature":2474,"showOnPricing":2509,"tiers":2769},"email-alerts","Email Alerts",{"edge":2474,"hub":2474,"fleet":2474},{"id":2771,"title":2772,"showOnPricing":2509,"tiers":2773},"api-debug-length-limit","API\u002FDebug Length Limit",{"edge":2474,"hub":2474,"fleet":2474},{"id":2775,"title":2776,"tiers":2777},"protected-instances","Protected Instances",{"edge":2509,"hub":2474,"fleet":2509},{"id":2779,"title":2780,"features":2781},"govern-secure","Govern and Secure",[2782,2791,2797,2803,2808,2814,2820,2826,2834,2840,2846,2852],{"id":2783,"title":2784,"description":2785,"docsLink":2786,"changelog":2787,"tiers":2790},"single-sign-on","Single Sign-On (SSO)","Configure FlowFuse to work with your own SSO provider, allowing users to access FlowFuse with a single set of login credentials.","\u002Fdocs\u002Fadmin\u002Fsso\u002F",[2788],{"url":2789,"release":2562},"\u002Fchangelog\u002F2026\u002F07\u002Fapplication-sso-groups\u002F",{"edge":2474,"hub":2474,"fleet":2474},{"id":2792,"title":2793,"description":2794,"docsLink":2795,"tiers":2796},"two-factor-authentication","Two-Factor Authentication","Two-factor authentication adds an extra layer of security to your FlowFuse account.","\u002Fdocs\u002Fuser\u002Fuser-settings\u002F#two-factor-authentication",{"edge":2474,"hub":2474,"fleet":2474},{"id":2798,"title":2799,"description":2800,"docsLink":2801,"tiers":2802},"certified-nodes-it","Certified Nodes - IT","IT certified node bundle includes: Redis, MQTT, HTTP Request, AI nodes (Gemini, Claude, ChatGPT, Ollama), MCP Server","\u002Fblog\u002F2025\u002F07\u002Fcertified-nodes-v2\u002F",{"edge":2509,"hub":2474,"fleet":2474},{"id":2804,"title":2805,"description":2806,"tiers":2807},"certified-nodes-ot","Certified OT Connections - OPC-UA, Modbus, etc.","OT certified node bundle includes: OPC-UA, Modbus TCP & RTU, RTSP, EtherNet\u002FIP, AI nodes (Gemini, Claude, ChatGPT, Ollama), MCP Server",{"edge":2474,"hub":2509,"fleet":2509},{"id":2809,"title":2810,"description":2811,"docsLink":2812,"tiers":2813},"audit-log","Audit Log","Keep track of everything going on in your Node-RED instances and FlowFuse. Audit Logs provide details on what actions have taken place, when they happened, and who did them.","\u002Fdocs\u002Fuser\u002Flogs\u002F#audit-log",{"edge":2474,"hub":2474,"fleet":2474},{"id":2815,"title":2816,"description":2817,"docsLink":2818,"tiers":2819},"role-based-access-control","Role-Based Access Control","Control who can do what at both the team and application level, from viewers to admins.","\u002Fdocs\u002Fuser\u002Frole-based-access-control\u002F",{"edge":2474,"hub":2474,"fleet":2474},{"id":2821,"title":2822,"description":2823,"docsLink":2824,"subfeature":2474,"showOnPricing":2509,"tiers":2825},"application-level-rbac","Application-Level RBAC","Fine-grained access control per application, allowing team members to have different permission levels across different applications without requiring separate teams.","\u002Fdocs\u002Fuser\u002Frole-based-access-control\u002F#application-level-rbac",{"edge":2474,"hub":2474,"fleet":2474},{"id":2827,"title":2828,"description":2829,"changelog":2830,"subfeature":2474,"showOnPricing":2509,"tiers":2833},"scoped-personal-access-tokens","Scoped Personal Access Tokens","Restrict a Personal Access Token to specific teams, limit it to read-only operations, or control whether it carries admin privileges.",[2831],{"url":2832,"release":2562},"\u002Fchangelog\u002F2026\u002F07\u002Fscoped-pats\u002F",{"edge":2474,"hub":2474,"fleet":2474},{"id":2835,"title":2836,"description":2837,"docsLink":2838,"showOnPricing":2509,"tiers":2839},"team-members","Team Members","Invite multiple team members to collaborate on the same Node-RED flows.","\u002Fdocs\u002Fuser\u002Fteam\u002F#teams",{"edge":2474,"hub":2474,"fleet":2474},{"id":2841,"title":2842,"description":2843,"docsLink":2844,"showOnPricing":2509,"tiers":2845},"endpoint-security","Endpoint Security","Secure HTTP endpoints for hosted Node-RED instances using FlowFuse credentials.","\u002Fdocs\u002Fuser\u002Finstance-settings\u002F#security",{"edge":2474,"hub":2474,"fleet":2474},{"id":2847,"title":2848,"description":2849,"docsLink":2850,"tiers":2851},"baa-for-hipaa","BAA for HIPAA","FlowFuse can sign a Business Associate Agreement to ensure proper safeguarding of protected health information handled on your behalf.","\u002Fhandbook\u002Fsales\u002Fsubscription-agreement-1.5\u002F",{"edge":2509,"hub":2474,"fleet":2509},{"id":2853,"title":2854,"description":2855,"tiers":2856},"sbom","Software Bill of Materials","A complete list of all software components used in your Node-RED instances and hosted applications, including version numbers and license information.",{"edge":2509,"hub":2474,"fleet":2509},{"id":2858,"title":2859,"features":2860},"support","Support",[2861,2866,2870],{"id":2862,"title":2863,"docsLink":2864,"tiers":2865},"installation-support","Installation Support","\u002Fdocs\u002Finstall\u002Fintroduction\u002F#do-you-need-help-installation-service",{"edge":2474,"hub":2474,"fleet":2474},{"id":2867,"title":2868,"showOnPricing":2509,"tiers":2869},"live-chat-support","Live Chat Support",{"edge":2474,"hub":2474,"fleet":2474},{"id":2871,"title":2872,"docsLink":2873,"tiers":2874},"enterprise-support","Enterprise Support","\u002Fdocs\u002Fpremium-support\u002F",{"edge":2474,"hub":2474,"fleet":2474},"feature-catalog","0AnkhTIPCECCwP9NmbTWP5HvRYx4FTSao4lG93-HaWM",[2878,2885,2904,2914],{"name":2879,"order":167,"children":2880},"FlowFuse User Manuals",[2881],{"title":2882,"path":2883,"group":2879,"groupOrder":167,"order":182,"children":2884},"FlowFuse API","\u002Fdocs\u002Fapi",[],{"name":2886,"order":202,"children":2887},"FlowFuse Self-Hosted",[2888,2892],{"title":2889,"path":2890,"group":2886,"groupOrder":202,"order":167,"children":2891},"Quick Start","\u002Fdocs\u002Fquick-start",[],{"title":2893,"path":2894,"group":2886,"groupOrder":202,"order":193,"children":2895},"Upgrading FlowFuse","\u002Fdocs\u002Fupgrade",[2896,2900],{"title":2897,"path":2898,"order":2472,"children":2899},"Installing a license","\u002Fdocs\u002Fupgrade\u002Fopen-source-to-premium",[],{"title":2901,"path":2902,"order":2472,"children":2903},"Upgrading the Node-RED version","\u002Fdocs\u002Fupgrade\u002Fnodered-version",[],{"name":2859,"order":213,"children":2905},[2906,2910],{"title":2907,"path":2908,"group":2859,"groupOrder":213,"order":193,"children":2909},"Premium Support","\u002Fdocs\u002Fpremium-support",[],{"title":2911,"path":2912,"group":2859,"groupOrder":213,"order":2472,"children":2913},"Debugging Node-RED issues","\u002Fdocs\u002Fdebugging",[],{"name":2915,"order":2472,"children":2916},"Other",[2917,2963,2975,3054,3102,3121,3195,3206],{"title":2918,"path":2919,"order":2472,"children":2920},"admin","\u002Fdocs\u002Fadmin",[2921,2925,2937,2943,2947,2951,2955,2959],{"title":2922,"path":2923,"order":167,"children":2924},"Administering FlowFuse","\u002Fdocs\u002Fadmin\u002Fintroduction",[],{"title":2926,"path":2927,"order":2472,"children":2928},"Configuring Single Sign-On (SSO)","\u002Fdocs\u002Fadmin\u002Fsso",[2929,2933],{"title":2930,"path":2931,"order":2472,"children":2932},"LDAP SSO","\u002Fdocs\u002Fadmin\u002Fsso\u002Fldap",[],{"title":2934,"path":2935,"order":2472,"children":2936},"SAML SSO","\u002Fdocs\u002Fadmin\u002Fsso\u002Fsaml",[],{"title":2938,"path":2939,"order":2472,"children":2940},"hardening","\u002Fdocs\u002Fadmin\u002Fhardening",[2941],{"title":5,"path":2476,"order":2472,"children":2942},[],{"title":2944,"path":2945,"order":2472,"children":2946},"Monitoring","\u002Fdocs\u002Fadmin\u002Fmonitoring",[],{"title":2948,"path":2949,"order":2472,"children":2950},"Observability","\u002Fdocs\u002Fadmin\u002Fobservability",[],{"title":2952,"path":2953,"order":2472,"children":2954},"Soft Launch Enablement","\u002Fdocs\u002Fadmin\u002Ffeature-flags",[],{"title":2956,"path":2957,"order":2472,"children":2958},"Telemetry","\u002Fdocs\u002Fadmin\u002Ftelemetry",[],{"title":2960,"path":2961,"order":2472,"children":2962},"User Management","\u002Fdocs\u002Fadmin\u002Fuser-management",[],{"title":2964,"path":2965,"order":2472,"children":2966},"cloud","\u002Fdocs\u002Fcloud",[2967,2971],{"title":2968,"path":2969,"order":167,"children":2970},"Introduction","\u002Fdocs\u002Fcloud\u002Fintroduction",[],{"title":2972,"path":2973,"order":2472,"children":2974},"FlowFuse Cloud Billing","\u002Fdocs\u002Fcloud\u002Fbilling",[],{"title":2976,"path":2977,"order":2472,"children":2978},"contribute","\u002Fdocs\u002Fcontribute",[2979,2982,2986,2990,2994,2998,3002,3010,3046,3050],{"title":2968,"path":2980,"order":167,"children":2981},"\u002Fdocs\u002Fcontribute\u002Fintroduction",[],{"title":2983,"path":2984,"order":2472,"children":2985},"Adding Template Settings","\u002Fdocs\u002Fcontribute\u002Fadding-template-settings",[],{"title":2987,"path":2988,"order":2472,"children":2989},"API Design","\u002Fdocs\u002Fcontribute\u002Fapi-design",[],{"title":2991,"path":2992,"order":2472,"children":2993},"Creating debug stack containers","\u002Fdocs\u002Fcontribute\u002Fcreating-debug-stack-containers",[],{"title":2995,"path":2996,"order":2472,"children":2997},"Database migrations","\u002Fdocs\u002Fcontribute\u002Fdb-migrations",[],{"title":2999,"path":3000,"order":2472,"children":3001},"FlowFuse Architecture","\u002Fdocs\u002Fcontribute\u002Farchitecture",[],{"title":3003,"path":3004,"order":2472,"children":3005},"Local Install","\u002Fdocs\u002Fcontribute\u002Flocal",[3006],{"title":3007,"path":3008,"order":2472,"children":3009},"Local Stacks","\u002Fdocs\u002Fcontribute\u002Flocal\u002Fstacks",[],{"title":3011,"path":3012,"order":2472,"children":3013},"State Flows","\u002Fdocs\u002Fcontribute\u002Fworkflows",[3014,3018,3022,3026,3030,3034,3038,3042],{"title":3015,"path":3016,"order":2472,"children":3017},"Device Editor","\u002Fdocs\u002Fcontribute\u002Fworkflows\u002Fdevice-editor",[],{"title":3019,"path":3020,"order":2472,"children":3021},"Instance states","\u002Fdocs\u002Fcontribute\u002Fworkflows\u002Fproject-states",[],{"title":3023,"path":3024,"order":2472,"children":3025},"Invite External Users","\u002Fdocs\u002Fcontribute\u002Fworkflows\u002Finvite-external-user",[],{"title":3027,"path":3028,"order":2472,"children":3029},"Project Creation","\u002Fdocs\u002Fcontribute\u002Fworkflows\u002Fproject-create",[],{"title":3031,"path":3032,"order":2472,"children":3033},"Reset Password Flow","\u002Fdocs\u002Fcontribute\u002Fworkflows\u002Fpassword-reset",[],{"title":3035,"path":3036,"order":2472,"children":3037},"Team creation Flow","\u002Fdocs\u002Fcontribute\u002Fworkflows\u002Fteam-create",[],{"title":3039,"path":3040,"order":2472,"children":3041},"User Login Flows","\u002Fdocs\u002Fcontribute\u002Fworkflows\u002Flogin",[],{"title":3043,"path":3044,"order":2472,"children":3045},"User Sign up Flow","\u002Fdocs\u002Fcontribute\u002Fworkflows\u002Fsignup",[],{"title":3047,"path":3048,"order":2472,"children":3049},"Team Broker","\u002Fdocs\u002Fcontribute\u002Fteam-broker",[],{"title":3051,"path":3052,"order":2472,"children":3053},"Working with Feature Flags","\u002Fdocs\u002Fcontribute\u002Ffeature-flags",[],{"title":3055,"path":3056,"order":2472,"children":3057},"device-agent","\u002Fdocs\u002Fdevice-agent",[3058,3062,3065,3069,3073,3077],{"title":3059,"path":3060,"order":167,"children":3061},"FlowFuse Device Agent Introduction","\u002Fdocs\u002Fdevice-agent\u002Fintroduction",[],{"title":2889,"path":3063,"order":182,"children":3064},"\u002Fdocs\u002Fdevice-agent\u002Fquickstart",[],{"title":3066,"path":3067,"order":202,"children":3068},"Register your Remote Instance","\u002Fdocs\u002Fdevice-agent\u002Fregister",[],{"title":3070,"path":3071,"order":213,"children":3072},"Running the Agent","\u002Fdocs\u002Fdevice-agent\u002Frunning",[],{"title":3074,"path":3075,"order":224,"children":3076},"Deploying your Flows","\u002Fdocs\u002Fdevice-agent\u002Fdeploy",[],{"title":3078,"path":3079,"order":2472,"children":3080},"install","\u002Fdocs\u002Fdevice-agent\u002Finstall",[3081,3086,3090,3094,3098],{"title":3082,"path":3083,"group":3084,"order":167,"children":3085},"Overview","\u002Fdocs\u002Fdevice-agent\u002Finstall\u002Foverview","DeviceAgentInstallation",[],{"title":3087,"path":3088,"group":3084,"order":182,"children":3089},"Device Agent Installer","\u002Fdocs\u002Fdevice-agent\u002Finstall\u002Fdevice-agent-installer",[],{"title":3091,"path":3092,"group":3084,"order":193,"children":3093},"Docker Install","\u002Fdocs\u002Fdevice-agent\u002Finstall\u002Fdocker",[],{"title":3095,"path":3096,"group":3084,"order":202,"children":3097},"Kubernetes Install","\u002Fdocs\u002Fdevice-agent\u002Finstall\u002Fkubernetes",[],{"title":3099,"path":3100,"group":3084,"order":213,"children":3101},"Manual Install with NPM","\u002Fdocs\u002Fdevice-agent\u002Finstall\u002Fmanual",[],{"title":3103,"path":3104,"order":2472,"children":3105},"hardware","\u002Fdocs\u002Fhardware",[3106,3109,3113,3117],{"title":3082,"path":3107,"order":167,"children":3108},"\u002Fdocs\u002Fhardware\u002Fintroduction",[],{"title":3110,"path":3111,"order":182,"children":3112},"ctrlX - Node-RED","\u002Fdocs\u002Fhardware\u002Fctrlx-node-red",[],{"title":3114,"path":3115,"order":193,"children":3116},"ctrlX - Device Agent","\u002Fdocs\u002Fhardware\u002Fctrlx-device-agent",[],{"title":3118,"path":3119,"order":193,"children":3120},"Raspberry Pi with Raspbian","\u002Fdocs\u002Fhardware\u002Fraspbian",[],{"title":3078,"path":3122,"order":2472,"children":3123},"\u002Fdocs\u002Finstall",[3124,3127,3131,3135,3155,3159,3163,3167],{"title":3082,"path":3125,"order":167,"children":3126},"\u002Fdocs\u002Finstall\u002Fintroduction",[],{"title":3128,"path":3129,"order":2472,"children":3130},"Configuring FlowFuse","\u002Fdocs\u002Finstall\u002Fconfiguration",[],{"title":3132,"path":3133,"order":2472,"children":3134},"DNS Setup","\u002Fdocs\u002Finstall\u002Fdns-setup",[],{"title":3136,"path":3137,"order":2472,"children":3138},"Docker install","\u002Fdocs\u002Finstall\u002Fdocker",[3139,3143,3147,3151],{"title":3140,"path":3141,"order":2472,"children":3142},"Add Project Stacks on Docker","\u002Fdocs\u002Finstall\u002Fdocker\u002Fstacks",[],{"title":3144,"path":3145,"order":2472,"children":3146},"Docker Engine on Windows","\u002Fdocs\u002Finstall\u002Fdocker\u002Fwindows-docker-ce",[],{"title":3148,"path":3149,"order":2472,"children":3150},"Docker from AWS Market Place","\u002Fdocs\u002Finstall\u002Fdocker\u002Faws-marketplace",[],{"title":3152,"path":3153,"order":2472,"children":3154},"Docker on Digital Ocean","\u002Fdocs\u002Finstall\u002Fdocker\u002Fdigital-ocean",[],{"title":3156,"path":3157,"order":2472,"children":3158},"Email configuration","\u002Fdocs\u002Finstall\u002Femail-providers",[],{"title":3160,"path":3161,"order":2472,"children":3162},"First Run Setup","\u002Fdocs\u002Finstall\u002Ffirst-run",[],{"title":3164,"path":3165,"order":2472,"children":3166},"FlowFuse File Storage","\u002Fdocs\u002Finstall\u002Ffile-storage",[],{"title":3168,"path":3169,"order":2472,"children":3170},"Install FlowFuse on Kubernetes","\u002Fdocs\u002Finstall\u002Fkubernetes",[3171,3175,3179,3183,3187,3191],{"title":3172,"path":3173,"order":2472,"children":3174},"AWS EKS Installation","\u002Fdocs\u002Finstall\u002Fkubernetes\u002Faws",[],{"title":3176,"path":3177,"order":2472,"children":3178},"AWS EKS Installation with Terraform and Helm","\u002Fdocs\u002Finstall\u002Fkubernetes\u002Faws-terraform",[],{"title":3180,"path":3181,"order":2472,"children":3182},"Digital Ocean Kubernetes Installation","\u002Fdocs\u002Finstall\u002Fkubernetes\u002Fdigital-ocean",[],{"title":3184,"path":3185,"order":2472,"children":3186},"Ingress Controller Migration","\u002Fdocs\u002Finstall\u002Fkubernetes\u002Fingress-controller-migration",[],{"title":3188,"path":3189,"order":2472,"children":3190},"Kubernetes Project Stacks","\u002Fdocs\u002Finstall\u002Fkubernetes\u002Fstacks",[],{"title":3192,"path":3193,"order":2472,"children":3194},"OpenShift Installation","\u002Fdocs\u002Finstall\u002Fkubernetes\u002Fopenshift",[],{"title":3196,"path":3197,"order":2472,"children":3198},"migration","\u002Fdocs\u002Fmigration",[3199,3202],{"title":2968,"path":3200,"order":167,"children":3201},"\u002Fdocs\u002Fmigration\u002Fintroduction",[],{"title":3203,"path":3204,"order":2472,"children":3205},"Node-RED Tools plugin","\u002Fdocs\u002Fmigration\u002Fnode-red-tools",[],{"title":3207,"path":3208,"order":2472,"children":3209},"user","\u002Fdocs\u002Fuser",[3210,3214,3218,3222,3226,3230,3234,3237,3241,3245,3248,3252,3264,3268,3272,3276,3280,3283,3287,3291,3295,3299,3303,3306,3310,3314,3317,3321],{"title":3211,"path":3212,"order":167,"children":3213},"Getting Started","\u002Fdocs\u002Fuser\u002Fintroduction",[],{"title":3215,"path":3216,"order":167,"children":3217},"Static asset service","\u002Fdocs\u002Fuser\u002Fstatic-asset-service",[],{"title":3219,"path":3220,"order":182,"children":3221},"Bill of Materials","\u002Fdocs\u002Fuser\u002Fbill-of-materials",[],{"title":3223,"path":3224,"order":182,"children":3225},"FlowFuse Concepts","\u002Fdocs\u002Fuser\u002Fconcepts",[],{"title":3227,"path":3228,"order":340,"children":3229},"Instance States","\u002Fdocs\u002Fuser\u002Finstance-states",[],{"title":3231,"path":3232,"order":2472,"children":3233},"Changing the Stack","\u002Fdocs\u002Fuser\u002Fchangestack",[],{"title":2660,"path":3235,"order":2472,"children":3236},"\u002Fdocs\u002Fuser\u002Fcustom-hostnames",[],{"title":3238,"path":3239,"order":2472,"children":3240},"Custom Node Packages","\u002Fdocs\u002Fuser\u002Fcustom-npm-packages",[],{"title":3242,"path":3243,"order":2472,"children":3244},"Dashboards","\u002Fdocs\u002Fuser\u002Fdashboards",[],{"title":2678,"path":3246,"order":2472,"children":3247},"\u002Fdocs\u002Fuser\u002Fdevops-pipelines",[],{"title":3249,"path":3250,"order":2472,"children":3251},"Environment Variables","\u002Fdocs\u002Fuser\u002Fenvvar",[],{"title":3253,"path":3254,"order":2472,"children":3255},"FlowFuse Expert","\u002Fdocs\u002Fuser\u002Fexpert",[3256,3260],{"title":3257,"path":3258,"order":2472,"children":3259},"AI in Node-RED","\u002Fdocs\u002Fuser\u002Fexpert\u002Fnode-red-embedded-ai",[],{"title":3261,"path":3262,"order":2472,"children":3263},"Chat Interface","\u002Fdocs\u002Fuser\u002Fexpert\u002Fchat",[],{"title":3265,"path":3266,"order":2472,"children":3267},"FlowFuse File Nodes","\u002Fdocs\u002Fuser\u002Ffilenodes",[],{"title":3269,"path":3270,"order":2472,"children":3271},"FlowFuse MQTT Nodes","\u002Fdocs\u002Fuser\u002Fmqtt-nodes",[],{"title":3273,"path":3274,"order":2472,"children":3275},"FlowFuse Persistent Context","\u002Fdocs\u002Fuser\u002Fpersistent-context",[],{"title":3277,"path":3278,"order":2472,"children":3279},"FlowFuse Project Nodes","\u002Fdocs\u002Fuser\u002Fprojectnodes",[],{"title":2556,"path":3281,"order":2472,"children":3282},"\u002Fdocs\u002Fuser\u002Fff-tables",[],{"title":3284,"path":3285,"order":2472,"children":3286},"Groups","\u002Fdocs\u002Fuser\u002Fdevice-groups",[],{"title":3288,"path":3289,"order":2472,"children":3290},"High Availability mode","\u002Fdocs\u002Fuser\u002Fhigh-availability",[],{"title":3292,"path":3293,"order":2472,"children":3294},"HTTP Access Tokens","\u002Fdocs\u002Fuser\u002Fhttp-access-tokens",[],{"title":3296,"path":3297,"order":2472,"children":3298},"Instance Settings","\u002Fdocs\u002Fuser\u002Finstance-settings",[],{"title":3300,"path":3301,"order":2472,"children":3302},"Logging","\u002Fdocs\u002Fuser\u002Flogs",[],{"title":2816,"path":3304,"order":2472,"children":3305},"\u002Fdocs\u002Fuser\u002Frole-based-access-control",[],{"title":3307,"path":3308,"order":2472,"children":3309},"Shared Team Library","\u002Fdocs\u002Fuser\u002Fshared-library",[],{"title":3311,"path":3312,"order":2472,"children":3313},"Snapshots","\u002Fdocs\u002Fuser\u002Fsnapshots",[],{"title":3047,"path":3315,"order":2472,"children":3316},"\u002Fdocs\u002Fuser\u002Fteambroker",[],{"title":3318,"path":3319,"order":2472,"children":3320},"Teams","\u002Fdocs\u002Fuser\u002Fteam",[],{"title":3322,"path":3323,"order":2472,"children":3324},"User Settings","\u002Fdocs\u002Fuser\u002Fuser-settings",[],1786717924641]