Home Assistant Integration
Home Assistant is Sanctum’s haus automation hub. It runs as a Docker container on the Mac Mini with bridge networking, integrating HomeKit devices and providing remote access through a Cloudflare tunnel. Sonos speakers are managed by a separate native bridge running directly on the Mac, because Docker bridge networking and Sonos callbacks have a relationship best described as “irreconcilable differences.”

Architecture
Section titled “Architecture”┌──────────────────────────────────────────────┐│ Mac Mini ││ ││ ┌─────────────────────────────────────────┐ ││ │ Sonos Bridge (native, port 18421) │ ││ │ SoCo → mDNS → 10 Sonos speakers │ ││ │ XTTS → port 8008 → Yoda voice │ ││ └──────────┬──────────────────────────────┘ ││ │ REST (host.docker.internal) ││ ┌──────────▼──────────────────────────────┐ ││ │ Docker (bridge network) │ ││ │ │ ││ │ ┌─────────────────────────────────┐ │ ││ │ │ Home Assistant Container │ │ ││ │ │ Port 8123 → Web UI │ │ ││ │ │ Port 21063 → HomeKit Bridge │ │ ││ │ │ SSH agent → VM access │ │ ││ │ └─────────────────────────────────┘ │ ││ └─────────────────────────────────────────┘ ││ ││ Cloudflare Tunnel → ha.example.net │└──────────────────────────────────────────────┘HA was migrated from the VM to Mac Docker because SLIRP networking on the VM proved unreliable for the number of integrations and real-time device communication required. Sonos was later extracted from HA entirely because Docker bridge networking on macOS couldn’t reliably maintain the bidirectional callback connection that Sonos requires. Two migrations, two networking problems, one closet.
Docker Configuration
Section titled “Docker Configuration”The container uses bridge networking rather than --network=host because host networking is not supported on macOS Docker. This is the polite way of saying “Docker on Mac is a compromise and we’ve all agreed to live with it.”
Key Settings
Section titled “Key Settings”| Setting | Value |
|---|---|
| Image | ghcr.io/home-assistant/home-assistant:stable |
| Network mode | bridge |
| Web UI port | 8123 |
| HomeKit port | 21063 |
| Config directory | ~/.openclaw/homeassistant/ |
| Restart policy | unless-stopped |
Compose File
Section titled “Compose File”The compose.yaml at ~/.openclaw/homeassistant/ defines the container with these essential directives:
- Port mappings: 8123:8123 (web), 21063:21063 (HomeKit)
- Volume mount: Local config directory into
/config - Extra hosts:
host.docker.internal:host-gatewayfor reaching Mac services from inside the container - SSH agent socket:
/run/host-services/ssh-auth.sockmounted for agent forwarding to the VM
Runtime: Colima, not Docker Desktop
Section titled “Runtime: Colima, not Docker Desktop”Docker Desktop on macOS is a virtualization layer pretending to be native. It runs a Linux VM, routes containers through it, and tells you that --network=host means host networking. It does not. It means the VM’s network — a thing that cannot see mDNS broadcasts, cannot discover HomeKit devices, and cannot be convinced otherwise no matter how many Stack Overflow answers suggest it should.
This matters because HA’s HomeKit Controller discovers Ecobee thermostats and similar devices via Bonjour/mDNS, which broadcasts to the local subnet — a subnet Docker Desktop’s VM is not on.
On March 28, 2026, Docker Desktop was replaced with Colima — a lightweight alternative that is, at its core, just a Lima VM running a Docker daemon. No GUI. No update nags. No Kubernetes toggle that nobody asked for. It starts in 12 seconds via launchd and exposes its Unix socket at:
DOCKER_HOST=unix:///Users/neo/.colima/default/docker.sockThe startup chain is intentionally sequential:
com.sanctum.colimaLaunchAgent starts Colima at bootlaunch-after-docker.shwaits for the Docker socket to appear- Once the socket is live, it brings up the Home Assistant and signal-cli containers
The migration itself was uneventful, which is the highest compliment infrastructure work can receive. Stop Desktop, start Colima, point DOCKER_HOST at the new socket, bring up the containers. The Ecobee sensors appeared in HA’s discovery panel within seconds. They had been broadcasting the entire time. Docker Desktop just couldn’t hear them.
Sonos Integration
Section titled “Sonos Integration”Sanctum manages 10 Sonos speakers across the haus. The speakers are not controlled through HA’s built-in Sonos integration. That integration is disabled. Instead, a native Python service called the Sonos Bridge runs directly on the Mac Mini, bypassing Docker entirely.
The bridge runs on port 18421 and exposes a REST API for speaker control, TTS announcements, and media playback. HA communicates with it via rest_command entries in configuration.yaml.
┌─────────────────────────────────────────────┐│ Mac Mini (native) ││ ││ ┌───────────────────────────────────────┐ ││ │ Sonos Bridge (port 18421) │ ││ │ SoCo → mDNS → 10 speakers on LAN │ ││ │ XTTS → Yoda TTS voice generation │ ││ └──────────┬────────────────────────────┘ ││ │ REST API ││ ┌──────────▼────────────────────────────┐ ││ │ Docker: Home Assistant │ ││ │ rest_command.sonos_tts → :18421/tts │ ││ │ rest_command.sonos_announce → :18421 │ ││ └───────────────────────────────────────┘ │└─────────────────────────────────────────────┘Why Not the HA Integration?
Section titled “Why Not the HA Integration?”Docker bridge networking on macOS cannot relay mDNS or SSDP discovery packets. The HA integration requires advertise_addr and static host IPs to compensate, but Sonos speakers still need to reach back into the container for event callbacks. This callback path breaks unpredictably after container restarts, Colima VZ networking warmups, and the occasional firmware update. We tried socat tunnels, socket_vmnet, and timed reload automations. None of it was reliable.
The native bridge uses SoCo directly on the Mac’s LAN interface. mDNS discovery works instantly. Speaker callbacks land on the Mac’s real IP. No tunnels, no NAT, no prayers.
HA REST Commands
Section titled “HA REST Commands”HA scripts and automations call the bridge through two REST commands:
rest_command: sonos_tts: url: "http://host.docker.internal:18421/tts" method: POST content_type: "application/json" payload: '{"rooms": {{ rooms }}, "text": "{{ message }}", "severity": "{{ severity }}"}' sonos_announce: url: "http://host.docker.internal:18421/announce" method: POST content_type: "application/json" payload: '{"rooms": {{ rooms }}, "text": "{{ message }}", "severity": "{{ severity }}"}'Severity maps to volume: low (30%), medium (50%), high (80%), critical (100%). The bridge handles XTTS generation, audio file serving, and Sonos playback in a single call.
Text-to-Speech
Section titled “Text-to-Speech”The bridge generates speech using the XTTS-v2 server on port 8008, saves the WAV file locally, and tells Sonos to fetch it from http://<mac-lan-ip>:18421/<id>.wav. The voice is Yoda. There was a discussion about this. Yoda won.
Bridge Management
Section titled “Bridge Management”# Check bridge healthcurl -s http://localhost:18421/health | python3 -m json.tool
# List all speakerscurl -s http://localhost:18421/speakers | python3 -m json.tool
# Manual TTS testcurl -X POST http://localhost:18421/tts \ -H 'Content-Type: application/json' \ -d '{"rooms": ["living_room"], "text": "Testing", "severity": "low"}'
# Restart bridgelaunchctl kickstart -k gui/$(id -u)/com.openclaw.sonos-bridgeSSH Agent Forwarding
Section titled “SSH Agent Forwarding”The HA container needs SSH access to the VM for certain automations and scripts. This is accomplished by mounting the Mac’s SSH agent socket into the container.
The SSH agent socket at /run/host-services/ssh-auth.sock is mapped as a volume in the compose file. Scripts inside the container can then SSH to ubuntu@10.10.10.10 using the Mac’s loaded SSH keys without storing any private keys in the container.
SSH wrapper scripts live at ~/.openclaw/ha-scripts/ and exec SSH directly to the VM with agent forwarding enabled.
Network Configuration
Section titled “Network Configuration”The configuration.yaml includes network-specific settings for the bridge networking environment:
homeassistant: internal_url: "http://192.168.1.10:8123" external_url: "https://ha.example.net"
http: use_x_forwarded_for: true trusted_proxies: - 172.16.0.0/12 - 192.168.64.0/20The trusted proxies cover Docker’s internal bridge subnets, allowing HA to correctly identify client IPs when accessed through the Cloudflare tunnel or Docker’s bridge network.
Remote Access
Section titled “Remote Access”There are two remote access paths into HA, each serving a different purpose. Because one way in would have been too simple, and simplicity is what other people have.
Browser Access (Cloudflare Tunnel)
Section titled “Browser Access (Cloudflare Tunnel)”For accessing the HA web UI from a browser, a Cloudflare tunnel provides HTTPS with Zero Trust access controls.
| Component | Details |
|---|---|
| Tunnel name | sanctum-hub |
| LaunchAgent | com.sanctum.tunnel |
| External URL | https://ha.example.net |
| Route | ha.example.net to localhost:8123 |
| Auth | Cloudflare Access OTP |
iPhone Companion App (Tailscale)
Section titled “iPhone Companion App (Tailscale)”The HA Companion app cannot handle Cloudflare Access’s login page, so it connects via Tailscale instead. Tailscale provides end-to-end WireGuard encryption, so HTTPS is not needed.
Companion App Setup
Section titled “Companion App Setup”-
Install Tailscale on iPhone and connect (do NOT enable exit node)
-
Install HA Companion
-
Open HA Companion → Settings → Companion App → Server & Connection
-
Configure connection URLs:
Field Value Internal URL http://<mac-lan-ip>:8123External URL http://<tailscale-ip>:8123 -
Under Internal Connection: add your haus Wi-Fi SSID so the app uses the LAN when haus
-
Enable Local Push for instant notifications on haus Wi-Fi
-
Test: turn off Wi-Fi briefly — the app should reconnect via Tailscale
HomeKit Bridge
Section titled “HomeKit Bridge”The HomeKit bridge runs on port 21063, allowing Apple Home app control of HA-managed devices.
| Setting | Value |
|---|---|
| Port | 21063 |
| Pairing code | 840-97-709 |
HomeKit entities are configured within HA’s integration settings. The bridge exposes selected devices to Apple Home while keeping the full HA device list available through the web UI.
Management
Section titled “Management”Starting and Stopping
Section titled “Starting and Stopping”# Start HAcd ~/.openclaw/homeassistant && docker compose up -d
# Stop HAcd ~/.openclaw/homeassistant && docker compose down
# View logsdocker logs -f homeassistant
# Restartcd ~/.openclaw/homeassistant && docker compose restartRollback
Section titled “Rollback”If the Mac Docker instance has issues, a rollback path exists to the VM:
- Stop the Mac container:
docker compose down - SSH to the VM:
ssh openclaw - Start the VM instance:
~/.openclaw/ha-docker.sh recreate