Install Stable 2.0.55, and pick the method you can actually operate
Matter Hub gives you three ways in: the Home Assistant OS add-on, a Docker image, or a global npm package. They are not tiers of the same product — each one hands you a different pile of things to own. This chapter walks all three, the network and storage requirements they share, every Stable 2.0.55 start option pulled straight from the source, the backup-and-upgrade order that keeps a rollback possible, and what to check first when the install itself will not cooperate.
--http-port / HAMH_HTTP_PORT. The add-on skips it and hands you a dynamic Ingress port insteadDo not assume everyone should deploy by hand
The upstream installation docs list the Home Assistant OS add-on as the preferred method, and there is a reason for that beyond convenience: if you already run Home Assistant OS, Supervisor takes over starting, stopping and Ingress, and the add-on gets its connection details straight from the Home Assistant API — you never type a URL or a token in by hand. Docker and global npm exist for readers who can maintain a container or a Node.js service, a data directory, the network and a way to inject secrets on their own. They are not an inevitable upgrade to “more complete features.”
Nobody asks which is the best of a screwdriver, a hammer and a drill. You ask which one fits the screw in front of you. The add-on fits a Home Assistant OS install because Supervisor already does the boring parts. Docker fits a host you already run containers on. npm fits an environment you are already comfortable operating as a bare service. Picking the “better” one for a job it does not fit just moves the work from the tool to you.
| Method | When it fits | What you own |
|---|---|---|
| Stable add-on 2.0.55 | Home Assistant OS; you want Supervisor and Ingress to manage it | Adding the right repository, checking the add-on settings, backing up addon_config, the network, and version upgrades |
| Docker image | You already operate containers, can use host network and can manage a persistent volume | Injecting the HA URL and token, the image version, the restart policy, /data, IPv6/mDNS, access control for the Web UI |
| Global npm | An advanced environment where you can manage a compatible Node.js, a system service, permissions and logs | The package version, keeping the process running, the storage location, rolling back an update, and every start option |
flowchart TD A["Do you run Home Assistant OS,
and want Supervisor to manage this?"] -->|"yes"| B["Stable add-on.
Supervisor handles start, stop and Ingress"] A -->|"no"| C{"Can you operate a container,
host networking and a persistent volume?"} C -->|"yes"| D["Docker, pinned to 2.0.55.
You own the token, the volume, the tag"] C -->|"no"| E{"Can you manage a compatible Node.js,
a system service and every start option?"} E -->|"yes"| F["Global npm.
You own the process, storage and rollback"] E -->|"no"| G["Go back to Home Assistant OS.
The add-on needs the least from you"]
HA, IPv6, mDNS and the data directory — before any of the three methods
All three methods need a working Home Assistant, a correct clock, storage that persists, and a LAN the controller can actually reach. Matter depends on IPv6, mDNS and UDP; if you run VLANs, both multicast and the return route have to be handled correctly. A Web UI that loads is not the same claim as a network that works for commissioning — that second claim is the one Chapter 4 needs, and it is worth confirming now rather than after you have built a bridge.
- Home Assistant itself works, and you are allowed to create a long-lived access token dedicated to this service. Do not paste the token into a repository, a chat or a screenshot.
- The controller or home hub and the host running Matter Hub have a working IPv6 and mDNS path between them, and AP/client isolation is off.
- Docker uses host network; the pinned add-on config also sets
host_network: true. - Decide where data will persist and how you will back it up before you start. Docker always mounts the container's
/data; npm defaults to an application folder under the user's home directory, or you name one with a start option. - Do not expose the Web UI directly to an untrusted network. Basic Auth is not multi-account, RBAC or SSO — treat it as a speed bump, not a lock.
flowchart TD A["Add-on shows Started,
or the container is Up"] --> B{"Does the Web UI load
and show HA Online?"} B -->|"no"| C["Fix the HA URL, the token,
or the network path first"] B -->|"yes"| D{"Is host networking on,
with a working IPv6 and mDNS path?"} D -->|"no"| E["The service is running,
but commissioning will still fail"] D -->|"yes"| F["Ready for the next chapter:
creating a bridge"]
A doorbell that rings only in the kitchen is not broken — it is just wired to the wrong room. Host networking and mDNS are the wiring that lets the sound reach wherever the controller happens to be standing. The Web UI loading tells you the doorbell has power. It does not tell you the wire reaches the room where the guest is knocking.
<HA_BASE_URL>, <HA_LONG_LIVED_ACCESS_TOKEN> and <PERSISTENT_DATA_PATH>. Fill in the real values through a controlled secret or environment mechanism when you run them, and do not publish your shell history, your compose file or your diagnostic output.Install the pinned Stable 2.0.55 add-on
The add-on facts in this guide are pinned to WOOWTECH mirror commit a68dc435da8eb206e9efd51388d5d1ce798aefe0. In it, hamh/config.yaml declares version 2.0.55, the slug hamh, a minimum Home Assistant of 2024.1.0, and support for aarch64 and amd64. It enables the Home Assistant API, host network and Ingress, the Ingress port is a dynamic value, and it mounts addon_config read-write.
| Pinned config field | Value / meaning |
|---|---|
version | 2.0.55, the Stable version this chapter targets |
homeassistant_api | true, so the add-on can use the HA API capability Supervisor provides |
host_network | true, so Matter and mDNS use the host network; the LAN still has to be set up correctly |
ingress / ingress_port | Ingress is enabled and the platform assigns the port; you normally enter through the add-on's “Open Web UI” |
arch | Lists only aarch64 and amd64; do not infer that this mirror supports any other architecture |
map | addon_config:rw, so the data persists and belongs in your backup |
| Visible options | app_log_level, disable_log_colors, mdns_network_interface, mdns_strip_global_ipv6 |
-
Step 1
Add the Stable repository
In Home Assistant, open Settings → Add-ons → Add-on Store, then use the repository menu in the top right to add the Stable add-on repository you have approved. Check that what shows up is Stable
hamh, and do not pick the Alpha or Testing slug by mistake. -
Step 2
Cross-check the version and the architecture
On the install card, first confirm the version is
2.0.55and that the host architecture is one of theaarch64oramd64the pinned config lists. If it does not match, stop the install; do not substitute an unknown image. -
Step 3
Install it and review the configuration
After you press Install, go to the Configuration tab and leave the log level at
info. Fill inmdns_network_interfaceonly when Network Diagnostics points at an interface problem. Do not pick a Docker or Thread interface at random. -
Step 4
Start it and open it through Ingress
Press Start, check the add-on log to see whether the service finished initializing, then press Open Web UI. A successful screen shows the Dashboard, with the HA connection Online.
-
Step 5
Back up before you create a bridge
Confirm that the Supervisor backup includes the add-on data before you go to the next chapter and create a bridge. Do not treat “the UI opens” as proof that the backup is done.
Pin the image, use host network and /data
Docker suits readers who already operate containers. Stable 2.0.55 needs host network so that Matter and mDNS are not held back by an ordinary bridge network; data is written to the container's /data, so you must mount a persistent volume. For reproducibility this chapter uses an explicit version tag, not the moving latest.
The full command is docker run -d followed by these flags, in order:
--name home-assistant-matter-hub--restart unless-stopped--network host-v <PERSISTENT_DATA_PATH>:/data-e HAMH_HOME_ASSISTANT_URL="<HA_BASE_URL>"-e HAMH_HOME_ASSISTANT_ACCESS_TOKEN="<HA_LONG_LIVED_ACCESS_TOKEN>"-e HAMH_LOG_LEVEL="info"ghcr.io/riddix/home-assistant-matter-hub:2.0.55Do not write the real token into a Compose file you can commit; use a permission-protected env file, a container secret or your deployment platform's secret store instead. <HA_BASE_URL> has to be a Home Assistant HTTP(S) base URL the container can reach — do not copy someone else's hostname or private address.
-
Step 1
Create a restricted data directory
Create
<PERSISTENT_DATA_PATH>on the host, make it readable and writable only by the account the service runs as, and add it to your backup. Do not sync that directory to a public location. -
Step 2
Prepare secret injection
Create variables for the HA URL and the long-lived token in your secret store. If an env file is your only option, give the file the least privilege it needs and keep it out of version control.
-
Step 3
Start the pinned-version container
Run the command above; confirm that you are using
--network host, version2.0.55and the/datamount. Do not remove the persistent volume just to get the container to start. -
Step 4
Verify health and the logs
Check the container status and the startup log first, then open the Web UI from a controlled network. Share only a redacted error summary, never the list of environment variables or the full configuration.
-
Step 5
Test that a rebuild keeps the data
Before you build a production bridge, record the version and where the backup lives; an update drill should be able to rebuild the container against the same
/data. Do not test by deleting the volume.
An environment variable on the command line is a postcard — anyone who handles it along the way can read what it says, including your shell history and your process list. A secret store or a permission-protected env file is a sealed envelope. The token does the same job either way; only one of them survives being left on a desk.
Only where you can manage a long-running service
A global npm install gives you none of the process supervision, network isolation or data mounts that Supervisor or a container layer provide. You maintain the compatible Node.js, the service account, systemd or another process manager, the restart policy, log rotation and the storage location yourself. If those responsibilities are unfamiliar, go back to the add-on or Docker.
npm install -g @riddix/hamhThe installation docs at the same v2.0.55 tag still print the old package name, but the release workflow rewrites it to @riddix/hamh at publish time; go by the upstream release workflow and the published package, not the docs page's literal text. The executable after installation is still home-assistant-matter-hub.
Command-line arguments can end up in shell history or in a process listing, so a real long-running service should inject the token as HAMH_HOME_ASSISTANT_ACCESS_TOKEN from a protected service environment or secret file, rather than leaving it on the command line. For a first run, though, the start command is:
home-assistant-matter-hub start--home-assistant-url="<HA_BASE_URL>"--home-assistant-access-token="<HA_LONG_LIVED_ACCESS_TOKEN>"--storage-location="<PERSISTENT_DATA_PATH>"--log-level=infoThe environment-variable rule is to uppercase the option, turn hyphens into underscores and add the HAMH_ prefix — so --storage-location maps to HAMH_STORAGE_LOCATION.
flowchart LR A["CLI option, e.g.
storage-location"] --> B["Uppercase every letter"] B --> C["Turn every hyphen
into an underscore"] C --> D["Add the HAMH prefix"] D --> E["HAMH_STORAGE_LOCATION"]
The complete Stable 2.0.55 yargs CLI / environment list
Every entry below comes from start-options-builder.ts at the exact commit, and is the complete yargs CLI / environment list. Those environment variables are produced by the yargs .env("HAMH") call: uppercase the long option, turn hyphens into underscores and add the prefix — the same rule from the previous section. Boolean, number and array values still have to match their type, and the IP allowlist can carry only one value in its environment-variable form.
| CLI option | Environment | Purpose and default |
|---|---|---|
--config | HAMH_CONFIG | Path to a JSON configuration file; keys may be kebabcase or camelcase. An empty string means no file; a path that does not exist, or invalid JSON, fails |
--log-level | HAMH_LOG_LEVEL | Application level: silly/debug/info/notice/warn/error/fatal; default info |
--protocol-log-level | HAMH_PROTOCOL_LOG_LEVEL | Level for the matter.js MessageChannel and Exchange, same set of values; default info, lower it only for protocol troubleshooting |
--disable-log-colors | HAMH_DISABLE_LOG_COLORS | Turns off ANSI colors; boolean, default false |
--json-logs | HAMH_JSON_LOGS | Writes structured JSON logs; boolean, default false |
--storage-location | HAMH_STORAGE_LOCATION | The data directory; npm defaults to an application folder in the user's home directory, and containers should persist /data |
--http-port | HAMH_HTTP_PORT | Port for the web application, default 8482; --web-port is a deprecated alias |
--http-ip-whitelist | HAMH_HTTP_IP_WHITELIST | Accepts IPv4, IPv6 or CIDR; repeatable on the CLI, one value only in ENV; when it is unset, every IP is allowed |
--mdns-disable-ipv4 | HAMH_MDNS_DISABLE_IPV4 | Turns off mDNS over IPv4 and uses IPv6 only; default false, which is not the same as turning off IPv6 |
--mdns-network-interface | HAMH_MDNS_NETWORK_INTERFACE | Restricts mDNS to a named LAN interface; do not guess the name, check Network Diagnostics first |
--mdns-strip-global-ipv6 | HAMH_MDNS_STRIP_GLOBAL_IPV6 | Strips the GUA out of mDNS so a controller cannot pick an address with no return path; default false |
--home-assistant-url | HAMH_HOME_ASSISTANT_URL | The HA HTTP(S) URL; required for a manual deployment |
--home-assistant-access-token | HAMH_HOME_ASSISTANT_ACCESS_TOKEN | The HA long-lived access token; required for a manual deployment, and it is a secret |
--home-assistant-refresh-interval | HAMH_HOME_ASSISTANT_REFRESH_INTERVAL | How often, in seconds, to refresh and detect new devices, entities and settings; default 60 |
--ha-message-timeout | HAMH_HA_MESSAGE_TIMEOUT | Timeout in milliseconds for a single HA WebSocket registry or action request; default 60000 |
--http-auth-username | HAMH_HTTP_AUTH_USERNAME | Optional HTTP Basic Auth user name; this is not a multi-account system |
--http-auth-password | HAMH_HTTP_AUTH_PASSWORD | Optional HTTP Basic Auth password; inject it as a secret and plan it together with the user name |
--http-base-path | HAMH_HTTP_BASE_PATH | Base path for a reverse-proxy subpath, default /; it has to match the WebSocket and API paths on the proxy |
| No CLI equivalent | HAMH_MATTER_SESSION_MAX_AGE_HOURS | Read directly by the bridge runtime, not through yargs; 0 disables it, and a non-zero value is clamped to 1–168. When it is unset, a standard bridge defaults to 0 (disabled) and Server Mode defaults to 4 hours |
HAMH_MATTER_SESSION_MAX_AGE_HOURS is a runtime-only exception: it is not a yargs option and has no CLI equivalent. --http-port still answers to its old alias --web-port, but the exact source explicitly marks that deprecated, so new deployments should use --http-port. Start options are not the same as everything visible on the add-on configuration page; the pinned add-on exposes only the options listed in its schema, and the rest are managed by the add-on entrypoint, Supervisor or the fixed packaging.
Backup, upgrade and rollback, in that order and no other
Bridge configuration, Matter operational state, mappings and other application data have to be managed together with the version. Backing up only the compose file or the add-on configuration page is not enough; the real storage or addon_config is what makes a restore work. Take a consistent backup before any upgrade, then record the current image or package version, and only then stop the service.
You photograph a room before you move the furniture, not after. The photo is worthless if you only take it once you already cannot remember where the sofa was. A backup taken before the upgrade is that photo; a backup you meant to take after something breaks is already too late to help.
-
Step 1
Take a consistent backup
For the add-on, use the Home Assistant backup and confirm it includes that add-on. For Docker or npm, stop writes or stop the service first, then back up the whole persistent data directory. Encrypt the backup itself and limit who can reach it.
-
Step 2
Record the version you can roll back to
Record Stable 2.0.55 and the deployment method, not the token. For Docker, keep an explicit tag you can pull again; for npm, record the package version; for the add-on, record the repository and the version.
-
Step 3
Change one layer at a time
When you upgrade the image or the package, leave the bridge filter, the port, the network interface and the HA token alone, so that a failure still tells you where it came from.
-
Step 4
Verify four layers after it starts
Confirm the process, the HA connection, that the bridge is running, and the state of your existing controllers, in that order. Do not rebuild a bridge because the version display has not updated; deal with the front-end version mismatch first.
-
Step 5
Restore both the data and the version on failure
Stop the failed version first, then restore the matching data backup and the original version. Do not hand a data directory that a newer version has already written to straight to an older version, unless the pinned-version docs explicitly support it.
flowchart TD A["Take a consistent backup
of the persistent data"] --> B["Record the current
version and method"] B --> C["Change one layer only:
the image or the package"] C --> D{"Do all four layers verify:
process, HA, bridge, controllers?"} D -->|"yes"| E["Done.
Back up the new known-good state"] D -->|"no"| F["Stop the new version,
restore backup and old version"]
A conservative setup for a 2–4 GB host
The upstream low-resource guide estimates: Node.js and the Matter cluster definitions take about 200–300 MB; the HA registry about 50–150 MB, growing with the entity count; each Matter endpoint about 1–3 MB; and a typical steady state for a medium install about 400–600 MB. These are estimates, not a guarantee or a hard minimum specification.
| Available RAM | Upstream starting point | What to watch |
|---|---|---|
| 2 GB | One or two bridges, no more than about 50 entities in total; turn off autoComposedDevices unless you need it | swap, OOM/exit 137, low-memory warnings at startup |
| 4 GB | Two to four bridges, in the guidance range of about 100–200 entities | memory-pressure log lines, competition with other large add-ons |
| 8 GB and up | The docs say no special setup is usually needed, but you should still monitor the actual endpoint count and workload | Do not misread enough RAM as meaning the controller or the network has no scale limit |
flowchart TD A["How much RAM does
the host have free?"] -->|"about 2 GB"| B["One or two bridges,
about 50 entities total.
Turn off autoComposedDevices"] A -->|"about 4 GB"| C["Two to four bridges,
about 100-200 entities"] A -->|"8 GB or more"| D["No special setup per the docs,
still watch endpoint count"]
Since v2.0.25 the application sets the Node heap dynamically at 25% of available memory, clamped to 256–1024 MB. The add-on entrypoint handles this automatically and you cannot override it from the add-on configuration page; with Docker or npm you can adjust it through NODE_OPTIONS, but you have to leave enough room for the system and for HA. If the last line is Killed, or the container exits 137 or is OOMKilled, first reduce entities and turn off heavy add-ons, then reassess RAM and swap. Do not rely on raising the heap without limit.
The failures that actually happen at install and first start
| Symptom | Likely cause | What to do |
|---|---|---|
| The add-on store does not show Stable | Wrong or stale repository, or you are reading the wrong slug | Check the repository URL, refresh the store, and identify the slug hamh; do not accept hamh-alpha or hamh-testing instead. Then cross-check that the host runs HA OS on a supported architecture |
| HA authentication failed | The token is incomplete, revoked, or the URL is not reachable | Do not paste the token into a log or a ticket. Check whether the secret is complete, whether the URL is a base URL the service can reach, and whether the token has been revoked; if needed, create a new token, swap it in safely, and revoke the old one immediately |
| The bridge is gone after a Docker rebuild | The volume mount points somewhere new, or permissions changed | Stop the container and check whether <PERSISTENT_DATA_PATH>:/data still points at the original data with the right permissions. Do not initialize an empty volume and carry on commissioning; restore from the backup first |
| The UI opens but commissioning finds nothing | Host network, IPv6 or mDNS is not actually working, even though the service is | Confirm host network, IPv6, mDNS and the network path to the controller. Open Network Diagnostics under Health to see which interface is actually bound; do not just change the HTTP port |
| The process keeps getting killed | Low memory on the host | Look at the container status, the exit code and the host OOM records. If it is low memory, reduce endpoints and turn off automatic composition you do not need or other heavy services, then handle swap and RAM according to your platform's policy |
| A start option change has no effect | Wrong name, wrong type, or the service did not restart | Cross-check the name, the type, the HAMH_ prefix, and whether the service restarted fully. The add-on can only use the fields its pinned schema exposes; do not assume every CLI option can be pasted straight into the add-on configuration |
Questions people ask before their first start
Which method should a Home Assistant OS user pick first?
Can Docker run without host network?
Does the add-on need the HA URL and token filled in by hand?
homeassistant_api: true, and its published schema has no URL or token field. Only a manual deployment — Docker or npm — requires those two start options.Can the token live in the Compose file?
--web-port: is it still usable?
--http-port, but the exact source already marks it deprecated. New setups should use --http-port / HAMH_HTTP_PORT.Do I have to commission everything again when I upgrade?
Pinned-version official and source-code references
- v2.0.55 release workflow: the npm package is renamed to
@riddix/hamhat publish time - v2.0.55 official installation docs (the npm package name is overridden by the release workflow)
- v2.0.55 source for every yargs start option
- v2.0.55 runtime-only session age parser, clamp and Server Mode default
- v2.0.55 low-resource device guide
- v2.0.55 README: Stable releases and the Docker entry point
- Pinned add-on Stable
config.yaml - Pinned add-on Stable changelog
Where to go from here
One of the three methods is running, the Web UI shows HA Online, and the network checks in this chapter passed.
Chapter 3 opens that Web UI properly: the Dashboard layout, where bridges and their status live, and the panels you will return to constantly once real devices are on the other end. Chapter 4 then walks you through creating your first bridge on top of the install you just finished.
Open the full guidePart 2 of the Home Assistant Matter Hub Complete Guide series on the Apporo blog.
Adapted from the Home Assistant Matter Hub Complete Guide, produced by WoowTech and released under CC BY 4.0. This adaptation is published by Apporo under the same licence.
Light · Air · Water · Control · apporo