Home Assistant
Description
Home Assistant is an open-source home automation platform that connects smart-home devices from many vendors behind a single local interface. It keeps device state, dashboards, and automation rules on the machine that runs it, and exposes them through a web interface, a REST API, and a built-in MCP server.
Overview
This role deploys Home Assistant as a container on its own canonical domain behind the reverse proxy, with the configuration directory kept in a persistent volume. It renders a configuration.yaml that trusts the proxy through use_x_forwarded_for and the project-wide trusted-proxy CIDRs, and it attaches the hub to a shared overlay network. With Hermes Agent deployed alongside it, the role declares the hub as the MCP server of the deployment: an internal /api/mcp endpoint plus the long-lived access token that MCP clients present.
Cosmos
The diagram places Home Assistant in the Infinito.Nexus cosmos: the components it deploys (capabilities), the central services it consumes (dependencies), and its outward reach (federation and bridged external networks).
flowchart LR
subgraph deps [Dependencies]
dep_svc_bkp_volume_2_local["svc-bkp-volume-2-local 💻"]
dep_svc_net_tor["svc-net-tor 🐳🐝"]
dep_web_app_dashboard["web-app-dashboard 🐳🐝"]
dep_web_app_flowise["web-app-flowise 🐳🐝"]
dep_web_app_hermes["web-app-hermes 🐳🐝"]
dep_web_app_keycloak["web-app-keycloak 🐳🐝"]
dep_web_app_openclaw["web-app-openclaw 🐳🐝"]
dep_web_app_openwebui["web-app-openwebui 🐳🐝"]
dep_web_app_prometheus["web-app-prometheus 🐳🐝"]
end
subgraph role [web-app-homeassistant 🐳🐝]
svc_homeassistant["homeassistant"]
svc_sso["sso ❌"]
svc_logout["logout ❌"]
svc_dashboard["dashboard"]
svc_prometheus["prometheus"]
svc_tor["tor"]
svc_container_backup["container_backup"]
svc_openwebui["openwebui"]
svc_hermes["hermes"]
svc_openclaw["openclaw"]
svc_flowise["flowise"]
end
dep_svc_bkp_volume_2_local -. "0..1" .-> svc_container_backup
dep_svc_net_tor -. "0..1" .-> svc_tor
dep_web_app_dashboard -. "0..1" .-> svc_dashboard
dep_web_app_flowise -. "0..1" .-> svc_flowise
dep_web_app_hermes -. "0..1" .-> svc_hermes
dep_web_app_keycloak -- "0..0" --> svc_sso
dep_web_app_openclaw -. "0..1" .-> svc_openclaw
dep_web_app_openwebui -. "0..1" .-> svc_openwebui
dep_web_app_prometheus -. "0..1" .-> svc_prometheus
linkStyle 5 stroke:red;
Solid 1:1 edges are fixed relationships; dashed 0..1 edges are conditional (enabled only in matching deployments); red 0..0 edges are turned off in this role. Node markers show the role's deploy modes (💻 host, 🐳 compose, 🐝 swarm); ❌ marks a service that is explicitly turned off, and ⚙️ an Ansible role dependency declared in meta/main.yml.
Features
- Containerized hub: Runs the official Home Assistant image on both the Docker Compose and Swarm stacks behind the reverse proxy.
- Reverse-proxy trust: Renders a
configuration.yamlwithdefault_config,use_x_forwarded_for, and the project-wide trusted-proxy CIDRs listed intrusted_proxies. In swarm the hub joins the proxy's own overlay, so the forwarded request arrives from that network rather than from the hub's, and trusting only the hub's subnet makes Home Assistant answer every proxied request with HTTP 400. - Persistent configuration: Mounts
/configas a named volume and hands it to the container backup service when volume backups are part of the deployment. - MCP server contract: Declares the built-in MCP server at
/api/mcpover streamable HTTP as an internal, bearer-token-authenticated endpoint, and generates the token that MCP clients present. Adding the MCP Server integration itself stays a Home Assistant onboarding step. - Token verified against the hub: Every deploy asks the hub whether the stored token still authenticates and re-mints it when the hub rejects it, then fails the deploy if the fresh token is rejected too. A hub whose
.storage/authwas recreated leaves a stored token pointing at a deleted refresh token, and clients would receive a 401 on every call. - Two-layer tool policy: Home Assistant offers no per-tool filter of its own; enabling the Assist API always publishes its actuating intents (
HassTurnOn,HassTurnOff, the todo-list writers). The role names those intools.mutating, andmutating_tools_enabled: falsewithholds them from every client's include list, so an agent is offered the read tools only. Entity exposure bounds the rest: the role exposes no entity to Assist, and making the hub actuate anything is an explicit operator step per entity. - Guest MCP probe: A Playwright spec asserts that an unauthenticated request to the MCP endpoint is never answered with a 2xx.
- Monitoring and dashboard entries: Registers the hub with the metrics and dashboard services when those are part of the deployment.
Quick Setup
Development
Clone, set up the workstation, and deploy Home Assistant onto the local stack:
git clone https://github.com/infinito-nexus/core.git
cd core
make onboard
make compose-deploy mode=reinstall apps=web-app-homeassistant full_cycle=false
Production
Run the published image to provision the inventory and deploy Home Assistant to a managed server (the mounted volume persists the inventory):
APP=web-app-homeassistant
HOST=<your-server>
DOMAIN=<your-domain>
TLS_MODE=self_signed
SSH_PUBLIC_KEY="<your-ssh-public-key>"
docker run --rm -it \
-v "$PWD/inventories:/etc/infinito.nexus/inventories" \
-e APP="$APP" -e HOST="$HOST" -e DOMAIN="$DOMAIN" -e TLS_MODE="$TLS_MODE" -e SSH_PUBLIC_KEY="$SSH_PUBLIC_KEY" \
ghcr.io/infinito-nexus/core/debian bash -c '
INVENTORY=/etc/infinito.nexus/inventories/production
infinito administration inventory provision "$INVENTORY" \
--inventory-file "$INVENTORY/devices.yml" \
--host "$HOST" \
--include "$APP" \
--vars "{\"TLS_MODE\": \"$TLS_MODE\", \"DOMAIN_PRIMARY\": \"$DOMAIN\", \"users\": {\"administrator\": {\"authorized_keys\": [\"$SSH_PUBLIC_KEY\"]}}}" &&
infinito administration deploy dedicated "$INVENTORY/devices.yml" \
--password-file "$INVENTORY/.password" \
--diff -vv'
MCP Server
Home Assistant ships the MCP server as a native integration. The role enables it
through mcp.enabled, which stays true only while an MCP client role is
part of the deployment.
Endpoint
| Property | Value |
|---|---|
| Transport | Streamable HTTP |
| URL | http://homeassistant:8123/api/mcp |
| Exposure | internal, container network only |
Auth
Clients present a long-lived access token as Authorization: Bearer <token>. The
token is minted once per deployment and kept in sys-token-store under the
administrator user, not in the role's credentials: block. An unauthenticated
request is answered with 404: Home Assistant does not reveal the endpoint.
Authorization subject
auth_subject: administrator: Home Assistant scopes the token to the account that minted
it. This deployment mints it for the administrator, so a call arrives as the
administrator whoever asked the client. Entity exposure still bounds the reach.
Getting to the tool server is gated on the role's mcp RBAC group.
Tool categories
tools/list returns 10 tools: entity control (HassTurnOn, HassTurnOff),
timers, broadcast, to-do list read and write, date and time, and GetLiveContext
for the current state.
Default state
Off. mcp.enabled is false unless web-app-flowise, web-app-hermes,
web-app-openclaw or web-app-openwebui is deployed alongside.
Tool scope
Two controls stack. The actuating tools are named in tools.mutating, and
mutating_tools_enabled: false withholds them from every client's include
list, so an agent is offered GetDateTime, GetLiveContext and
todo_get_items only. Entity exposure bounds those: only entities exposed to
Assist are reachable, and the role exposes none. Setting
mutating_tools_enabled: true offers the actuating tools as well; entity
exposure then decides what they can reach.
How to disable
Remove the MCP client roles from the deployment, or pin
mcp.enabled: false for this role in the inventory. The integration is
then not configured and the endpoint stops answering.
Credits
Implemented by Kevin Veen-Birkenbach. Part of the Infinito.Nexus Project and maintained by Kevin Veen-Birkenbach. Licensed under the Infinito.Nexus Community License (Non-Commercial).