Run a custom integration in its own container and bring it back to Home Assistant over MQTT

I built hass-remote-integration: a small container that runs one Home Assistant custom integration outside your main Home Assistant, and brings everything it produces back over MQTT: entities with MQTT discovery, services and a health signal.

Why? Custom integrations are often the fragile part of a setup. An HA upgrade breaks them, a library version conflicts, or a bug in one integration slows down the whole house. In its own container, the integration has its own HA Core and library versions, a crash stays isolated, and your main HA only sees MQTT.

What you get, all from a web UI (no HACS, no shell):

  • Install any custom integration from GitHub releases, a branch, a commit or a local folder
  • Preflight checks before changing anything, backups before every change, automatic rollback if a new version is unhealthy
  • Switch the Home Assistant version inside the container, including safe downgrades
  • Configure through the integration’s own config flow or YAML, or import settings and entity ids from a normal HA backup
  • Shadow mode: run it next to your main HA, compare entity by entity, then enable discovery with one click (and undo with one click)
  • Optional device in your main HA with update entities (integration, HA in the container, the manager itself) and memory / CPU / event-loop lag sensors
  • Small fixes for an integration or its libraries as patches, with an editor that checks them against the running code
  • Logs, a log file viewer, diagnostics, and an optional password for the UI

Quick start (image for amd64 and arm64: Raspberry Pi, Apple silicon, most NAS boxes)

mkdir hass-remote-integration && cd hass-remote-integration
curl -fsSLO https://github.com/trailro/hass-remote-integration/releases/latest/download/docker-compose.yml
docker compose up -d

Update later with docker compose pull && docker compose up -d.

Or build it from source (the latest release):

git clone https://github.com/trailro/hass-remote-integration.git && cd hass-remote-integration
git checkout "$(git describe --tags --abbrev=0)"
docker compose -f docker-compose.yml -f docker-compose.build.yml up -d --build

Then open http://<docker-host>:8087. You need Docker, an MQTT broker, and the MQTT integration on your main HA.

Good to know: it runs exactly one integration per container, and there is no HA frontend inside it. Keep it on a trusted network or set a password. I have been running it in shadow mode with a real integration next to my main HA.

Repository and full documentation: GitHub - trailro/hass-remote-integration: Run a Home Assistant integration in its own headless container and mirror it into the main HA over MQTT discovery · GitHub

Feedback, bug reports and ideas are very welcome. Issues and pull requests are open.

Here is how I use it today, as a real example.

My heating runs on Honeywell evohome, integrated with the ramses_cc custom integration and a radio stick. For the last days that integration has been running inside hass-remote-integration, in shadow mode, next to my main Home Assistant, which still runs its own copy. MQTT discovery stays off until I switch over. Device ids and addresses are masked in the screenshots.

Overview. One integration per container: ramses_cc 0.60.4 is running, healthy and publishing to MQTT. The timeline records every boot, restore, install, MQTT connection and health change.

Integration. All ramses_cc releases from GitHub. Each one can be checked with Preflight (requirements, patches, minimum HA version) before installing. The two patches I need for my setup are applied automatically at every start, and they retire themselves once upstream fixes the issue.

Devices. The controller, its zones, thermostats and radiator valves, grouped the way the integration reports them. These are the devices my main Home Assistant receives once discovery is on.

Log files. ramses_cc writes a packet log of the radio traffic. A small user-defined format splits each line into columns and colours requests and replies, so the traffic can be followed live in the browser.

MQTT. Every entity is published as a retained JSON document, together with the service catalog and a health document. Commands and service calls come back over MQTT, and discovery is one checkbox away.

System. The Home Assistant version inside the container can be updated or rolled back from here, with a backup taken before every change. Backups can be downloaded and restored, fully or in parts.

If your custom integration keeps breaking with Home Assistant updates, or you would like to test a new release without touching your main instance, give it a try. I’m happy to help anyone set it up.

Update: 0.16.1 is out, and the image is now on Docker Hub

You can now try it with a single command. No git clone, no compose file download:

docker run -d --name hass-remote-integration \
  --init --stop-timeout 240 --restart unless-stopped \
  -p 8087:8087 -v hass-remote-integration:/config \
  trailro26/hass-remote-integration:latest

Open http://<docker-host>:8087 and install your integration from the web UI. The first start installs Home Assistant inside the container, which takes a few minutes. Updating later is docker pull and recreate. Everything lives on the volume.

The image is published to Docker Hub (trailro26/hass-remote-integration) and GitHub Container Registry, with the same tags and digest, for amd64 and arm64. The compose setup from the first post still works as before.

What’s new since the first post:

  • MQTT 5, with automatic fallback to 3.1.1. Oversized messages can no longer break the broker connection, and retained commands are never replayed.
  • Config flows render real controls (durations, sliders with units, dates, colours, multi-selects) and use the integration’s own translations.
  • Security hardening from several external reviews: log searches and access logs never reveal secrets, and a crafted MQTT payload can no longer freeze the process.

Awesome project!
Since im also not a friend of custom integrations and dont want to use HACS, this seems like a good middleground!

Update: 0.24.0 is out

A lot has changed since 0.16.1. These are the parts you will notice.

It notices when an integration dies quietly, and brings it back. A real case from my heating: the TCP bridge to my radio stick restarted, and ramses_cc lost its connection without writing a single log line. Its entities stayed available, and its coordinator kept rewriting the same values, so everything looked healthy while no data came in. HRI can now judge an integration by when its values last changed (opt-in, per integration). The health watchdog first reloads the integration’s config entries, and only restarts Home Assistant in the container if that did not help. In a test of the same failure, the integration went degraded 3 minutes after the loss, the watchdog reloaded it a few minutes later, and data flowed again 2 seconds after the reload. The bug in the integration itself is fixed by a small patch, which HRI applies at every start until upstream fixes it.

Home Assistant versions. The container can run any Home Assistant from 2026.5.0 up to the newest. Before a switch, a preflight checks that the version’s requirements install on this image. It also warns you when your integration imports something that version of HA removed. You can tell HRI which version your main Home Assistant runs, so it never publishes a platform or device class that your main HA would reject.

System packages. HRI_APT_PACKAGES installs Debian packages at boot, for what pip cannot provide (ffmpeg, BlueZ tools, …). If your compose file is from 0.17.2 or older, download it again to use this.

Tested hard. Three independent code reviews, then an end-to-end campaign on amd64 and arm64 with a test integration that has an entity on every Home Assistant platform. It covered installs, upgrades and rollbacks, backups and restores, HA version switches, and commands sent from the main HA. It also counted the real passwords and tokens on every log and diagnostics surface: zero.

Shorter docs. The README is now a quick start and an everyday guide. The reference (MQTT, API, security, backups, health) lives in docs/.

Update with docker compose pull && docker compose up -d, or docker pull and recreate. Full release notes: Release v0.24.0 · trailro/hass-remote-integration · GitHub

@The-May thanks! That is exactly one of the reasons I built it: it installs straight from GitHub releases, so you don’t need HACS, and the integration never touches your main HA’s Python environment.

Thanks for the effort: just to clarify:
is there a specific reason on why not make a HA App (formerly Addon) of it?
you could basically make it a repo for docker deployment and as a addon which references your prebuilt container

see example:

name: "Signal CLI REST API"
description: "Signal CLI HA Addon/App"
version: "0.100"
slug: "signal_cli_rest_api"
init: false

arch:
  - amd64

image: bbernhard/signal-cli-rest-api
startup: services

options:
  mode: normal

schema:
  mode: list(normal|native|json-rpc|json-rpc-native)

environment:
  MODE: "{options.mode}"
  PORT: "8080"

map:
  - addon_config:rw

ports:
  8080/tcp: 8080

ports_description:
  8080/tcp: "REST API (external access)"

@The-May good question, and there is no fundamental reason. I develop and run it on plain Docker (my Home Assistant runs in a container too), so the app packaging simply hasn’t been done yet. It would fit well: an app is still a separate container, so the isolation stays exactly the same, and HA OS users are the people who can’t easily run ‘docker compose’.

It is a bit more than the config.yaml, though:

  • an app gets its options in `/data/options.json`, not as environment variables, so HRI has to read its settings from there;

  • Home Assistant inside needs up to 240 s to stop cleanly, so the app’s `timeout` has to be raised;

  • backups must exclude the Home Assistant installs inside the container, or every HA backup would carry several hundred MB;

  • the UI would start on its own port; showing it in the sidebar through ingress needs the UI to work under a path prefix, which it doesn’t yet.

I’ll put it on the list. If you run HA OS and would like to try a test version when it’s ready, let me know.

Update: on Home Assistant OS now, through HRI Manager (0.27.0 / manager 0.2.0)

@The-May it’s done, and it went a step further than a single app.

On HA OS, start with HRI Manager. An app has one slug, so installing HRI itself as an app gives you exactly one instance: one integration. HRI Manager is a separate app that runs as many HRI instances as you want, one integration each. From its page you create, update and remove them. Each instance is then an ordinary app with its own sidebar panel, Configuration tab, logs and backups, and its own container, so one integration still can’t take down another.

  1. Settings > Apps > App Store, ⋮ > Repositories, add https://github.com/trailro/hass-remote-integration-manager
  2. Install HRI Manager, turn on Show in sidebar, start it
  3. Open it, pick an HRI release, give the instance a name, create it. Then open the instance from the sidebar and install your integration there, as before.

The manager builds every instance from an HRI release (or a branch, for testing), checks that what the Supervisor installs is what it wrote, and only Home Assistant administrators can use it. It is still marked experimental. Screenshots are in its README.

If you only ever need one integration, HRI also installs directly as an app from https://github.com/trailro/hass-remote-integration (docs/app.md).

Either way, the four points from my last reply are covered. The app reads its options from the Supervisor and gets the 240 s it needs to stop cleanly. The UI works in the sidebar through ingress: Home Assistant’s login applies, and ingress_users limits who may open it. A Home Assistant backup of the app leaves out the Home Assistant installs inside it but keeps HRI’s own backups. It needs Core 2025.10 and Supervisor 2026.07.1 or newer, and I tested it on HA OS 18.3. If you installed 0.25.0 directly, update: 0.25.1 fixed a way to get around ingress_users.

What the manager adds on top:

  • Two instances of the same integration on one broker (HRI 0.26.0). Each manager instance publishes under its own MQTT identity, derived from its name. An install that already published keeps its topics and entity ids.
  • Host network, per instance (HRI 0.26.0 + manager 0.2.0). This is for integrations that find their devices by mDNS, SSDP or broadcast. Each instance gets its own port from the Supervisor, so instances never clash. On the host network, the instance’s port refuses LAN requests until the app has a password. The Home Assistant inside does not announce itself on your network.

0.27.0 fixes Remove orphans on the Cutover page. With two containers of integrations like a and a_binary on one broker, one could delete the other’s entities. New installs also get ids that can’t collide between integrations, and existing installs keep theirs.

Docker users: nothing changes, docker compose pull && docker compose up -d, one container per integration.

If you try the manager on HA OS, I’d like to hear how it goes.