👍 What we like
- ✓Supports a large number of Zigbee devices across brands, with no proprietary hub
- ✓Automatic device discovery in Home Assistant through MQTT
- ✓File-based configuration that's easy to back up and reproduce
- ✓Runs 100% locally, with no cloud
👎 What to watch
- ✕Three services to maintain (broker, Zigbee2MQTT, Home Assistant)
- ✕Dongle compatibility must be checked: not every chip is recommended
- ✕Losing the network key or changing the channel means re-pairing your devices
- ✕The Container edition of Home Assistant doesn't offer apps (add-ons)
🏆 Our picks
Affiliate links · same price for youEnergenie EDZB1943W Zigbee USB Stick
Amazon · price and availability on the listing
Intel NUC Kit NUC8I7HBN
Amazon · price and availability on the listing
See all our recommended gear in the shop.
📑 Contents ▾
- 01 Prerequisites
- 02 Step-by-step installation
- · Step 1: Install Docker Engine and the Compose plugin
- · Step 2: Identify the Zigbee dongle
- · Step 3: Create the folder layout and configure Mosquitto
- · Step 4: Write the Zigbee2MQTT configuration
- · Step 5: Create the compose.yaml file
- · Step 6: Start the stack
- · Step 7: Set up Home Assistant and the MQTT integration
- · Step 8: Pair Zigbee devices
- · Step 9: Create a first automation
- 12 Verification checks
- 13 Security and best practices
- 14 Troubleshooting common errors
- 15 FAQ
- · Is the configuration.yaml file mandatory?
- · Which Zigbee devices are supported?
- · How do I update Home Assistant?
- · What if I use Home Assistant OS?
- · Can I use ZHA and Zigbee2MQTT at the same time?
- 21 Read also
- 22 Host this yourself
This guide sets up a complete Zigbee home automation stack on a Linux server with Docker. Mosquitto is the MQTT broker, Zigbee2MQTT drives the Zigbee dongle and Home Assistant provides the interface and automations. The idea is simple. Zigbee2MQTT talks to Zigbee devices (bulbs, plugs, sensors) through the dongle and publishes their state to the MQTT broker. Home Assistant connects to that broker, not to Zigbee2MQTT, and discovers the devices automatically through MQTT discovery. Without a broker nothing works: Zigbee2MQTT won’t start and Home Assistant has nothing to integrate.
All three services run from a single Compose file. They stay reachable from your local network only.
Prerequisites
- An up-to-date 64-bit Linux server (this guide uses Ubuntu Server 24.04 LTS) with
sudoaccess. An x86 mini-PC such as the Intel NUC Kit NUC8I7HBN works as a Docker host. Be aware that it’s a “barebone” kit: make sure RAM and an SSD are installed. - A USB Zigbee adapter (coordinator). Zigbee2MQTT recommends adapters with Texas Instruments (Z-Stack), Silicon Labs (EmberZNet) or Dresden Elektronik (deCONZ) chips. The Energenie EDZB1943W Zigbee USB Stick is not on Zigbee2MQTT’s official adapter list, and we found no official spec sheet that gives its chip. Before using it, identify its chip (step 2) and check that the chip is listed at https://www.zigbee2mqtt.io/guide/adapters/. If it isn’t, pick an adapter from that list.
- A fixed IP address on your local network (a reserved DHCP lease on your router). You do not need a domain name or any ports opened to the Internet.
- If possible, a short USB extension cable to keep the dongle away from the server and its USB 3 ports, a known source of 2.4 GHz interference.
Step-by-step installation
Step 1: Install Docker Engine and the Compose plugin
The official script installs Docker Engine and the Compose v2 plugin (the docker compose command, with a space). Don’t install the old docker-compose v1 package, which is no longer maintained.
curl -fsSL https://get.docker.com -o get-docker.sh
sudo sh get-docker.sh
sudo usermod -aG docker $USER
# Log out and back in so the group membership takes effect
Check:
docker --version
docker compose version
docker run --rm hello-world
The first two commands print a version and the third prints “Hello from Docker!”. Membership in the docker group is equivalent to root access, so only add trusted accounts.
Step 2: Identify the Zigbee dongle
Plug in the dongle, then run:
lsusb
ls -l /dev/serial/by-id/
Write down the full path, which looks like /dev/serial/by-id/usb-…-if00-port0. This path is stable, unlike /dev/ttyUSB0 or /dev/ttyACM0, which can change after a reboot. The lsusb line and the by-id link name often show the USB chip vendor. For the Zigbee chip itself, check your dongle maker’s documentation. The chip sets the adapter value in step 4: zstack (Texas Instruments), ember (Silicon Labs), deconz (ConBee/RaspBee), zigate or zboss.
Check: ls -l /dev/serial/by-id/ should list one link for your dongle. If the folder doesn’t exist, see Troubleshooting.
Step 3: Create the folder layout and configure Mosquitto
mkdir -p ~/domotique/{mosquitto/config,mosquitto/data,mosquitto/log,zigbee2mqtt/data,homeassistant/config}
cd ~/domotique
nano mosquitto/config/mosquitto.conf
Contents of mosquitto.conf:
persistence true
persistence_location /mosquitto/data/
log_dest stdout
listener 1883
allow_anonymous false
password_file /mosquitto/config/passwd
Since version 2.0, Mosquitto requires you to choose an authentication method explicitly. Here, anonymous connections are refused. Now create two accounts, one for Zigbee2MQTT and one for Home Assistant (you’ll be prompted for each password):
docker run --rm -it -v "$PWD/mosquitto/config:/mosquitto/config" eclipse-mosquitto:2 \
mosquitto_passwd -c /mosquitto/config/passwd zigbee2mqtt
docker run --rm -it -v "$PWD/mosquitto/config:/mosquitto/config" eclipse-mosquitto:2 \
mosquitto_passwd /mosquitto/config/passwd homeassistant
Use -c for the first command only, because it overwrites an existing file.
Check:
cat mosquitto/config/passwd
You should see two lines, zigbee2mqtt:$7$… and homeassistant:$7$…, with hashed passwords rather than plain text.
Step 4: Write the Zigbee2MQTT configuration
First, generate a token to protect the web interface:
openssl rand -hex 32
nano ~/domotique/zigbee2mqtt/data/configuration.yaml
version: 5
homeassistant:
enabled: true
frontend:
enabled: true
port: 8080
auth_token: PASTE_THE_GENERATED_TOKEN_HERE
mqtt:
base_topic: zigbee2mqtt
server: mqtt://mosquitto:1883
user: zigbee2mqtt
password: ZIGBEE2MQTT_ACCOUNT_PASSWORD
serial:
port: /dev/ttyACM0
adapter: ember # replace to match your chip: zstack, ember, deconz, zigate or zboss
advanced:
channel: 11
network_key: GENERATE
pan_id: GENERATE
ext_pan_id: GENERATE
A few things to know:
mqttandserialare top-level sections (there is nobridgekey).mosquittois the service name in the step 5 Compose file.serial.portis the path inside the container. The Compose file maps the host’sby-idpath to it.version: 5follows the current documentation example. If your image is older, check the expected value in the documentation for your version.- On first start,
GENERATEis replaced with random keys. Back up this file: if you lose thenetwork_key, you’ll have to re-pair every device. - Changing the channel later means re-pairing your devices. The documentation advises choosing a channel away from your 2.4 GHz Wi-Fi channel.
- You don’t write the
devices:section yourself. Zigbee2MQTT fills it in as you pair devices, as a map keyed by each device’s IEEE address (for example'0x00158d0001234567': friendly_name: living_room_sensor). The coordinator is never listed there.
chmod 600 ~/domotique/zigbee2mqtt/data/configuration.yaml
Check: python3 -c "import yaml,sys; yaml.safe_load(open(sys.argv[1]))" ~/domotique/zigbee2mqtt/data/configuration.yaml should print no error. If the module is missing, install it with sudo apt install python3-yaml.
Step 5: Create the compose.yaml file
nano ~/domotique/compose.yaml
services:
mosquitto:
image: eclipse-mosquitto:2
container_name: mosquitto
restart: unless-stopped
ports:
- "127.0.0.1:1883:1883" # reachable from the host only
volumes:
- ./mosquitto/config:/mosquitto/config
- ./mosquitto/data:/mosquitto/data
- ./mosquitto/log:/mosquitto/log
zigbee2mqtt:
image: ghcr.io/koenkk/zigbee2mqtt
container_name: zigbee2mqtt
restart: unless-stopped
depends_on:
- mosquitto
ports:
- "8080:8080" # web interface
volumes:
- ./zigbee2mqtt/data:/app/data
- /run/udev:/run/udev:ro
environment:
- TZ=Europe/Paris
devices:
- /dev/serial/by-id/REPLACE_WITH_YOUR_DONGLE:/dev/ttyACM0
homeassistant:
image: ghcr.io/home-assistant/home-assistant:stable
container_name: homeassistant
restart: unless-stopped
network_mode: host
privileged: true
volumes:
- ./homeassistant/config:/config
- /etc/localtime:/etc/localtime:ro
- /run/dbus:/run/dbus:ro
environment:
- TZ=Europe/Paris
There’s no version: key (obsolete) and no docker-compose: key. The whole Zigbee2MQTT data folder is mounted at /app/data, so the configuration, device database and state persist. Home Assistant runs with network_mode: host, as in the official documentation, so it reaches Mosquitto at 127.0.0.1:1883. Zigbee2MQTT reaches it over the internal Compose network (mosquitto:1883).
Check:
cd ~/domotique && docker compose config --quiet && echo OK
Step 6: Start the stack
docker compose up -d
docker compose ps
docker compose logs -f zigbee2mqtt
Check: all three containers are running (or Up). The Zigbee2MQTT logs should show the connection to the MQTT server and then the startup message (Zigbee2MQTT started!), with no serial port error. Exit with Ctrl+C. Next, check the broker:
docker compose exec mosquitto mosquitto_sub -h localhost -u homeassistant -P 'HA_PASSWORD' \
-t 'zigbee2mqtt/bridge/state' -C 1 -v
The expected output is zigbee2mqtt/bridge/state {"state":"online"}. Finally, open http://SERVER_IP:8080 and enter the auth_token: the Zigbee2MQTT interface appears.
Step 7: Set up Home Assistant and the MQTT integration
- Open
http://SERVER_IP:8123and create the owner account. - Go to Settings > Devices & services, click Add Integration (bottom right) and choose MQTT.
- Enter the broker details: host
127.0.0.1, port1883, userhomeassistantand its password.
The default discovery prefix, homeassistant, matches what Zigbee2MQTT uses with homeassistant: enabled: true. Leave it unchanged.
Check: under Settings > Devices & services, the MQTT integration shows no error, and a “Zigbee2MQTT Bridge” device is listed among its devices.
Step 8: Pair Zigbee devices
In the Zigbee2MQTT interface (port 8080), click the Permit join button at the top of the page. Joining is temporary and stops on its own when the countdown ends. Then put the device into pairing mode as its manual describes: reset, long press, and so on. Pair it close to the dongle or to a Zigbee router (usually a mains-powered device).
Check: the device appears in the Devices tab with its model recognised. The logs show that the “interview” completed successfully. In Home Assistant, the device and its entities appear under the MQTT integration. Give it a meaningful name in Zigbee2MQTT before you build automations.
Step 9: Create a first automation
In Home Assistant, go to Settings > Automations & scenes > Create automation. For example: a “Device” trigger using your motion sensor, an optional condition, and a “Device” action that turns on your bulb.
Check: trigger the sensor. The automation’s trace, in the automation’s ⋮ menu, shows the run and the bulb turns on.
Verification checks
cd ~/domotique
docker compose ps # 3 services running
curl -s -o /dev/null -w '%{http_code}\n' http://localhost:8080 # expect 200
curl -s -o /dev/null -w '%{http_code}\n' http://localhost:8123 # expect 200
docker compose logs --tail 50 zigbee2mqtt | grep -i error # ideally empty
Other checks: the Map tab in Zigbee2MQTT shows the network mesh. In Home Assistant, your devices’ entities should change state when you operate them.
Security and best practices
- Nothing is exposed to the Internet. Don’t forward ports 1883, 8080 or 8123 on your router. For remote access, use a VPN (WireGuard, for example).
- Here, Mosquitto listens on
127.0.0.1only. If other clients on your LAN need to connect, publish the port on the server’s LAN IP ("192.168.1.10:1883:1883") and keep authentication on. Ports published by Docker bypass UFW rules, so don’t rely on the host firewall to filter them. - Keep the
auth_tokenon the Zigbee2MQTT interface and use separate MQTT passwords for each client.configuration.yamlholds secrets in plain text, hence thechmod 600. - Backups: back up all of
~/domotique/regularly, especiallyzigbee2mqtt/data(configuration, network keys, device database) andhomeassistant/config. - Updates: read the release notes, then run
docker compose pull && docker compose up -d. Avoid unattended automatic updates.
Troubleshooting common errors
- Symptom: Zigbee2MQTT stops with an error opening the serial port.
- Cause: wrong
by-idpath underdevices:, the dongle is in use by another service (the ZHA integration, for example) or theadaptervalue is wrong. - Fix: check
ls -l /dev/serial/by-id/, correctcompose.yamlandadapter, then restart withdocker compose up -d. Only one program can use a dongle at a time.
- Cause: wrong
- Symptom:
/dev/serial/by-id/doesn’t exist on Ubuntu.- Cause: the
brlttyservice (braille displays) sometimes grabs dongles with CH340/CH341 USB chips. - Fix: check with
sudo dmesg | grep -i -E 'tty|brltty'. If you don’t use a braille display, remove it withsudo apt remove brlttyand re-plug the dongle.
- Cause: the
- Symptom:
Connection refusedorNot authorizedin the MQTT logs.- Cause: wrong credentials or a missing
passwdfile. - Fix: check
docker compose logs mosquitto, recreate the account withmosquitto_passwd(without-c), then rundocker compose restart mosquitto.
- Cause: wrong credentials or a missing
- Symptom: pairing fails.
- Cause:
Permit joinis off, the device is too far away, or there’s Wi-Fi or USB 3 interference. - Fix: turn
Permit joinback on, move the device closer, use a USB extension cable and check that the device is on the supported devices list.
- Cause:
- Symptom: Home Assistant doesn’t see the devices.
- Cause: the integration points to the wrong host, or discovery is disabled.
- Fix: the integration must point to the broker (
127.0.0.1:1883), andhomeassistant: enabled: truemust be set in the Zigbee2MQTT configuration.
FAQ
Is the configuration.yaml file mandatory?
Yes. Zigbee2MQTT reads its settings from data/configuration.yaml. Recent versions may offer a web onboarding wizard on first start if the file is missing (check the documentation for your version), but the wizard produces the same file. Writing it yourself, as in step 4, makes the setup reproducible.
Which Zigbee devices are supported?
See the official “Supported devices” list at https://www.zigbee2mqtt.io/supported-devices/. It’s generated from the zigbee-herdsman-converters project and shows the features exposed for each model.
How do I update Home Assistant?
With Docker, you update by pulling a new image: docker compose pull homeassistant && docker compose up -d homeassistant. HACS has nothing to do with this: it installs community integrations and cards, not Home Assistant updates.
What if I use Home Assistant OS?
Home Assistant OS lets you install Mosquitto and Zigbee2MQTT as apps (formerly “add-ons”) from its interface. The logic is the same: MQTT broker, Zigbee2MQTT, then the MQTT integration. This guide covers the “Container” installation under Docker, which doesn’t offer those apps.
Can I use ZHA and Zigbee2MQTT at the same time?
Not with the same dongle. Pick one, or use a second coordinator on another channel.
Read also
- Tutoriel frigate google coral home assistant
- Tutoriel home assistant docker
- Home assistant yellow vs green vs raspberry pi
Host this yourself
No hardware to manage? This kind of service runs on a managed VPS, ready in minutes. See PlanetHoster plans