ESPHome with Docker Compose: My Installation and Home Assistant Setup
I run ESPHome as a Docker container on micropc, alongside my Home Assistant container. I use it to manage three ESP32 Bluetooth proxies around my flat.
I originally flashed the boards using USB cables connected to my laptop. Since then, I have updated them over Wi-Fi from ESPHome. These OTA updates have worked without problems as long as the boards are connected.
This guide covers the Docker installation and how it fits into my setup. Flashing a particular ESP32 board and configuring Bluetooth sensors are separate tasks.
Official website: ESPHome
Official Docker documentation: Running ESPHome in Docker
My installation
| Item | My setup |
|---|---|
| Docker host | micropc |
| ESPHome directory | /opt/docker/esphome |
| Compose file | docker-compose.yml |
| Persistent configuration directory | /opt/docker/esphome/data |
| Home Assistant directory | /opt/docker/homeassistant, on the same host |
| Container network | Host networking |
| Image | ghcr.io/esphome/esphome:stable |
| Version checked | ESPHome 2026.10.0, on 26 October 2026 |
| Devices | Three ESP32 Bluetooth proxies |
| Remote dashboard access | Cloudflare Access with an approved email and a one-time PIN |
Docker and the Docker Compose plugin must already be installed. The commands below use the current docker compose syntax.
Create the directory and Compose file
For a new installation:
sudo mkdir -p /opt/docker/esphome/data
sudo chown "$(id -u):$(id -g)" /opt/docker/esphome
cd /opt/docker/esphome
nano docker-compose.yml
If ESPHome is already installed, keep the existing device files and secrets. Do not replace the data directory with an empty one.
Here is my working Compose configuration, with the unused legacy login comments removed:
services:
esphome:
container_name: esphome
stop_grace_period: 30s
image: ghcr.io/esphome/esphome:stable
volumes:
- ./data:/config
- /etc/localtime:/etc/localtime:ro
environment:
- TZ=America/Santo_Domingo
restart: unless-stopped
privileged: true
network_mode: host
The ./data directory is mounted as /config inside the container. My device YAML files and secrets.yaml are stored there, so recreating the container keeps them.
Host networking allows the dashboard to use mDNS for discovering devices and resolving their .local names. There is no ports: section because the container shares the Linux host's network.
My existing installation includes privileged: true. This grants broad access to the host and should not be treated as a requirement for every installation. I flash boards from my laptop and use OTA afterwards; I have not yet tested this installation with privileged mode removed.
Start and check ESPHome
From the Compose directory:
docker compose config --quiet
docker compose up -d
docker compose ps
docker exec esphome esphome version
During my check, the container was running and healthy, and reported:
Version: 2026.10.0
Open the dashboard using the host's LAN IP address:
http://YOUR_SERVER_LAN_IP:6052
Replace YOUR_SERVER_LAN_IP with your server's address. On another computer, localhost would refer to that computer rather than the ESPHome server.
A new installation will not contain my three devices. They appear in my dashboard because their configurations are already saved in my persistent data directory.
To inspect startup problems:
docker compose logs --tail=100 esphome
Dashboard login and remote access
My standalone HTTPS dashboard is protected by Cloudflare Access. Access is restricted to an approved email address, which receives a one-time PIN. It does not use my Caddy reverse proxy.
My Cloudflare Tunnel forwards the ESPHome hostname to http://192.168.86.100:6052 on my local network. Cloudflare Access controls access through that hostname; direct access to the local address bypasses it.
Cloudflare Access protects requests through that public hostname. Direct LAN access to the dashboard needs its own protection if I want it to require a login too.
My Compose file originally contained commented-out USERNAME and PASSWORD entries. Current ESPHome Device Builder documentation uses ESPHOME_USERNAME and ESPHOME_PASSWORD instead.
The following is an optional change, separate from the installation I verified above.
Create a credentials file:
cd /opt/docker/esphome
touch dashboard.env
chmod 600 dashboard.env
nano dashboard.env
Add your own credentials:
ESPHOME_USERNAME=your_chosen_username
ESPHOME_PASSWORD=your_long_unique_password
Use actual values, not these placeholders. Add this under the esphome: service, at the same indentation level as environment::
env_file:
- ./dashboard.env
Apply the change:
docker compose config --quiet
docker compose up -d
Use a private browser window to check that direct LAN access requires the ESPHome login. Then check the Cloudflare-protected URL and the Home Assistant sidebar page. Remote access may require both Cloudflare authentication and the ESPHome login.
This login change has not yet been tested on my installation. A container restart alone does not apply changes to its Compose environment; recreate it with docker compose up -d.
Connecting devices to Home Assistant
The ESPHome dashboard manages configuration files, compiles firmware and installs updates. The ESPHome integration in Home Assistant connects directly to each device through the native API.
These are separate connections. Home Assistant does not need to pass device traffic through the dashboard container.
My Home Assistant integration page shows three ESPHome devices, and Device Builder shows all three proxies online.
For a newly configured device, check Settings → Devices & services in Home Assistant for a discovered ESPHome device. If discovery does not find it, add the ESPHome integration manually using the device's LAN IP address. Use the ESP32's address, not the Docker server's address. Supply the API encryption key if requested.
See the official Home Assistant ESPHome integration documentation.
I also display Device Builder in my Home Assistant sidebar. I have not yet confirmed how I originally configured that page, so this guide does not include instructions for reproducing my sidebar arrangement. The standalone dashboard works independently of it.
Devices managed by ESPHome
I currently use ESPHome to manage three ESP32 Bluetooth proxies. Each has its own YAML configuration file in /opt/docker/esphome/data.
I initially flashed the boards over USB from my laptop. Since then, I have used the ESPHome dashboard to install updates wirelessly, with the boards powered and reachable on my network.
The proxies and the Bluetooth devices they serve will be covered separately. This guide focuses on installing and maintaining the ESPHome container.
Updates and backups
Updating the Docker container and updating firmware on an ESP32 are separate operations.
Before updating ESPHome, back up the Compose file and the complete data directory. Include dashboard.env if you have added it, and protect the backup because it contains credentials.
After reviewing the ESPHome release notes:
cd /opt/docker/esphome
docker compose pull
docker compose up -d
docker compose ps
docker exec esphome esphome version
The stable tag follows new stable releases when the image is pulled. For controlled updates, use a specific release tag and change it deliberately.
Updating the container does not automatically flash my boards. I install device firmware separately from the dashboard and check that the device reconnects to Home Assistant afterwards.
What I verified
On 26 October 2026, I checked the installation directory and persistent configuration filenames, validated the Compose file and confirmed that the container was running and healthy with ESPHome 2026.10.0.
Device Builder showed all three Bluetooth proxies online, and Home Assistant listed all three in its ESPHome integration. I also confirmed that the Cloudflare Tunnel routes the dashboard hostname to the server's local address on port 6052.
These checks verified my existing installation. They did not include a fresh installation or new-device adoption test.
My previous OTA updates have worked successfully. Enabling dashboard authentication, removing privileged mode and reproducing the sidebar setup remain untested changes.