Chapter 21

Credentials, Backup and Restore, Projects, and Security Hardening

Protect flows, credentials, settings, package inventories, and decryption materials in separate layers. Then prove that the backups work by conducting an isolated restore drill with every external side effect disabled. This chapter performs offline checks only: it makes no connections and deploys nothing.

Why this chapter matters

A backup involves more than copying flows.json, just as security involves more than adding a login to the editor. This Add-on holds flows, encrypted credentials, and access to Home Assistant and Supervisor capabilities. It can also access several mapped directories and the host network. A leak, accidental deletion, or configuration mismatch at any layer could halt your automations or expose previously controlled capabilities to untrusted nodes.

This chapter sets a fixed scope of Add-on 22.0.1, its bundled Node-RED 5.0.2, and HA WebSocket nodes 0.80.3. You will build a five-layer threat model covering data, keys, versions, exposure, and permissions, then use a read-only inventory and an offline restore drill to verify recoverability. Examples that involve networking, Home Assistant, file writes, package installation, or hardware are shown only for identification; this chapter does not run them.

Prerequisites: First complete the Add-on and Ingress boundaries in Chapter 2, the flow architecture in Chapter 17, and the safe testing practices in Chapter 18. If you cannot yet identify nodes that cause side effects, do not deploy after a restore.

Core concepts

A five-layer threat model

LayerPrimary assetsTypical failureMinimum control
Dataflows, credentials, settings, contextLoss, corruption, or overwrite with the wrong versionEncrypted backups, a retention schedule, and restore drills
Keyscredential_secret, Project credential secret, TLS private keyExposure alongside the data, or loss that prevents decryptionSeparate storage, no arbitrary rotation, and dual-control access records
VersionsAdd-on, Node-RED, node, and package versionsUnknown nodes or schema incompatibilities after a restoreA pinned version inventory and recorded package sources
ExposureIngress, direct port, HTTP, Dashboard, MQTTTreating editor authentication as authentication for every endpointRoute-by-route checks of authentication, TLS, and source restrictions
PermissionsSupervisor, HA API, host network, UART, mapped directoriesThird-party nodes gaining capabilities beyond their intended purposeThe fewest nodes and destinations, with the fewest writable paths

Back up data paths together with their meaning

The Add-on wrapper fixes userDir=/config/, nodesDir=/config/nodes, and flowFile=flows.json. The backend listens only on 127.0.0.1:46836, and the flow HTTP root is fixed at /endpoint. The “configuration directory” therefore includes at least /config/flows.json, its corresponding credentials file, /config/settings.js, /config/package.json, /config/nodes/, and any context storage that may exist. The actual credentials filename is derived from the flow filename, so do not select backup files merely by guessing the name.

addon_config:rw maps this persistent data to /config. homeassistant_config:rw, media:rw, and share:rw are additional capabilities; they do not mean that Node-RED necessarily writes to those locations. The ssl mount supplies files for direct TLS. If it contains private keys, never copy them into a flow, log, or general-purpose shared directory.

Build a recoverable process that triggers no actions

  1. Create a read-only asset inventory.

    Record Add-on 22.0.1, Node-RED 5.0.2, HA WebSocket 0.80.3, the pinned version of every additional package, whether Projects is enabled, the context store, and which mapped directories the flows actually use. Do not include tokens, passwords, private keys, real URLs, entity/device/area IDs, MQTT brokers, client IDs, or topics.

  2. Archive the data separately from its decryption materials.

    Use an approved Home Assistant backup mechanism for Add-on data, and store credential_secret separately in an approved secrets manager. If Projects is enabled, store that Project’s credential secret separately as well. Do not keep the only copies of these materials on the same host, and never commit them to Git.

  3. Confirm backup exclusions and rebuild sources.

    The Add-on manifest explicitly uses backup_exclude to exclude node_modules. Preserve package.json and a pinned version/name inventory for custom npm_packages and system_packages. Do not claim that the backup contains the complete dependency tree.

  4. Run the restore drill in an isolated environment first.

    The isolated environment must not connect to production HA, MQTT, HTTP, TCP, UDP, WebSocket, database, or UART services. Keep every Action, API, Fire Event, Update Config, file-output, email, Cast, Modbus, serial, and network node disabled. Disable automatic schedules as well.

  5. Validate with read-only checks.

    Compare flow counts, node types, package versions, whether credentials decrypt successfully, and whether the settings and context stores exist. Use manual Inject nodes only with pure data-processing chains, and limit Debug output to essential fields. Do not deploy any node that writes data or communicates externally.

  6. Record the drill results and recovery point.

    Record the backup time, restored version, missing dependencies, verifier, and rollback method—but no secret values. Schedule a separate production change window only after the isolated validation passes. This chapter performs no production restore, network connection, or deployment.

End-of-chapter offline acceptance check

DeliverableExpected contentsStop if
Recovery inventoryAdd-on, Node-RED, HA WebSocket, and additional package versions; flow and node-type counts; a backup hash; three secrets-management reference fields; missing dependencies; and an enabled external/write I/O count of 0Versions or counts cannot be compared; the hash or references are missing; credentials cannot be decrypted; an unknown node remains unexplained; or any production HA, MQTT, HTTP, file, or hardware I/O could operate

Credentials, exports, and the key lifecycle

credential_secret must remain recoverable and unchanged

Node-RED encrypts stored credentials with a secret key. The Add-on maps credential_secret to the runtime setting credentialSecret. The official documentation explicitly requires you to store it securely. Once configured, it must not be changed arbitrarily, or existing credentials will no longer decrypt. This does not make the encrypted file safe to publish: ciphertext and keys are both sensitive assets and require separate controls.

Recovery reference inventory (not Add-on configuration; not executable)
Add-on credential secret reference = PLACEHOLDER_SECRET_RECORD_ID
Project credential secret reference = PLACEHOLDER_PROJECT_SECRET_RECORD_ID
Backup reference = PLACEHOLDER_BACKUP_ID

The inventory stores reference IDs only. Actual secret values belong exclusively in an approved secrets manager; never place them in this inventory, a flow, Git, backup notes, or a support ticket.

Projects have a separate key boundary: The Add-on documentation states that when you manually enable Node-RED Projects, credential_secret remains a required Add-on option, but Node-RED ignores it. Project credentials use the Project’s own secret. The two secrets are not interchangeable.

Sanitize content before export; do not rely on the credentials panel

Flow JSON exports, Library entries, and Subflows may expose server-configuration references, environment identifiers, or node properties. Review Subflow instance properties, environment variables, and parent flow context as well. Before sharing, inspect every field and replace sensitive values with complete placeholders such as YOUR_HA_SERVER, YOUR_ENTITY_ID, YOUR_DEVICE_ID, YOUR_AREA_ID, YOUR_MQTT_BROKER, and YOUR_MQTT_TOPIC. Also remove credential blocks, Authorization headers, cookies, webhook IDs, zones/tags, location data, file paths, and captured Debug output.

Render Template, API, Webhook, Zone, deprecated Entity, Server, Device Config, Entity Config, Update Config, and other HA nodes may access sensitive settings or environment IDs. Update Config, in particular, changes a companion entity’s configuration or state metadata. Keep the node disabled in exported examples and retain placeholders only. See Chapter 8 for more HA node roles and Chapter 19 for HTTP and Webhook boundaries.

Backup contents, immutability, and restore drills

ItemFixed location or sourceBackup and restore considerations
Flows/config/flows.jsonCompare offline first; keep all side-effecting nodes disabled after the restore.
CredentialsThe credentials storage paired with the flow fileBoth the ciphertext and the correct secret are required; never paste either into a support ticket.
Runtime settings/config/settings.jsThe wrapper overwrites specific backend, path, authentication, TLS, and other keys. Do not apply upstream defaults directly.
Node declarations/config/package.json, Add-on options inventorynode_modules is not included in backups; rebuild it from trusted, pinned sources.
Local nodes/config/nodesReview their source and code; local modules run with the Node-RED process’s permissions.
ContextThe configured memory or localfilesystem storeMemory does not persist across restarts; even with a disk store, do not assume that every assignment becomes durable immediately.
External stateHA, MQTT, InfluxDB, devicesThis state is not part of a Node-RED backup. A restore must neither replay commands nor assume that external state is synchronized.

Backup immutability

Keep at least one backup version that the Node-RED runtime account cannot modify. Apply a retention period, integrity hashes, and access logging. “Immutable” does not mean “never delete”; it means that a compromised runtime cannot destroy every recovery point at once. Regularly replace expired versions with new backups, then destroy the expired copies securely according to their data classification.

Do not deploy immediately after an incident

First isolate the system and preserve the timeline and de-identified logs, then rebuild from a known-good backup. If credentials, a Project secret, an HA token, MQTT credentials, HTTP Basic Auth credentials, a TLS private key, or a webhook ID may have leaked, revoke and rotate them through the relevant system. Rotate external-system credentials first, update Node-RED credentials next, and finally validate with the flows disabled. Do not treat replacement of credential_secret as routine token rotation: changing it affects decryption of existing ciphertext.

Boundaries for Projects, Git, and private repositories

The Add-on’s settings.js sets editorTheme.projects.enabled=false by default. Projects is not an out-of-the-box backup system. When enabled manually, it provides a Git-backed project workflow, but a Git commit, remote availability, and a complete Add-on backup are three different things.

For Projects, distinguish three assets: the actual plaintext credentials; the Project credential file, encrypted with the Project secret and eligible for Git tracking; and the Project secret, which is not stored in the repository. A standard workflow may commit the encrypted file to a private repository with restricted membership and permissions. Encryption does not make ciphertext suitable for public disclosure, and the decryption secret must be protected separately in an approved secrets manager.

  • A private repository is still not a secrets manager: Minimize permissions for members, deploy keys, and automation tokens. Never commit plaintext credentials, Project secrets, TLS keys, backup files, real endpoints, or environment IDs.
  • Store the Project secret independently: The Add-on’s credential_secret does not replace it, and it does not enter Git with the encrypted Project credential file. Before restoring a Project, confirm that you have the matching secret; do not gamble by “resetting the key.”
  • Choose a ciphertext policy explicitly: If your organization permits tracking the encrypted Project credential file, commit it only to a restricted private repository. If policy excludes even ciphertext, Git cannot restore the Project credentials; keep a separate, protected credential-file backup whose recoverability has been verified.
  • Review the diff before committing: Check flow JSON, Project metadata, package versions, the ciphertext-file policy, and deleted items. Export-sanitization rules also apply to Git.
  • A remote is only one layer: Keep a separate Add-on backup because settings, non-Project flows, context, Add-on options, and credential lifecycles may not all be covered by Git.

If the remote is unavailable, first preserve a read-only copy of the local Project directory and its status. Do not force-push, delete .git, or reinitialize the Project and overwrite its history. Once the identity and target remote have been verified, an authorized maintainer can proceed.

Exposure, capabilities, and least privilege

Ingress, direct access, and endpoints are separate layers

SurfaceBehavior in 22.0.1Required controls
Ingressingress=true, dynamic ingress_port=0, and ingress_stream=true; the NGINX listener accepts only the Supervisor Ingress source.Apply least privilege to HA accounts. Do not infer that the direct endpoint receives the same protection.
Direct editorContainer port 80/tcp can map to host port 1880; / uses the Supervisor authentication API by default.Map the port only when necessary; leave leave_front_door_open false or omit it.
TLSssl defaults to true and affects only the direct listener; certfile and keyfile are read from /ssl.Verify that the pair matches, is current, and has appropriate permissions. These options neither issue nor automatically renew certificates, and they do not control Ingress.
Flow HTTP/endpoint/ does not use the direct editor’s Supervisor authentication; http_node provides Basic Auth.Use separate strong credentials, TLS, and input size/schema limits. Do not confuse this with editor authentication.
Static contenthttp_static protects static content only.Do not assume that this protection extends to HTTP nodes, the editor, WebSockets, or other routes.
DashboardFlowFuse Dashboard 2 @flowfuse/[email protected] is optional and not bundled. It declares Node >=14 and Node-RED >=3.0.0; Node-RED serves its routes.Compatibility metadata does not replace testing in the target environment. Verify HTTP and WebSocket authentication route by route. Use legacy node-red-dashboard and the deprecated @flowforge scope only for migration; do not install them for new deployments.
MQTT and other networksMQTT, HTTP, WebSocket, TCP, UDP, and TLS configuration nodes can all produce external I/O.Use broker ACLs, a dedicated client, TLS verification, and least-privilege topic access. Keep examples disabled and use placeholders.

Manifest grants define the maximum risk, not a usage requirement

hassio_api=true with hassio_role=manager grants powerful Supervisor capabilities; homeassistant_api=true grants access to the HA Core API; and auth_api=true lets the wrapper use Supervisor authentication. host_network=true expands local-network reachability, while uart=true enables serial-hardware access. Never write a Supervisor or HA token into a flow or Debug output. Restrict additional nodes, outbound destinations, and writable directories. Ensure that File, File In, Watch, HTTP In/Response/Request/Proxy, MQTT, TLS configuration, TCP, UDP, WebSocket, serial, and similar nodes receive only the access their jobs require.

Flows can write to homeassistant_config:rw, media:rw, and share:rw. Allowlist filenames and paths to prevent traversal, overwrites, and storage of secrets in shared directories. UART and Modbus writes can cause physical side effects; always validate them in an isolated environment with no hardware connected.

Custom code and preinstalled packages belong inside the trust boundary

During startup, the wrapper first installs system_packages, then uses npm install --omit=dev --omit=optional to install npm_packages, and finally uses eval to run each line of init_commands. A failure at any stage aborts initialization. Because init_commands runs at every startup, keep it empty unless the commands have passed change review, are repeatable, and contain no secrets. This chapter neither supplies nor runs any commands.

Pinned packagePrimary risks and constraints
[email protected]The wrapper uses it to hash HTTP Basic Auth passwords; a hash is not a publishable substitute for a password.
[email protected], [email protected]These can control devices or send outbound messages; keep the nodes disabled during restore drills.
[email protected]Control database credentials, query scope, and retention separately.
[email protected], [email protected]OT and serial reads or writes may cause physical side effects; pairing them with UART access increases the risk.
[email protected]Restored persistent state may not match the real external state.
[email protected], [email protected]These read untrusted content or probe networks; restrict sources, sizes, frequencies, and destinations.
[email protected], [email protected]Base64 is not encryption, and the random node must not generate cryptographic secrets.

The first startup creates /config. The wrapper can migrate old data from /homeassistant/node-red, migrate the old dark theme to dark-modern, and attempt to remove three conflicting legacy HA packages. These are wrapper behaviors, not deletion commands that you should run manually. See Chapter 20 for supply-chain boundaries around optional extensions and MQTT.

Diagnose backup and access problems safely

  • Credentials do not work after a restore: Keep all flows disabled and verify the versions and Project boundaries of the backup and secret. Do not repeatedly change credential_secret, and do not paste ciphertext or secrets into logs. If no matching secret exists, reissue the external credentials through the incident-response process.
  • Ingress opens, but /endpoint/ lacks the expected authentication: First determine whether you are using Ingress or the direct host port, then confirm the route with a read-only request that contains no real data. Check http_node, TLS, and the port mapping. Do not use leave_front_door_open as a fix.
  • Unknown nodes appear after a restore: Do not deploy or delete an unknown node. Identify the matching pinned package from the inventory, then rebuild the excluded node_modules in an isolated environment. Verify the source and version before loading it.
  • The Project remote or credentials fail: Preserve the local data and Git status. Verify the Project secret, remote identity, and least-privilege access. Do not force-push, reset the secret, or reinitialize the Project.
  • You suspect a token or private key has leaked: Isolate the Add-on first and preserve a de-identified timeline, then revoke or rotate the credential in its source system. Do not resume service after merely deleting Debug messages; also inspect backups, Git, shared directories, and external logs to determine the full scope of exposure.

Pinned sources

This chapter’s technical boundaries are based only on the following exact commits and corresponding official documentation:

Frequently asked questions

During an incident, the secrets-manager reference does not match the backup time. Which key should I try first?
Do not guess or overwrite the configuration. Stop the restore and preserve read-only evidence of the backup hash, timestamp, and reference version. Use the secrets manager’s access records to establish the match. If you cannot prove a match, mark that recovery point as failed and follow the approved incident-response and external-credential reissuance procedures.
Can a private Git repository for Projects replace an Add-on backup?
No. Git may not cover Add-on options, non-Project data, context, every credential, or wrapper state, and a private repository is not a secrets manager. Treat the two as separate recovery layers.
Can I rotate credential_secret regularly?
Do not treat it like an access token that receives routine rotation. The official Add-on documentation warns that arbitrary changes prevent existing credentials from being decrypted. During an incident, rotate external credentials first. If the key itself is affected, follow a controlled migration or rebuild procedure.
Does an Ingress login automatically protect HTTP, Dashboard, and MQTT?
No. Ingress, the direct editor, /endpoint/, static content, Dashboard routes, WebSockets, and MQTT are separate boundaries. Configure endpoint authentication, TLS, broker ACLs, and source restrictions individually.
How can a restore drill avoid triggering smart-home actions?
Use an isolated environment with no production network and no HA, MQTT, or UART connections. Disable all external I/O, writes, schedules, and executable HA nodes. Perform only read-only checks of file integrity, node types, credential decryption, and pure data-processing chains.