Home Assistant Integration
Type: How-to · Audience: User integrating Home Assistant
⚠ Partially stale. The deployment topology and HA addon blueprint below describe the pre-pivot architecture (MachineLink port 50180, WireGuard capabilities, Provider gRPC port 50190, join tokens). Under the current architecture (TF-state model), the management plane needs only the HTTP port (8080) — there is no MachineLink, no Provider gRPC, and no join token. Authoritative current architecture:
CONTEXT.md+docs/adr/. A full rewrite of this guide is tracked as a follow-up; until then, disregard the MachineLink/Provider-gRPC/join-token specifics below and expose onlyREZUSCLOUD_ADDR(HTTP :8080) plus the standard env vars fromAGENTS.md.
Running the RezusCloud management plane as a Home Assistant add-on — turning an always-on HA device into a personal cloud control plane with a sidebar panel.
This document defines the contract between two repos.
rezuscloud/rezuscloud(this repo) — provides the management plane binary + container imagerezuscloud/homeassistant-rezuscloud(add-on repo) — wraps it into an HA add-on withconfig.yaml,run.sh, and HAOS lifecycle integration
Architecture
Home Assistant OS Cloud / Edge
┌──────────────────────────────────────────┐ ┌──────────────┐
│ HA Sidebar │ │ Worker nodes │
│ ┌──────┬──────┬──────────┬─────────────┐ │ │ (Talos) │
│ │ Over │ Conf │ RezusCl… │ Energy │ │ │ │
│ │ view │ ig │ ☁️ │ │ │ │ │
│ └──────┴──────┴──────────┴─────────────┘ │ │ │
│ │ │ │
│ ┌──────────────────────────────────────┐ │ │ │
│ │ RezusCloud Ingress Panel │ │ │ │
│ │ (iframe → localhost:3000) │ │ │ │
│ │ │ │ │ │
│ │ Dashboard │ Tenants │ Machines │ │ │ │
│ │ │ │ │ │
│ └──────────────────────────────────────┘ │ │ │
│ │ │ │
│ ┌──────────────────────────────────────┐ │ │ │
│ │ HA Supervisor │ │ │ │
│ │ ┌──────────────────────────────────┐ │ │ │ │
│ │ │ rezuscloud container │ │ │ │ │
│ │ │ │ │ │ │ │
│ │ │ /usr/local/bin/rezuscloud │ │ │ │ ───> │ hetzner │
│ │ │ ├── HTTP/WebUI :3000 │ │ │ │ ───> │ oci │
│ │ │ ├── MachineLink :50180 │ │ │ │ ───> │ edge metal │
│ │ │ ├── Provider gRPC :50190 │ │ │ │ ───> │ home RPi │
│ │ │ └── SQLite /data/ │ │ │ │ └──────────────┘
│ │ └──────────────────────────────────┘ │ │
│ └──────────────────────────────────────┘ │
└──────────────────────────────────────────┘
What the Add-On Repo Must Build
The add-on repo (rezuscloud/homeassistant-rezuscloud) is a standard HA add-on structure:
homeassistant-rezuscloud/
├── config.yaml # HA add-on configuration (ingress, panel, options)
├── DOCS.md # Documentation shown in HA add-on store
├── Dockerfile # Multi-stage: pull rezuscloud image + HA base
├── run.sh # Entry point: configure + exec rezuscloud
├── translations/
│ └── en.yaml # Option labels and descriptions
├── icon.png # Add-on icon (shown in HA add-on store)
└── README.md # Repository README
config.yaml
This is the critical file that makes RezusCloud appear in the HA sidebar:
name: "RezusCloud"
description: "Personal cloud management — run Kubernetes clusters from your home"
version: "0.1.0"
slug: "rezuscloud"
url: "https://github.com/rezuscloud/homeassistant-rezuscloud"
# -- Sidebar panel (this is what makes it appear in HA sidebar) --
ingress: true # Enable ingress → sidebar entry
ingress_port: 3000 # Internal port rezuscloud listens on
ingress_stream: true # Stream requests (for SSE/WebSocket)
panel_icon: "mdi:cloud" # MDI icon in sidebar
panel_title: "RezusCloud" # Sidebar text (defaults to name)
panel_admin: true # Only visible to admin users
# -- Lifecycle --
init: false # We use our own entrypoint (run.sh)
startup: "services" # Start after core HA services
boot: "manual" # Don't auto-start on first install
# -- Architecture --
arch:
- aarch64 # RPi 4/5, HA Green/Yellow
- amd64 # Intel NUC, mini PC
# -- Privileges (needed for Docker-in-Docker: Talos containers) --
host_network: true # Needed for MachineLink + WireGuard
docker_api: true # Read-only Docker API access
privileged:
- NET_ADMIN # WireGuard/MachineLink tunnel
- SYS_ADMIN # Docker container management
- NET_RAW # Raw socket access for CNI
full_access: true # Full hardware access for Talos containers
apparmor: false # Disable AppArmor (conflicts with privileged ops)
# -- Storage --
map:
- data:rw # /data for persistent SQLite state
# -- Watchdog --
watchdog: "http://[HOST]:[PORT:3000]/healthz"
# -- User-configurable options --
options:
auto_start: false
join_token: ""
ingress_type: "direct"
backup_enabled: false
backup_s3_endpoint: ""
backup_s3_bucket: ""
schema:
auto_start: bool
join_token: password?
ingress_type: list(direct|cloudflare|ngrok)
backup_enabled: bool
backup_s3_endpoint: str?
backup_s3_bucket: str?
Key config.yaml fields explained
| Field | Value | Why |
|---|---|---|
ingress: true |
Required | This is what creates the sidebar entry. Without it, the add-on is invisible in the HA UI. |
ingress_port: 3000 |
Internal port | HA supervisor proxies http://addon-rezuscloud:3000 into an iframe in the HA frontend. |
ingress_stream: true |
Stream mode | Needed for SSE (live events), HTMX partial responses, and WebSocket connections from the WebUI. |
panel_icon: mdi:cloud |
Cloud icon | Material Design Icons — appears next to "RezusCloud" in the sidebar. |
panel_admin: true |
Admin-only | Only admin HA users see the panel. Non-admin users can't manage clusters. |
host_network: true |
Host network | MachineLink needs to accept incoming TCP connections on port 50180. Ingress won't route gRPC. |
docker_api: true |
Docker access | The management plane creates Talos containers via the Docker socket. |
privileged: [NET_ADMIN, SYS_ADMIN, NET_RAW] |
Capabilities | Required for WireGuard tunnel (MachineLink) and Docker-in-Docker. |
full_access: true |
Full access | Talos containers need device access, cgroup manipulation, and mount operations. |
apparmor: false |
No AppArmor | AppArmor blocks the privileged operations needed for Talos containers. |
watchdog |
healthz | HA supervisor monitors /healthz and restarts the add-on if unhealthy. |
Dockerfile
# Multi-stage: pull the rezuscloud binary from GHCR
FROM ghcr.io/rezuscloud/rezuscloud:latest AS rezuscloud
# Use HA base image
FROM ghcr.io/home-assistant/base:latest
# Copy binary from release image
COPY --from=rezuscloud /usr/local/bin/rezuscloud /usr/local/bin/rezuscloud
RUN chmod +x /usr/local/bin/rezuscloud
# Copy entrypoint
COPY run.sh /run.sh
RUN chmod a+x /run.sh
CMD ["/run.sh"]
run.sh
#!/usr/bin/with-contenv bashio
set -e
# -- Configure from HA add-on options --
export REZUSCLOUD_DATA_DIR="/data/rezuscloud"
export REZUSCLOUD_ADDR=":3000"
export REZUSCLOUD_MACHINELINK_ADDR=":50180"
export REZUSCLOUD_PROVIDER_ADDR=":50190"
export REZUSCLOUD_MODE="standalone"
# Join token (from HA options UI)
if bashio::config.has_value 'join_token'; then
export REZUSCLOUD_JOIN_TOKEN="$(bashio::config 'join_token')"
fi
# Backup configuration
if bashio::config.true 'backup_enabled'; then
export REZUSCLOUD_BACKUP_ENABLED="true"
export REZUSCLOUD_BACKUP_S3_ENDPOINT="$(bashio::config 'backup_s3_endpoint')"
export REZUSCLOUD_BACKUP_S3_BUCKET="$(bashio::config 'backup_s3_bucket')"
fi
# Ensure data directory exists
mkdir -p "${REZUSCLOUD_DATA_DIR}"
# -- Health check announcement --
bashio::log.info "RezusCloud management plane starting"
bashio::log.info " WebUI: http://localhost:3000"
bashio::log.info " MachineLink: :50180"
bashio::log.info " Provider: :50190"
# -- Run the management plane --
exec rezuscloud
Ingress Panel Behavior
When ingress: true is set:
- HA Supervisor starts the add-on container
- Supervisor creates a reverse proxy from the HA frontend to
http://addon-rezuscloud:3000 - A sidebar entry appears with
panel_icon(mdi:cloud) andpanel_title("RezusCloud") - Clicking the sidebar entry loads the RezusCloud WebUI inside an iframe in the HA frontend
- All requests go through HA's auth proxy — the user's HA session is used
Important constraints for the WebUI (in rezuscloud repo):
- No authentication redirect — HA ingress handles auth. The WebUI should not prompt for login when accessed via ingress. Detect the
X-Hass-Sourceheader. - Relative URLs only — the WebUI is served under
/api/hassio_ingress/.... All internal links must be relative (no absolute paths like/api/v1/tenants— useapi/v1/tenants). - CSP headers — HA sets strict Content-Security-Policy. The WebUI must work within it (no inline scripts except Alpine.js, HTMX is fine).
- No iframe breakout — don't set
X-Frame-Options: DENYon the HTTP server.
What This Repo (rezuscloud) Must Provide
The rezuscloud binary must:
| Requirement | Implementation |
|---|---|
| Listen on port 3000 | REZUSCLOUD_ADDR=:3000 |
Serve WebUI at / |
templ + Alpine.js + HTMX |
Serve health at /healthz |
Returns 200 OK |
Serve API at /api/v1/... |
REST endpoints |
| Detect ingress mode | Check X-Hass-Source header, skip auth UI |
| Use relative URLs | All WebUI links are relative |
| Work without TLS | HA ingress terminates TLS |
Store state in /data/ |
REZUSCLOUD_DATA_DIR=/data/rezuscloud |
| Accept Docker socket | /var/run/docker.sock mounted by HA supervisor |
| Run as PID 1 | exec rezuscloud in run.sh — no s6, no init system |
| Work without K8s | Standalone mode (SQLite) — no K8s dependency |
| Multi-arch | linux/amd64 + linux/arm64 via GHCR |
What the Add-On Repo Must Build
The add-on repo (rezuscloud/homeassistant-rezuscloud) is responsible for:
| Responsibility | Details |
|---|---|
config.yaml |
HAOS add-on config (ingress, panel, privileges, options schema) |
Dockerfile |
Pull rezuscloud from GHCR + HA base image |
run.sh |
Configure env vars from HA options, exec binary |
DOCS.md |
User-facing docs shown in HA add-on store |
translations/en.yaml |
Option labels for the HA configuration UI |
| CI pipeline | Build add-on image, publish to GHCR |
| Version tracking | version in config.yaml matches rezuscloud image tag |
| Testing | Validate add-on installs on HAOS, sidebar appears, WebUI loads |
Requirements
- Home Assistant OS or Supervised — add-ons don't work on HA Container
- Docker access — the add-on needs Docker socket for Talos containers
- Minimum 4 GB RAM — management cluster components need headroom
- Persistent storage — SQLite state stored in
/data/rezuscloud(HA volume, survives restarts) - ARM64 or AMD64 — multi-arch image supports both
User Experience
- User adds the add-on repository URL to HA
- Installs "RezusCloud" from the HA add-on store
- ☁️ RezusCloud appears in the HA sidebar
- Click → WebUI dashboard opens inside HA
- User creates tenants, issues join tokens, downloads Talos images
- Machines boot, connect via MachineLink, receive config
- All visible from the HA sidebar — no separate port, no separate login