👍 What we like
- ✓The mini-PC keeps a regular Linux system that can run other services
- ✓No driver needed for the ConBee III, which ZHA and Zigbee2MQTT support
- ✓Built-in, encrypted, scheduled backups to a NAS or the cloud
- ✓Simple updates with docker compose pull
👎 What to watch
- ✕No access to Home Assistant apps (formerly add-ons): Zigbee2MQTT or Mosquitto must run in separate containers
- ✕Home Assistant OS remains the method the documentation recommends for most users
- ✕You have to keep the host system, Docker and Home Assistant up to date yourself
- ✕Caddy's local certificate must be imported on each machine to avoid browser warnings
🏆 Our picks
Affiliate links · same price for youDresden Elektronik ConBee III
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: Update the system and install Docker Engine with Compose
- · Step 2: Identify the ConBee III stick
- · Step 3: Create the Home Assistant Compose file
- · Step 4: Add the ConBee III with the ZHA integration
- · Step 5: Set up automatic backups
- · Step 6: Local HTTPS with Caddy (no Internet exposure)
- · Step 7: Enable two-factor authentication
- 10 Verification checks
- 11 Security and best practices
- 12 Troubleshooting common errors
- 13 FAQ
- · How do I run a manual backup?
- · Can I use a protocol other than Zigbee?
- · Docker doesn’t start on its own at boot, what should I do?
- · How do I uninstall Home Assistant?
- 18 Read also
- 19 Host this yourself
This tutorial installs Home Assistant as a Docker container (“Home Assistant Container”) on a Linux mini-PC. It also covers setting up a Dresden Elektronik ConBee III Zigbee stick with the ZHA integration, Home Assistant’s built-in automatic backups, HTTPS access through a Caddy reverse proxy restricted to the local network, and two-factor authentication. Every command follows the official Home Assistant, Docker and Caddy documentation.
One thing to know before you start: for most users, the Home Assistant documentation recommends Home Assistant Operating System (HAOS), which installs directly on the mini-PC’s disk. The Container method shown here suits you if you want to keep a regular Linux system on the machine (to run other services on it, for example). The trade-off is that it has no access to Home Assistant apps (formerly add-ons): Zigbee2MQTT, Mosquitto or Samba then run in separate containers.
Prerequisites
- An x86-64 mini-PC, for example the Beelink Mini S12 Pro, with an SSD and a free USB port. It has to stay on all the time.
- A supported 64-bit Linux distribution: Ubuntu 24.04 LTS or 26.04 LTS (versions listed in the Docker documentation), or Debian stable. Don’t use an end-of-life release such as Ubuntu 23.10, which no longer gets updates.
- Docker Engine 23.0.0 or newer. Home Assistant does not support Docker Desktop.
- A Zigbee stick: the Dresden Elektronik ConBee III is on the ZHA integration’s list of tested and compatible adapters. You don’t need to install any driver or deCONZ software on the host: the Linux kernel sees it as a USB serial port.
- A shielded USB extension cable (recommended by the ZHA documentation) to keep the stick away from USB 3.x ports and from the case.
sudoaccess and a fixed IP address (or a reserved DHCP lease) for the mini-PC.
Step-by-step installation
Step 1: Update the system and install Docker Engine with Compose
Ubuntu’s docker.io package does not provide the docker compose command. So we use Docker’s official repository, which also ships the Compose plugin. The commands below come from Docker’s Ubuntu documentation. On Debian, replace ubuntu with debian in the URLs and check the procedure on docs.docker.com.
sudo apt update && sudo apt upgrade -y
sudo apt install -y ca-certificates curl
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc
sudo tee /etc/apt/sources.list.d/docker.sources <<EOF
Types: deb
URIs: https://download.docker.com/linux/ubuntu
Suites: $(. /etc/os-release && echo "${UBUNTU_CODENAME:-$VERSION_CODENAME}")
Components: stable
Architectures: $(dpkg --print-architecture)
Signed-By: /etc/apt/keyrings/docker.asc
EOF
sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
sudo systemctl enable --now docker
Check: the engine version must be at least 23.0.0, and the test container must print “Hello from Docker!”.
sudo docker version --format '{{.Server.Version}}'
sudo docker compose version
sudo docker run --rm hello-world
systemctl is-enabled docker # should print "enabled"
Step 2: Identify the ConBee III stick
Plug in the ConBee III, ideally into a USB 2.0 port and through the extension cable. The ZHA documentation gives its USB ID: 0403:6015. On Debian or Ubuntu, ModemManager can grab serial ports. If it’s installed and you have no modem, remove it as the ZHA documentation advises.
lsusb | grep -i 0403:6015
ls -l /dev/serial/by-id/
dpkg -l modemmanager 2>/dev/null | grep ^ii && sudo apt purge -y modemmanager
Check: lsusb shows a line with 0403:6015, and /dev/serial/by-id/ contains a link like usb-dresden_elektronik_ConBee_III_XXXXXXXX-if00-port0 -> ../../ttyUSB0. Write down this full by-id path: unlike /dev/ttyUSB0, it doesn’t change if the USB devices come up in a different order at boot.
Step 3: Create the Home Assistant Compose file
Create the directory with sudo, because it’s outside your home directory. Don’t run chmod a+w: the configuration doesn’t need to be writable by every user.
sudo mkdir -p /opt/homeassistant/config
sudo nano /opt/homeassistant/compose.yaml
Paste the following, based on the official example. Replace the by-id path with the one you noted in step 2.
services:
homeassistant:
container_name: homeassistant
image: "ghcr.io/home-assistant/home-assistant:stable"
volumes:
- /opt/homeassistant/config:/config
- /etc/localtime:/etc/localtime:ro
- /run/dbus:/run/dbus:ro
devices:
- /dev/serial/by-id/usb-dresden_elektronik_ConBee_III_XXXXXXXX-if00-port0:/dev/ttyUSB0
restart: unless-stopped
stop_grace_period: 60s
privileged: true
network_mode: host
environment:
TZ: Europe/Paris
The serial port goes to the container through the devices: key, not as a volume. Inside the container, the stick always shows up as /dev/ttyUSB0, whatever its name on the host. network_mode: host makes the UI reachable directly on port 8123 and lets Home Assistant discover devices on the local network. The /run/dbus mount is used by the Bluetooth integration (it’s optional).
cd /opt/homeassistant
sudo docker compose config --quiet && echo "Valid YAML"
sudo docker compose up -d
Check: the container is Up, port 8123 is listening, and the stick is visible inside the container.
sudo docker compose ps
sudo ss -tlnp | grep 8123
sudo docker exec homeassistant ls -l /dev/ttyUSB0
Open http://MINI_PC_IP:8123 from your local network and create the owner account in the onboarding wizard.
Step 4: Add the ConBee III with the ZHA integration
In Home Assistant, go to Settings > Devices & services. If the stick shows up under Discovered, click Configure. Otherwise, click Add integration and choose Zigbee Home Automation. Select the /dev/ttyUSB0 serial port and submit. If auto-detection fails, choose the deCONZ radio type manually.
To pair a Zigbee device, go to Settings > Connectivity > Zigbee, then Add device, and put the device into pairing mode. Menu names may differ slightly between versions: check the documentation for yours.
If you’d rather use Zigbee2MQTT (which also supports the ConBee III), don’t run ZHA on the same stick at the same time. Follow our Zigbee2MQTT tutorial linked at the end of this article instead.
Check: the ZHA integration shows up without errors in Devices & services, and the log has no serial port errors:
sudo docker logs homeassistant 2>&1 | grep -iE "zha|zigpy|ttyUSB0" | tail -n 20
Step 5: Set up automatic backups
Home Assistant has a built-in backup system, which is a better choice than a “live” tar archive of the database. Go to Settings > System > Backups and click Set up backups. Download the emergency kit and keep it off the mini-PC: it holds the encryption key, and you can’t restore anything without it. Then set the schedule, retention and included data. You can change locations later with Configure automatic backups > Locations: network storage (NAS), Home Assistant Cloud, or cloud providers through their integrations (Google Drive, OneDrive…).
A backup that only lives on the mini-PC’s SSD won’t protect you from a disk failure. If you don’t have a NAS, copy the archives to another drive every night. On a Container install, local backups are normally written to the backups subfolder of the configuration directory (check on your system with the command below). Example with an external drive mounted at /mnt/sauvegarde:
sudo ls -lh /opt/homeassistant/config/backups/
sudo tee /etc/cron.d/ha-backup-copy <<'EOF'
30 3 * * * root rsync -a /opt/homeassistant/config/backups/ /mnt/sauvegarde/homeassistant/ && cp /opt/homeassistant/compose.yaml /mnt/sauvegarde/homeassistant/
EOF
Check: run Back up now from the UI, check with the ls above that a recent .tar file appears, then check /mnt/sauvegarde/homeassistant/ the next day. To restore, the first screen of a fresh install offers Upload backup and asks for the key from the emergency kit. On a running system, select the backup in Settings > System > Backups, then Restore.
Step 6: Local HTTPS with Caddy (no Internet exposure)
Here Caddy acts as an HTTPS reverse proxy for the local network only. With tls internal, it signs the certificate with its own local authority, so you don’t have to open ports 80/443 on your router. For remote access, use a VPN (WireGuard, Tailscale) or Home Assistant Cloud rather than forwarding a port to the mini-PC.
sudo mkdir -p /opt/caddy
sudo nano /opt/caddy/Caddyfile
Caddyfile contents (this is not YAML):
ha.home.arpa {
tls internal
reverse_proxy 127.0.0.1:8123
}
Then /opt/caddy/compose.yaml. The Caddyfile is actually mounted, and certificates are kept in /data (Caddy v2).
services:
caddy:
container_name: caddy
image: caddy:2
restart: unless-stopped
network_mode: host
volumes:
- /opt/caddy/Caddyfile:/etc/caddy/Caddyfile:ro
- caddy_data:/data
- caddy_config:/config
volumes:
caddy_data:
caddy_config:
In host mode, Caddy listens directly on the mini-PC’s ports 80 and 443. Then point ha.home.arpa to the mini-PC’s IP, either in your local DNS (router, Pi-hole…) or in the hosts file of your client machines.
Finally, tell Home Assistant to trust the proxy, otherwise proxied requests are blocked (error 400). According to the current documentation, since Home Assistant 2026.8 this setting lives in Settings > System > Network > HTTP server: turn on Trust X-Forwarded-For and add 127.0.0.1 under Trusted proxies. On an older version, add this block to /opt/homeassistant/config/configuration.yaml, then restart the container:
http:
use_x_forwarded_for: true
trusted_proxies:
- 127.0.0.1
- ::1
cd /opt/caddy && sudo docker compose config --quiet && sudo docker compose up -d
sudo docker restart homeassistant
Check: the following command should return 200. A 400 means the trusted proxy setting is missing.
curl -sk -o /dev/null -w '%{http_code}\n' --resolve ha.home.arpa:443:127.0.0.1 https://ha.home.arpa/
Your browser will show a warning until Caddy’s local authority is imported on your machines. You can grab its root certificate with sudo docker cp caddy:/data/caddy/pki/authorities/local/root.crt ./caddy-root.crt.
Step 7: Enable two-factor authentication
Click your username at the bottom of the sidebar, then open the Security tab. Under Multi-factor authentication modules, enable Authenticator app (TOTP). Scan the QR code with your app, then enter the code to confirm. Do this for every administrator account.
Check: log out and back in: you should be asked for a six-digit code after your password.
Verification checks
sudo docker compose -f /opt/homeassistant/compose.yaml ps
sudo docker compose -f /opt/caddy/compose.yaml ps
sudo docker logs --since 10m homeassistant 2>&1 | grep -iE "error|exception" | tail
Then reboot the mini-PC (sudo reboot): both containers should come back on their own (restart: unless-stopped), and ZHA should find the stick again.
Security and best practices
- Never expose port 8123, SSH or the Docker socket to the Internet. For remote access, use a VPN or Home Assistant Cloud.
- Only add your user to the
dockergroup if you understand the consequences: that group grants root-equivalent rights. Usingsudo dockeris safer. - Updates: back up first, read the “Backward-incompatible changes” in the release notes, then run
sudo docker compose pull homeassistant && sudo docker compose up -din/opt/homeassistant. - Keep the emergency kit and a copy of your backups off the mini-PC.
Troubleshooting common errors
docker: 'compose' is not a docker command: the plugin is missing. Installdocker-compose-pluginfrom the Docker repository (step 1).- The container won’t start, error
error gathering device information: the by-id path indevices:is wrong or the stick is unplugged. Check withls -l /dev/serial/by-id/. - ZHA can’t find the stick or keeps disconnecting: remove ModemManager, choose the deCONZ radio type, and use an extension cable to keep the stick away from USB 3.x ports.
- Error 400 behind Caddy: Trust X-Forwarded-For or the trusted proxies aren’t set (step 6).
- Caddy won’t start,
address already in use: another service is using port 80 or 443. Find it withsudo ss -tlnp | grep -E ':80|:443'.
FAQ
How do I run a manual backup?
Go to Settings > System > Backups, then Back up now. Always do this before a major update, and write down the matching encryption key.
Can I use a protocol other than Zigbee?
Yes. Home Assistant also handles Z-Wave, Thread/Matter and Bluetooth, each with suitable hardware. The ConBee III only does Zigbee.
Docker doesn’t start on its own at boot, what should I do?
Run sudo systemctl enable --now docker, then check with systemctl is-enabled docker. Docker on Linux has no graphical setting for this.
How do I uninstall Home Assistant?
Stop the containers first:
cd /opt/homeassistant && sudo docker compose down
cd /opt/caddy && sudo docker compose down
Warning: the deletion below is irreversible. It wipes the configuration and the local backups. Copy /opt/homeassistant/config/backups/ somewhere else first, then check what you’re about to delete:
sudo du -sh /opt/homeassistant /opt/caddy
ls /mnt/sauvegarde/homeassistant/ # the copy must exist
sudo rm -rf /opt/homeassistant /opt/caddy
Read also
- Quel mini pc home assistant
- Tutoriel zigbee2mqtt home assistant
- Tutoriel frigate google coral home assistant
Host this yourself
No hardware to manage? This kind of service runs on a managed VPS, ready in minutes. See PlanetHoster plans