Every SmartHome enthusiast loves Home Assistant. And so do I! But, with Home Assistant as your central brain and heart of your SmartHome, downtimes are nothing you want to have or run into. So I thought a lot about what would be the best, yet affordable, hardware setup to make Home Assistant as reliable as possible. Also only with a reasonable amount of work and maintenance (sorry, no large Kubernetes multi-node cluster with dedicated CEPH storage 🙂 ).
I landed for my use case on a four node RaspberryPi4 8GB cluster, which I setup with portainer and traefik as a load balancer, you can read more about it in my recent guide here. It also uses a Synology shared persistent NFS storage which can be accessed by all nodes. So if one node fails and the container gets automatically relaunched on a new node, it will take over all configurations and settings from the previous Home Assistant instance.
The easiest way to get started is to create your storage folders and then deploy Home Assistant together with influxdb, mariadb and grafana via a docker-compose.yml
. So lets get started!
First you want to create the following folders in your nfs shared storage of your docker swarm cluster. ssh into your node and create the folders with (change path according to your structure):
mkdir /mnt/docker/homeassistant
mkdir /mnt/docker/homeassistant/config
mkdir /mnt/docker/homeassistant/grafana
mkdir /mnt/docker/homeassistant/mariadb
mkdir /mnt/docker/homeassistant/mariadb/db
mkdir /mnt/docker/homeassistant/influxdb
mkdir /mnt/docker/homeassistant/textconfigurator
touch /mnt/docker/homeassistant/docker-compose.yml
touch /mnt/docker/homeassistant/mariadb/my.cnf
touch /mnt/docker/homeassistant/grafana/custom.ini
Now we have created all folders and files we want to mount in our docker-compose file. To be sure we have sufficient rights, own the folder recursively with your used username. For example:
sudo chown username:username -R /mnt/docker/homeassistant/
This should ensure your are not running in any future access right problem on the other nodes.
Now we need to set some docker secret variables that we are using later in the compose file. Run these commands and replace the values with your own, very long and save passwords (Note: don't forget the dash "-" at the end of the command!):
echo "SUPERLONGCOMPLEXPASSWORDSTRING" | docker secret create ha_db_password -
echo "SUPERLONGCOMPLEXPASSWORDSTRING" | docker secret create mysql_root_password -
echo "SUPERLONGCOMPLEXPASSWORDSTRING" | docker secret create influxdb_user_password -
echo "SUPERLONGCOMPLEXPASSWORDSTRING" | docker secret create hass_configurator_password -
Now we have stored your own database passwords secure and save into our docker vault. Important to note down the passwords you used, as we need them later. Next we also need to store our Home Assistant API Key in here. If you don't have one yet, you can also run that command later:
echo "SUPERLONGCOMPLEXAPIKEY" | docker secret create hass_api_password -
Now we are ready to run and deploy Home Assistant on our nodes via docker-compose. Edit the docker compose file with:
nano /mnt/docker/homeassistant/docker-compose.yml
And copy & paste the following code into it:
version: '3.8'
services:
#homeassistant
homeassistant:
image: homeassistant/raspberrypi4-64-homeassistant:latest
ports:
- "8443:8443"
- "51827:51827"
- "5353:5353"
volumes:
- /mnt/docker/homeassistant/config:/config
- /etc/localtime:/etc/localtime:ro
networks:
- proxy
environment:
- TZ=Europe/Berlin
deploy:
mode: replicated
replicas: 1
placement:
constraints:
- node.role == manager
labels:
- "traefik.enable=true"
- "traefik.docker.network=proxy"
- "traefik.port=8443"
- "traefik.backend=homeassistant"
- "traefik.http.routers.homeassistant.entrypoints=http"
- "traefik.http.routers.homeassistant.rule=Host(`homeassistant.yourdomain.com`)"
- "traefik.http.middlewares.homeassistant-https-redirect.redirectscheme.scheme=https"
- "traefik.http.routers.homeassistant.middlewares=homeassistant-https-redirect"
- "traefik.http.routers.homeassistant-secure.entrypoints=https"
- "traefik.http.routers.homeassistant-secure.rule=Host(`homeassistant.yourdomain.com`)"
- "traefik.http.routers.homeassistant-secure.tls=true"
- "traefik.http.routers.homeassistant-secure.service=homeassistant"
- "traefik.http.services.homeassistant.loadbalancer.server.port=8080"
#config editor
hass-configurator:
image: "causticlab/hass-configurator-docker:latest"
ports:
- "3218:3218/tcp"
networks:
- proxy
volumes:
- "/mnt/docker/homeassistant/textconfigurator:/config"
- "/mnt/docker/homeassistant/config:/hass-config"
environment:
- HC_USERNAME=YOURWISHUSERNAME
- HC_PASSWORD=/run/secrets/hass_configurator_password
- HC_HASS_API_PASSWORD=/run/secrets/hass_api_password
deploy:
labels:
- "traefik.enable=true"
- "traefik.docker.network=proxy"
- "traefik.port=3218"
- "traefik.backend=homeassistant-configurator"
- "traefik.http.routers.homeassistant-configurator.entrypoints=http"
- "traefik.http.routers.homeassistant-configurator.rule=Host(`homeassistant-configurator.local.yourdomain.com`)"
- "traefik.http.middlewares.homeassistant-configurator-https-redirect.redirectscheme.scheme=https"
- "traefik.http.routers.homeassistant-configurator.middlewares=homeassistant-https-redirect"
- "traefik.http.routers.homeassistant-configurator-secure.entrypoints=https"
- "traefik.http.routers.homeassistant-configurator-secure.rule=Host(`homeassistant-configurator.local.yourdomain.com`)"
- "traefik.http.routers.homeassistant-configurator-secure.tls=true"
- "traefik.http.routers.homeassistant-configurator-secure.service=homeassistant-configurator"
- "traefik.http.services.homeassistant-configurator.loadbalancer.server.port=3218"
#influxDB
influxdb:
image: influxdb:latest
networks:
- proxy
ports:
- "8086:8086"
- "8083:8083"
environment:
INFLUXDB_DB: homeassistant
INFLUXDB_USER: homeassistant
INFLUXDB_USER_PASSWORD: /run/secrets/influxdb_user_password
volumes:
- /mnt/docker/homeassistant/influxdb/:/var/lib/influxdb
- /etc/localtime:/etc/localtime:ro
#grafana
grafana:
depends_on:
- influxdb
image: grafana/grafana:latest
networks:
- proxy
ports:
- "3000:3000"
environment:
- GF_INSTALL_PLUGINS=grafana-clock-panel,briangann-gauge-panel,natel-plotly-panel,grafana-simple-json-datasource
volumes:
- /mnt/docker/homeassistant/grafana/custom.ini:/etc/grafana/grafana.ini
- /mnt/docker/homeassistant/grafana/:/var/lib/grafana
deploy:
labels:
- "traefik.enable=true"
- "traefik.docker.network=proxy"
- "traefik.port=3000"
- "traefik.backend=homeassistant-grafana"
- "traefik.http.routers.homeassistant-grafana.entrypoints=http"
- "traefik.http.routers.homeassistant-grafana.rule=Host(`homeassistant-grafana.local.yourdomain.com`)"
- "traefik.http.middlewares.homeassistant-grafana-https-redirect.redirectscheme.scheme=https"
- "traefik.http.routers.homeassistant-grafana.middlewares=homeassistant-https-redirect"
- "traefik.http.routers.homeassistant-grafana-secure.entrypoints=https"
- "traefik.http.routers.homeassistant-grafana-secure.rule=Host(`homeassistant-grafana.local.yourdomain.com`)"
- "traefik.http.routers.homeassistant-grafana-secure.tls=true"
- "traefik.http.routers.homeassistant-grafana-secure.service=homeassistant-grafana"
- "traefik.http.services.homeassistant-grafana.loadbalancer.server.port=3000"
#mariadb
mariadb:
image: mariadb:latest
ports:
- 3306:3306
secrets:
- ha_db_password
- mysql_root_password
environment:
- MYSQL_USER=ENTERYOURUSER
- MYSQL_DATABASE=home_assistant
- MYSQL_PASSWORD_FILE=/run/secrets/ha_db_password
- MYSQL_ROOT_PASSWORD_FILE=/run/secrets/mysql_root_password
volumes:
- /mnt/docker/mariadb/db:/var/lib/mysql
- /mnt/docker/mariadb/my.cnf:/etc/mysql/my.cnf:ro
- /etc/localtime:/etc/localtime:ro
networks:
- proxy
deploy:
placement:
constraints: [node.role == manager]
replicas: 1
update_config:
parallelism: 2
delay: 10s
restart_policy:
condition: on-failure
#mariadb admin interface
adminer:
image: adminer
ports:
- 8280:8080
networks:
- proxy
deploy:
replicas: 1
labels:
- "traefik.enable=true"
- "traefik.docker.network=proxy"
- "traefik.port=8280"
- "traefik.http.routers.adminer.entrypoints=http"
- "traefik.http.routers.adminer.rule=Host(`mariadb.local.yourdomain.com`)"
- "traefik.http.middlewares.adminer-https-redirect.redirectscheme.scheme=https"
- "traefik.http.routers.adminer.middlewares=adminer-https-redirect"
- "traefik.http.routers.adminer-secure.entrypoints=https"
- "traefik.http.routers.adminer-secure.rule=Host(`mariadb.local.yourdomain.com`)"
- "traefik.http.routers.adminer-secure.tls=true"
- "traefik.http.routers.adminer-secure.service=adminer"
- "traefik.http.services.adminer.loadbalancer.server.port=8080"
secrets:
ha_db_password:
external: true
mysql_root_password:
external: true
hass_configurator_password:
external: true
hass_api_password:
external: true
influxdb_user_password:
external: true
networks:
proxy:
external: true
PLEASE make sure to read through it and replace all placeholders with your own values. Specifically the usernames of the services and the custom traefik domain labels "local.yourdomain.com" with your own domain settings.
If you are NOT using traefik at all, you can also delete the full "labels:..." section of each service.
Now if you have read through the whole file and replaced every necessary value, save and exit the file with CTRL + X, enter and y to confirm.
Now you can deploy the file using this command:
docker stack deploy -c /mnt/docker/homeassistant/docker-compose.yml homeassistant
If you are using portainer you should see the new "homeassistant" service being created and running with all its sub instances of grafana, mariadb and influxdb.
When every container started running you should be able to access the Home Assistant web interface via:
https://192.168.x.x-IP-of-Cluster-Node:8443/
On your first start Home Assistant will guide you through user creation and some first basic settings. Once you are done and are on the main dashboard, go back to your ssh console and edit the configuration.yml.
We need to add some first basic settings to tell Home Assistant that we are using grafana, influxdb and mariadb. We also add direct access to your text-editor container via iframe, so we can edit the configuration files right from within Home Assistant. The configuration.yml should be created by now when you first went through the setup guide.
nano /mnt/docker/homeassistant/config/configuration.yml
Replace its contents with:
# Configure a default setup of Home Assistant (frontend, api, etc)
default_config:
# include external config files
group: !include groups.yaml
automation: !include automations.yaml
script: !include scripts.yaml
scene: !include scenes.yaml
panel_iframe:
file_editor:
title: 'File Editor'
url: 'https://homeassistant-configurator.local.yourdomain.com'
icon: mdi:wrench-outline
grafana:
title: 'Grafana'
url: 'https://homeassistant-grafana.local.yourdomain.com'
icon: mdi:chart-timeline
http:
use_x_forwarded_for: true
trusted_proxies:
- 172.30.33.3
- 172.0.0.1
- ::1
- 10.0.0.2
server_port: 8443
# MariaDB integration
recorder:
db_url: !secret mariadb
purge_keep_days: 3
auto_purge: true
commit_interval: 60
include:
domains:
- sensor
- binary_sensor
- switch
- automation
- light
- media_player
- updater
# influxDB integration
influxdb:
host: localhost
port: 8086
username: !secret influxdb_user
password: !secret influxdb_password
database: !secret influxdb_database
max_retries: 5
default_measurement: state
include:
domains:
- switch
- light
- sensor
- binary_sensor
- device_tracker
exclude:
entities:
- sensor.icloud3_event_log
Also read this config carefully and replace the necessary usernames and domains with your values before you save and exit the file. The !secret values can either be set in the secrets files or if you are lazy and won't be too secure, you can just copy and paste the passwords you set earlier in here directly (not recommended).
To set the passwords as !secrets in Home Assistant, edit this file:
nano /mnt/docker/homeassistant/config/secrets.yml
Add these secret values to the file:
# Use this file to store secrets like usernames and passwords.
# Learn more at https://www.home-assistant.io/docs/configuration/secrets/
some_password: welcome
mariadb: 'mysql://youruser:[email protected]:3306/home_assistant?charset=utf8'
influxdb_user: homeassistant
influxdb_password: YOURINFLUXDBPASS
influxdb_database: homeassistant
Replace the placeholders "yourpassword", "youruser" and IP with your values. Save and exit the file as usual with CTRL + X and confirm with Y and enter.
Now we check our configuration and restart Home Assistant to load our config changes. In the Home Assistant web interface go to "Configuration" -> "Settings" and click "Check configuration". If it returns green and says all good you can restart the server with the below red Restart button under "Server management". If you get a red error, check the configuration.yml again on typos or missed annotations.
After the restart, Home Assistant should come back online and is now using influxDB, mariaDB and has 2 extra links in the menu for "Text Editor" and "Grafana".
Congratulations, you finished a basic Home Assistant install on a Docker Swarm cluster with custom databases (influxDB and mariaDB).