Using homekit component inside Docker

mhhh I definitely have trouble with it running reliable. I suspect that I miss iptable rules since the bridge is seen and the hass HomeKit logs don’t look off at all.
The avahi service you posted is meant to be run on the host, right?
Thanks for sharing though. I’ll definitely tinker with it!

edit: may I ask how you configured your external network?

yes avahi service is configured on the host, that is, on the synology nas box.

as for network configuration if you mean docker network, there’s a ui in synology docker app that allows creation of external networks, i’m sure its not much more than a facade to docker network create. in fact, here:

root@nas:~# docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
...
e239xxxxxxxx        homeassistant       bridge              local
57efxxxxxxxx        ingress             bridge              local
...

Hi @rzen! You are such a big help in this and I have the feeling I almost got it working for me.
Can you show how you configure your homekit component in configuration.yaml?
I am on the latest Home Assistant version, have everything running in Docker behind a NGINX reverse proxy. I want to avoid having network_mode: host at all cost.

With the homeassistant.service I managed to get the bridge published, however, I cannot connect to it from Home.app. It seems, that I somehow need to get from the docker-ip (172.xxx) to the host-ip (192.168.1.8). Any ideas? How did you solve that part?

Thanks again!

my homekit config is very straightforward:

homekit:
  port: 51827
  auto_start: False
  filter:
    include_entities:
      - climate.thermostat
      - sensor.thermostat_temperature
      - sensor.thermostat_humidity
      - ...all entities for homekit listed here...

this is my complete docker-compose.yaml for HA (except for Host:xxx which is used to ingress traffic for HA via traefik):

version: '3.2'
networks:
  homeassistant:
    external: true
services:
  homeassistant:
    container_name: home-assistant
    image: homeassistant/home-assistant
    restart: always
    volumes:
      - ./config:/config
      - /etc/localtime:/etc/localtime:ro
    devices:
      - /dev/ttyACM1:/dev/ttyACM1
    ports:
      - 8123:8123
      - 51827:51827
    networks:
      - homeassistant
    labels:
      traefik.port: '8123'
      traefik.frontend.rule: Host:xxx
1 Like

Hi, thanks for the info, 3 questions

Are you running avahi native or in docker?
Wat is your avahi config?
What ip do you fill in the config yaml under advertise_ip, from the os, docker or hass container?

I’m using native avahi that came pre-installed on my Synology nas.

 $ cat /etc/avahi/avahi-daemon.conf
# This file is part of avahi.
#
# avahi is free software; you can redistribute it and/or modify it
# under the terms of the GNU Lesser General Public License as
# published by the Free Software Foundation; either version 2 of the
# License, or (at your option) any later version.
#
# avahi is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
# or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
# License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with avahi; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
# USA.

# See avahi-daemon.conf(5) for more information on this configuration
# file!

[server]
loglevel=0
#host-name=foo
#domain-name=local
#browse-domains=0pointer.de, zeroconf.org
use-ipv4=yes
use-ipv6=yes
#allow-interfaces=eth0
#deny-interfaces=eth1
#check-response-ttl=no
#use-iff-running=no
#enable-dbus=yes
#disallow-other-stacks=no
#allow-point-to-point=no
#cache-entries-max=4096
#clients-max=4096
#objects-per-client-max=1024
#entries-per-entry-group-max=32
ratelimit-interval-usec=1000000
ratelimit-burst=1000
aliases-conf=/var/tmp/nginx/avahi-aliases.conf

[wide-area]
enable-wide-area=yes

[publish]
#disable-publishing=no
#disable-user-service-publishing=no
#add-service-cookie=no
#publish-addresses=yes
#publish-hinfo=yes
#publish-workstation=yes
#publish-domain=yes
#publish-dns-servers=192.168.50.1, 192.168.50.2
#publish-resolv-conf-dns-servers=yes
#publish-aaaa-on-ipv4=yes
#publish-a-on-ipv6=no

[reflector]
#enable-reflector=no
#reflect-ipv=no

[rlimits]
#rlimit-as=
#rlimit-core=0
rlimit-data=4194304
#rlimit-fsize=0
rlimit-nofile=768
rlimit-stack=4194304
rlimit-nproc=3

[synology]
resolve-raop=yes
resolve-airplay=yes
resolve-airport=yes

This is a service descriptor for HA:

 $ cat /etc/avahi/services/homeassistant.service
<service-group>
  <name>Home Assistant Bridge</name>
  <service>
    <type>_hap._tcp</type>
    <port>51827</port>
    <txt-record>md=HA Bridge</txt-record>         <!-- friendly name                 -->

    <!-- the following appear to be mandatory -->
    <txt-record>pv=1.0</txt-record>               <!-- HAP version                   -->
    <txt-record>id=00:11:22:33:44:55</txt-record> <!-- MAC (from `.homekit.state`)   -->
    <txt-record>c#=2</txt-record>                 <!-- config version                -->

    <!-- the following appear to be optional -->
    <txt-record>s#=1</txt-record>                 <!-- accessory state               -->
    <txt-record>ff=0</txt-record>                 <!-- unimportant                   -->
    <txt-record>ci=2</txt-record>                 <!-- accessory category (2=bridge) -->
    <txt-record>sf=1</txt-record>                 <!-- 0=not paired, 1=paired        -->
    <txt-record>sh=UaTxqQ==</txt-record>          <!-- setup hash (used for pairing) -->
  </service>
</service-group>

In this configuration advertise_ip isn’t necessary. You can see my homekit config above in its entirety.

Best of luck!

1 Like

Thank you @rzen for all the tips! I finally got mine working!

For anyone on Raspberry Pi using Docker, here are additional pointers:

  • Don’t forget to clear out .homekit.state
  • I followed @rzen’s instructions but needed to update the MAC (id) on the host’s avahi service after home-assistant started
1 Like

Thanks for the help.

On Mac os i used this command to get mDNS to work correctly.

dns-sd -R Homeassistant _hap._tcp local 51827 md=”HA Bridge” pv=1.0 c#=2 id=00:11:22:33:44:55 s#=1 sf=1 ci=2 ff=0 sh=UaTxqQ== 

MAC-adress, as mentioned by others, should be the same as in .homekit.state

2 Likes

It works link a charm! You just save my day. :smiley:

Now I am having trouble adding HomeKit controller devices to HA.

Does anyone have HA running in Docker and HomeKit accessories (ecobee in my case) paired with HA?

Thanks, this command is working for me

Question, is ik posible to use dns-sd as deamon or something that runs automatic on the background?

edit:
For now I made an automator program that runs with the startup of macOS.

Just wanted to drop in here and post my solution. I’ve spent a lot of time getting a simple solution worked out, given the amount of time spent I feel that I must share.

Issue:
Running in network_mode: host would allow me to control my Ecobee3 Lite thermostat. This seems to use things related to mDNS, multicast, Bonjour, Homekit; I may be slightly wrong about that part.

How to pinpoint if you have the same issue:

  1. With Home Assistant running with network_mode: host, run:
docker exec [your home assistant docker container id here] python3 -m netdisco
  1. With Home Assistant running WITHOUT network_mode: host, run:
docker exec [your home assistant docker container id here] python3 -m netdisco

If #1 returns results but #2 does not, then you have the same situation as me and the solution below will probably work!

(side note: netdisco is documented here: https://www.home-assistant.io/integrations/homekit_controller/#home-assistant-cannot-discover-my-device)

Solution:
Add a container that repeats mDNS traffic from one network interface to another network interface. In my case I ran

docker exec [your home assistant docker container id here] ifconfig

and found that my Home Assistant container had a ip address of 192.168.80.7. To determine what network interface that’s on, I ran route -n and then found the 80 subnet (192.168.80.0) in the Destination column and then grabbed the interface name from the Iface column. I did the same for my host; find 0.0.0.0 and then grabbed the interface name from Iface.

Once you have the two network interface names, you can run a container to repeat mDNS between the two network interfaces.

Here’s a docker-compose example:

version: '3.8'

services:
  home-assistant:
    image: homeassistant/home-assistant
    ports:
    - 8123:8123

  mdns-repeater:
    image: angelnu/mdns_repeater
    network_mode: host
    environment:
    - hostNIC=enp4s0
    - dockerNIC=br-de87821a94e9

Also, here’s a link to my solution: https://github.com/TonyBrobston/tbro-server/blob/e3ff788e81c68848e20a5d325fe5c2e2484bf65d/home-automation/docker-compose.yml#L34-L40

I personally felt this was the best way to handle this problem, I feel like running network_mode: host on my Home Assistant container is opening up a bunch of things unbeknownst to me. I prefer to open only exactly as much as necessary. I realize that the mdns-repeater in my solution is running in network_mode: host, however I assume (probably a bad assumption) that the mdns-repeater isn’t doing anything more than repeating mDNS. I may look further into that repo later to be sure.

Hope this helps someone else!

7 Likes

Hey @TonyB . Appreciate you posting this. I really hope you are on Mac? because this solution may be just what I’m looking for.

Edit: NVM. #2 Does return results for me :confused:

Any solutions available for MacOS? I’m about to throw Docker out the window for this, but I really like the idea of having everything containerized.

To everyone who has HASS running in docker on Synology DSM
The Avahi Reflector doesn’t want to join docker mutlicast group for some reason. I suspect synology has modified it this way. I spent way to much time on it.
The only thing that helped me was

mdns-repeater:
    image: angelnu/mdns_repeater
    network_mode: host
    environment:
    - hostNIC=enp4s0
    - dockerNIC=br-de87821a94e9

@TonyB Amazing tips on running HA without host network! I just have one more thing to add.

I am also running Home Assistant in a Docker bridge network (without wanting to use network: host). The mdns-repeater sidecar container works amazingly well to forward mDNS packets in and out of a Docker bridge network.

However, I realise that in my setup, I had to also install avahi-daemon WITHIN the homeassistant container so that discovery would work. I don’t understand too much about the Avahi/Bonjour/SSDP protocols to explain why this is required.

I found out that this was required when following this guide on how to resolve mDNS queries from within a Docker container: mDNS, avahi and docker non-root containers. Basically, with the mdns-repeater container in the same bridge network, I was able to discover other devices using avahi-browse -alr with the above method.


My setup is thus as follows, after taking everything into account:

  1. Create a dedicated Docker bridge network homeassistant with docker network create homeassistant.
  2. The network interface of the newly created network is given by br-$(docker network ls | grep homeassistant | cut -d' ' -f1). You can use this to automatically substitute the value of the bridge network into the docker-compose file.
  3. In the HA Dockerfile, install avahi-daemon like as follows. This assumes we are using the Alpine-based images, which are default:
FROM homeassistant/home-assistant:2021.12.7

# Install avahi-daemon in container
# https://gnanesh.me/avahi-docker-non-root.html
RUN set -ex \
  && apk --no-cache --no-progress add avahi avahi-tools dbus \
  # Disable default Avahi services
  && rm /etc/avahi/services/* \
  && rm -rf /var/cache/apk/*

# Add our custom entrypoint
COPY docker-entrypoint.sh /usr/local/sbin/
ENTRYPOINT ["/usr/local/sbin/docker-entrypoint.sh"]

# Rest of your dockerfile here...
  1. Create a custom entrypoint entrypoint.sh:
#!/bin/bash
set -euxo pipefail

# Start dbus and avahi-daemon
dbus-uuidgen > /var/lib/dbus/machine-id
dbus-daemon --config-file=/usr/share/dbus-1/system.conf --print-address
avahi-daemon --daemonize

# Run anything else you want to run before HA starts...

# Run original entrypoint
exec /init

And voila, you should now be able to see integrations like HomeKit and Google Cast appearing in the integrations page automatically :slight_smile:

You can also verify this by running avahi-browse -alr in the HA container now, since avahi-tools is installed above.

2 Likes

Wow this works for me, many thanks, it’s a simple solution. Do you know if the docker NIC (Iface) can change? I set a static IP to my HA container.

Trying to get Homekit working while running HA without --net=host. Tried all the solutions from above and Homekit not working with docker · Issue #15692 · home-assistant/core · GitHub but could not get it working. Pairing does not succeed: Accessory Not Found.

Should these methods still work?

Could not edit previous post.

The mdsn repeater container solution still works. Not a fan because of the --net=host that it needs.

At this moment the Avahi reflector mode started working out of nowhere. Will test more.

I try my luck and hope somebody can help:

iam running HA in a bride network and have the mens repeater as container running in host network.

the HomeKit App does show the new bridge I can start the setup process but than it timed out and I can’t find where the problem is :confused: any idea ?