Jesse A. Green / notebook

Home Assistant Operating System — Administrator & Developer Guide

Generated May 2026 from home-assistant/operating-system at a0b3eb6

AI-generated documentation. The library is checked by sampling (three repositories so far); this guide was not individually reviewed. Verify against the project before relying on it.

1. Architecture Overview

Home Assistant Operating System (HAOS) is a Buildroot-based Linux distribution purpose-built to host the Home Assistant ecosystem. It provides a minimal, hardened, and fully managed OS that boots directly into a Docker-based service stack running the Home Assistant Supervisor, Core, and add-ons.

Design Philosophy

HAOS is not a general-purpose Linux distribution. It is an appliance OS:

  • The root filesystem is read-only (squashfs/erofs)
  • User data lives on a separate data partition (/mnt/data)
  • Configuration persistence uses bind mounts from the data partition to /etc paths
  • System updates are atomic A/B slot swaps via RAUC — no package manager
  • All user-facing services (Home Assistant, add-ons) run as Docker containers
  • The OS handles only hardware, networking, storage, and container orchestration

Architecture Diagram

┌─────────────────────────────────────────────────────────────┐
│                        User Browser                         │
│                    homeassistant.local:8123                  │
└──────────────────────────┬──────────────────────────────────┘
                           │
┌──────────────────────────┴──────────────────────────────────┐
│                    Docker (containerd)                       │
│  ┌──────────────┐ ┌──────────────┐ ┌──────────────────────┐│
│  │  Supervisor   │ │     Core     │ │   Add-ons (DNS,     ││
│  │  (hassio_     │ │  (home-      │ │   Audio, CLI,       ││
│  │  supervisor)  │ │  assistant)  │ │   Observer, etc.)   ││
│  └──────┬───────┘ └──────────────┘ └──────────────────────┘│
│         │  manages all containers                           │
└─────────┼───────────────────────────────────────────────────┘
          │
┌─────────┴───────────────────────────────────────────────────┐
│                  HAOS (Buildroot Linux)                      │
│  ┌────────────┐ ┌──────────────┐ ┌────────────────────────┐│
│  │ systemd    │ │ NetworkMgr   │ │ RAUC (OTA updates)     ││
│  │ services   │ │ (networking) │ │ A/B slot management    ││
│  └────────────┘ └──────────────┘ └────────────────────────┘│
│  ┌────────────┐ ┌──────────────┐ ┌────────────────────────┐│
│  │ AppArmor   │ │ os-agent     │ │ zRAM / swap           ││
│  │ (security) │ │ (D-Bus API)  │ │ (memory management)   ││
│  └────────────┘ └──────────────┘ └────────────────────────┘│
└─────────────────────────────────────────────────────────────┘
          │
┌─────────┴───────────────────────────────────────────────────┐
│                   Disk Partition Layout                      │
│  boot │ kernel.0 │ system.0 │ kernel.1 │ system.1 │ data   │
│  (FAT)│  (A)     │  (A)     │  (B)     │  (B)     │ (ext4) │
└─────────────────────────────────────────────────────────────┘

Component Inventory

Component Path / Package Role
Buildroot buildroot/ (git submodule) Cross-compilation build system
Buildroot External buildroot-external/ HAOS-specific packages, configs, overlays
Board Support buildroot-external/board/ Per-hardware boot config, kernel configs, hooks
Package Definitions buildroot-external/package/ Custom packages (os-agent, hassio, drivers, etc.)
Root FS Overlay buildroot-external/rootfs-overlay/ Systemd units, config files, shell scripts
Kernel Configs buildroot-external/kernel/ Kernel fragment configs per version
OTA/RAUC buildroot-external/ota/ RAUC system config, signing certificates, hooks
Image Generation buildroot-external/genimage/ Disk image layout configs
Boot Configuration buildroot-external/bootloader/ U-Boot config, MBR images
Build Configs buildroot-external/configs/ Buildroot defconfigs per board
Patches buildroot-external/patches/ Patches for upstream packages (Docker, systemd, GRUB, etc.)
Build Scripts buildroot-external/scripts/ Post-build, post-image, and utility scripts
Tests tests/ Smoke tests and Supervisor integration tests (labgrid + pytest)
Container Scripts scripts/ Development helpers (enter.sh, update scripts)

Technology Stack

Layer Technology Version / Notes
Build system Buildroot Git submodule, cross-compilation
Init system systemd PID 1, service management, journald
Container runtime Docker + containerd Containerd snapshotter backend
Networking NetworkManager Wi-Fi, Ethernet, VLAN, mDNS
DNS systemd-resolved Stub resolver, per-link DNS
OTA updates RAUC A/B slots, signed bundles, hooks
Bootloader U-Boot (ARM) / GRUB (x86) Per-board configuration
Security AppArmor Profiles for Supervisor containers
Filesystem squashfs/erofs (system), ext4 (data) Read-only system, read-write data
Memory zRAM + swap file Configurable sizes
D-Bus agent os-agent Host API for Supervisor communication
USB disk management udisks2 Data disk operations

Note

HAOS uses Buildroot (not Yocto/OpenEmbedded). Buildroot produces a complete cross-compiled root filesystem image from source. The buildroot/ directory is a git submodule pinned to a specific Buildroot release, and buildroot-external/ contains all HAOS customizations using Buildroot's external tree mechanism (BR2_EXTERNAL).


2. System Requirements

Build Requirements

Building HAOS requires a Linux host (or Docker on any platform):

Requirement Minimum
OS Linux (Ubuntu 22.04+ recommended) or Docker
Disk 50+ GB free space
RAM 4+ GB
Tools make, gcc, git, docker (for containerized builds)

The repository includes a Dockerfile for reproducible builds and a Makefile with board-specific targets.

Test Requirements

The test suite (tests/) requires:

Package Version Purpose
labgrid 25.0.1 Hardware/VM test automation framework
pytest-dependency 0.6.1 Test ordering and dependency chains
pytest-timeout 2.4.0 Per-test timeout enforcement
Python 3.x (.python-version in tests/) Test runner

Target Hardware Requirements

Board Category RAM Storage Architecture
Raspberry Pi 3/4/5 1–8 GB 32+ GB SD/eMMC/NVMe aarch64
ODROID (C2/C4/M1/M1S/N2) 2–4 GB 32+ GB SD/eMMC aarch64
Khadas VIM3 2–4 GB 32+ GB SD/eMMC aarch64
NabuCasa Green 4 GB 32 GB eMMC aarch64
Generic x86-64 2+ GB 32+ GB SSD/NVMe x86_64
OVA (VM) 2+ GB allocated 32+ GB virtual disk x86_64

3. Configuration Reference

Partition Layout

HAOS uses a fixed partition scheme created by genimage during the build:

Partition Label Filesystem Mount Point Purpose
Boot hassos-boot FAT32 /mnt/boot Bootloader, kernel, DTBs, config.txt
Kernel A hassos-kernel0 raw — Kernel image (slot A)
System A hassos-system0 squashfs/erofs / (when active) Root filesystem (slot A)
Kernel B hassos-kernel1 raw — Kernel image (slot B)
System B hassos-system1 squashfs/erofs / (when active) Root filesystem (slot B)
Bootstate — raw — RAUC boot status tracking
Overlay hassos-overlay ext4 /mnt/overlay Persistent overlay for /etc
Data hassos-data ext4 /mnt/data User data, Docker, add-ons, backups

Important

The partition table type varies by board: GPT for UEFI systems (hdimage-gpt.cfg), hybrid MBR/GPT for some ARM boards (hdimage-hybrid.cfg), and pure MBR for legacy boards (hdimage-mbr.cfg). The genimage configs in buildroot-external/genimage/ define the exact layout for each type.

Disk Image Generation Configs

Config File Purpose
genimage/genimage.cfg Top-level image assembly
genimage/hdimage-gpt.cfg GPT partition table layout
genimage/hdimage-hybrid.cfg Hybrid MBR/GPT layout
genimage/hdimage-mbr.cfg MBR partition table layout
genimage/images-boot.cfg Boot partition image
genimage/images-os.cfg OS (system) partition image
genimage/image-raucb-spl.cfg RAUC bundle with SPL
genimage/image-raucb-nospl.cfg RAUC bundle without SPL

Systemd Service Units

HAOS defines a comprehensive set of systemd services in buildroot-external/rootfs-overlay/usr/lib/systemd/system/:

Core OS Services

Unit Type Purpose
hassos-config.service oneshot Reads and applies user configuration from /mnt/config
hassos-data.service oneshot Initializes data partition structure
hassos-expand.service oneshot Expands data partition to fill disk on first boot
hassos-overlay.service oneshot Sets up persistent overlay for /etc
hassos-persists.service oneshot Persists certain runtime state across reboots
hassos-supervisor.service service Starts the Home Assistant Supervisor container
hassos-apparmor.service oneshot Loads AppArmor profiles
hassos-bind.target target Ordering target for bind mounts
hassos-hardware.target target Ordering target for hardware readiness
hassos-zram.target target Ordering target for zRAM setup
hassos-user-rules-udev-trigger.service oneshot Re-triggers udev for user-supplied rules

Data and Storage Services

Unit Type Purpose
mnt-boot.mount mount Mounts boot partition to /mnt/boot
mnt-config.mount mount Mounts config partition to /mnt/config
mnt-data.mount mount Mounts data partition to /mnt/data
mnt-overlay.mount mount Mounts overlay partition to /mnt/overlay
var.mount mount Mounts /var from data partition
var-lib-docker.mount mount Bind-mounts Docker data directory
var-lib-bluetooth.mount mount Bind-mounts Bluetooth state
var-lib-NetworkManager.mount mount Bind-mounts NetworkManager state
var-lib-systemd.mount mount Bind-mounts systemd persistent state
var-log-journal.mount mount Bind-mounts journal log directory
root-.docker.mount mount Bind-mounts Docker config for root
root-.ssh.mount mount Bind-mounts SSH config for root
haos-data-disk-detach.service oneshot Safely detaches external data disk
haos-swapfile.service oneshot Creates and activates swap file
mnt-data-swapfile.swap swap Swap file unit

Persistent Bind Mounts

Unit Purpose
etc-default.mount Persists /etc/default from data partition
etc-dropbear.mount Persists Dropbear SSH host keys
etc-hostname.mount Persists hostname
etc-hosts.mount Persists hosts file
etc-modprobe.d.mount Persists modprobe configuration
etc-sysctl.d.mount Persists sysctl settings
etc-systemd-timesyncd.conf.mount Persists time sync configuration
etc-udev-rules.d.mount Persists user udev rules
etc-usb_modeswitch.d.mount Persists USB modeswitch config

Memory Management Services

Unit Type Purpose
zram-tmp.service oneshot Creates zRAM-backed /tmp
zram-var.service oneshot Creates zRAM-backed /var
haos-mglru.service oneshot Enables Multi-Generation LRU for improved memory reclaim
haos-swapfile.service oneshot Manages swap file creation and activation

Other Services

Unit Type Purpose
docker-prepare.service oneshot Pre-start Docker preparation
ha-cli@.service template Home Assistant CLI service template
haos-bt-cache.service oneshot Bluetooth device cache management
haos-bt-cache.timer timer Timer for Bluetooth cache service
haos-wipe.service oneshot Factory reset / data wipe
raucdb-update.service oneshot Updates RAUC database
systemd-journal-gatewayd.socket socket Journal gateway for Supervisor log access

Note

Many upstream systemd services have drop-in overrides in subdirectories (e.g., docker.service.d/, NetworkManager.service.d/). These customize behavior without modifying the original unit files. For example, docker.service.d/hassos.conf sets Docker dependencies and resource limits, and docker.service.d/failure.conf configures restart behavior on failure.

Systemd Presets

The file buildroot-external/rootfs-overlay/usr/lib/systemd/system-preset/70-haos.preset controls which services are enabled by default at boot.

System Configuration Files

File Format Purpose
/etc/fstab fstab Static filesystem mount table
/etc/resolv.conf resolv DNS resolver (stub to systemd-resolved)
/etc/motd text Message of the day for console login
/etc/input-event-daemon.conf ini Input event daemon configuration
/etc/NetworkManager/NetworkManager.conf ini NetworkManager main configuration
/etc/bluetooth/main.conf ini Bluetooth daemon configuration
/etc/containerd/config.toml TOML Containerd runtime configuration
/etc/docker/daemon.json JSON Docker daemon configuration
/etc/systemd/coredump.conf ini Core dump handling configuration
/etc/systemd/journald.conf ini Journal logging configuration
/etc/systemd/logind.conf ini Login manager configuration
/etc/systemd/resolved.conf ini DNS resolution configuration
/etc/systemd/timesyncd.conf ini Time synchronization configuration

Sysctl Settings

File Key Settings
/usr/lib/sysctl.d/10-printk.conf Kernel print level tuning
/usr/lib/sysctl.d/15-swappiness.conf Swap aggressiveness tuning
/usr/lib/sysctl.d/20-network.conf Network buffer and connection tuning
/usr/lib/sysctl.d/30-cp15barrier.conf ARM CP15 barrier workaround
/usr/lib/sysctl.d/60-otbr-ancillary-buffer.conf OpenThread Border Router buffer tuning

System Configuration Overrides

File Purpose
/usr/lib/systemd/system.conf.d/etc-environment-overrides.conf Environment variable overrides for all services
/usr/lib/systemd/system.conf.d/watchdog.conf Hardware watchdog configuration

Tmpfiles Configuration

File Purpose
/etc/tmpfiles.d/data.conf Data partition directory structure
/etc/tmpfiles.d/nm.conf NetworkManager runtime directories
/etc/tmpfiles.d/overlay.conf Overlay partition structure

Tip

To understand the full boot sequence, trace the systemd dependency chain starting from hassos-data.service → hassos-expand.service → hassos-overlay.service → hassos-config.service → hassos-supervisor.service. The bind mount units depend on hassos-bind.target, ensuring data is available before services that need persistent state.


4. Deployment & Scaling

Building HAOS Images

The repository includes a Dockerfile and Makefile for reproducible builds:

make <board_target>

Where <board_target> is one of the defconfig names in buildroot-external/configs/:

Target Board
rpi3_64 Raspberry Pi 3 (64-bit)
rpi4_64 Raspberry Pi 4 (64-bit)
rpi5_64 Raspberry Pi 5 (64-bit)
yellow Home Assistant Yellow
green NabuCasa Green
odroid_c2 ODROID-C2
odroid_c4 ODROID-C4
odroid_m1 ODROID-M1
odroid_m1s ODROID-M1S
odroid_n2 ODROID-N2/N2+
khadas_vim3 Khadas VIM3
generic_x86_64 Generic x86-64 (UEFI)
generic_aarch64 Generic AArch64 (UEFI)
ova OVA (Virtual Machine)

Build Process Flow

make <target>
  → Docker container with Buildroot toolchain
    → BR2_EXTERNAL=buildroot-external
      → buildroot-external/configs/<target>_defconfig
        → Cross-compile kernel, packages, root filesystem
          → buildroot-external/scripts/post-build.sh
            → Root filesystem overlay applied
          → buildroot-external/scripts/post-image.sh
            → genimage creates disk image
            → RAUC bundle created (.raucb)
            → hassos-hook.sh (board-specific post-processing)
              → Compressed image (.img.xz) output

Development Shell

Enter the Buildroot build environment interactively:

scripts/enter.sh

This launches a Docker container with the build environment mounted, allowing direct access to Buildroot's make menuconfig, make linux-menuconfig, and other build system commands.

Board Support Architecture

Each supported board has a directory under buildroot-external/board/ containing:

File Purpose
meta Board metadata (name, architecture, image type)
cmdline.txt Kernel command line parameters
hassos-hook.sh Build hook for board-specific image processing
kernel.config Board-specific kernel configuration fragment
uboot.config U-Boot configuration (ARM boards)
uboot-boot.ush / uboot-boot64.ush U-Boot boot scripts
boot-env.txt U-Boot environment variables
config.txt Raspberry Pi firmware configuration (RPi boards only)
grub.cfg GRUB configuration (x86 boards only)

Note

The hassos-hook.sh script for each board implements two functions: hassos_pre_image() (copies bootloader, DTBs, and firmware to the boot partition) and hassos_post_image() (post-processing like xz compression). The Raspberry Pi hook additionally enables 64-bit mode in config.txt for 64-bit board targets.

Raspberry Pi-Specific Configuration

The Raspberry Pi boards use a shared base configuration with per-variant overrides:

buildroot-external/board/raspberrypi/
├── config.txt              ← Shared RPi firmware config
├── cmdline.txt             ← Shared kernel command line
├── hassos-hook.sh          ← Shared build hook
├── kernel.config           ← Shared kernel config fragment
├── uboot-boot.ush          ← U-Boot script (32-bit)
├── uboot-boot64.ush        ← U-Boot script (64-bit)
├── uboot.config            ← U-Boot config
├── rpi3-64/meta            ← RPi 3 metadata
├── rpi4-64/meta            ← RPi 4 metadata
├── rpi5-64/                ← RPi 5 (has own cmdline, config, hook)
│   ├── cmdline.txt
│   ├── config.txt
│   ├── hassos-hook.sh
│   └── rootfs-overlay/usr/lib/rauc/
│       ├── cmdline.sh      ← RAUC cmdline update hook
│       └── rpi-tryboot.sh  ← RPi 5 tryboot mechanism
└── yellow/                 ← HA Yellow (CM4/CM5 carrier board)
    ├── config.txt
    ├── cmdline.txt
    ├── patches/            ← Yellow-specific kernel & U-Boot patches
    └── rootfs-overlay/     ← Yellow firmware (brcmfmac)

Important

The Raspberry Pi 5 uses a different boot mechanism (tryboot) instead of U-Boot for slot switching. The rpi-tryboot.sh RAUC hook script manages this. This is why rpi5-64 has its own hassos-hook.sh separate from the shared RPi hook.


5. Operations

OTA Update System (RAUC)

HAOS uses RAUC for over-the-air updates with an A/B partition scheme.

RAUC Configuration

The RAUC system configuration template is at buildroot-external/ota/system.conf.gtpl and defines:

  • Slot definitions (kernel.0, kernel.1, system.0, system.1)
  • Keyring for bundle signature verification
  • Status file location for boot tracking
  • Bundle format and compatibility string

Signing Infrastructure

File Purpose
buildroot-external/ota/rel-ca.pem Release signing CA certificate
buildroot-external/ota/dev-ca.pem Development signing CA certificate
buildroot-external/ota/provisioning-ca.pem Provisioning CA certificate
buildroot-external/ota/manifest.raucm.gtpl RAUC manifest template
buildroot-external/ota/rauc-hook RAUC installation hook script
buildroot-external/scripts/rauc.sh RAUC bundle creation script
buildroot-external/scripts/generate-signing-key.sh Key generation utility

Warning

RAUC bundles are cryptographically signed. The three CA certificates (release, development, provisioning) form a trust chain. Only bundles signed with a trusted key are accepted for installation. Modifying or removing these certificates will break the OTA update mechanism.

Update Flow

1. Supervisor checks version.home-assistant.io for updates
2. Downloads .raucb bundle for the board
3. RAUC verifies bundle signature against trusted CA chain
4. RAUC installs kernel + system to INACTIVE slot (A→B or B→A)
5. RAUC marks new slot as primary boot target
6. System reboots into new slot
7. If boot succeeds → new slot marked "good"
8. If boot fails → bootloader falls back to previous "good" slot

Service Management

Supervisor Lifecycle

The Supervisor is managed by hassos-supervisor.service, which:

  1. Depends on Docker being ready
  2. Runs /usr/sbin/hassos-supervisor to start the Supervisor container
  3. The Supervisor then manages all other containers (Core, add-ons, plugins)

The Supervisor container is tagged as ghcr.io/home-assistant/{arch}-hassio-supervisor:latest during the build process by buildroot-external/package/hassio/dind-import-containers.sh.

Key OS Scripts

Script Path Purpose
hassos-supervisor /usr/sbin/hassos-supervisor Starts/manages the Supervisor container
hassos-config /usr/sbin/hassos-config Applies user configuration from /mnt/config
hassos-cli /usr/sbin/hassos-cli Host-level CLI entry point
hassos-apparmor /usr/libexec/hassos-apparmor Loads AppArmor profiles
hassos-data /usr/libexec/hassos-data Initializes data partition structure
hassos-expand /usr/libexec/hassos-expand Expands data partition to fill disk
hassos-overlay /usr/libexec/hassos-overlay Sets up persistent overlay
hassos-persists /usr/libexec/hassos-persists Persists runtime state
hassos-zram /usr/libexec/hassos-zram Configures zRAM devices
haos-swapfile /usr/libexec/haos-swapfile Manages swap file
haos-wipe /usr/libexec/haos-wipe Factory reset handler
haos-freeze-hook /usr/libexec/haos-freeze-hook Filesystem freeze hook for backups
haos-data-disk-detach /usr/libexec/haos-data-disk-detach Safe external disk detach
docker-prepare /usr/libexec/docker-prepare Pre-Docker startup preparation
docker-disk-check /usr/libexec/docker-disk-check Docker disk space monitoring
raucdb-update /usr/libexec/raucdb-update RAUC database maintenance

Tip

The boot sequence flows: hassos-data.service (initialize data) → hassos-expand.service (expand partition) → hassos-overlay.service (overlay setup) → bind mounts → hassos-config.service (apply config) → docker-prepare.service → docker.service → hassos-supervisor.service. Tracing this chain is essential for debugging boot failures.

Container Image Pre-loading

During the build, HAOS pre-loads Docker container images into the data partition to enable offline first boot. The process is managed by three scripts in buildroot-external/package/hassio/:

  1. fetch-container-image.sh — Downloads container images using skopeo with architecture-aware selection and retry logic (3 retries with exponential backoff). Uses file locking to prevent race conditions during parallel downloads.

  2. dind-import-containers.sh — Runs inside a Docker-in-Docker container during the build. Loads pre-fetched OCI archives into the Docker daemon and tags the Supervisor image with the expected naming convention.

  3. create-data-partition.sh — Creates and populates the data partition image:

    • Creates a 1280 MB ext4 image labeled hassos-data
    • Mounts and populates with Docker images via DinD
    • Sets up initial AppArmor profiles from version.home-assistant.io
    • Writes the updater channel configuration (updater.json)
    • Creates the .docker-use-containerd-snapshotter marker file

Note

The data partition image created during build contains pre-loaded container images so the system can boot without internet. The initial size is 1280 MB but is expanded to fill the disk on first boot by hassos-expand.service.

Monitoring and Health

The test suite validates these health indicators that administrators should also monitor:

  • No failed systemd units: systemctl list-units --state=failed should report 0 failures
  • No systemd dependency cycles: Check journalctl -b0 | grep 'ordering cycle'
  • Kernel not tainted: cat /proc/sys/kernel/tainted should be 0
  • Network connectivity: nmcli network connectivity check should report full
  • No AppArmor denies: journalctl -t audit | grep DENIED should return empty
  • Supervisor health: ha resolution healthcheck should pass with no unhealthy/unsupported entries
  • RAUC slot status: rauc status should show active slot with correct version and no warnings

6. Performance

Memory Management

HAOS implements several memory optimization strategies:

zRAM

Two zRAM devices are configured by hassos-zram (/usr/libexec/hassos-zram):

Device Mount Purpose
zram-tmp /tmp Compressed in-memory temporary storage
zram-var /var Compressed in-memory variable data

zRAM provides transparent compression of temporary data, reducing disk I/O and extending the effective memory capacity on memory-constrained devices.

Multi-Generation LRU (MGLRU)

The haos-mglru.service enables the Multi-Generation LRU page reclaim algorithm, which improves memory management efficiency compared to the traditional LRU, particularly beneficial for systems running many containerized services.

Swap File

The swap file at /mnt/data/swapfile provides additional virtual memory. The size is managed by haos-swapfile.service reading /etc/default/haos-swapfile. Swap aggressiveness is tuned via /usr/lib/sysctl.d/15-swappiness.conf.

Docker Optimization

  • Containerd snapshotter backend: Enabled when the .docker-use-containerd-snapshotter marker exists on the data partition, improving container layer handling
  • journald logging: Docker uses journald as the log driver, eliminating separate log files and enabling unified log access through journalctl
  • overlay2 storage driver: Efficient copy-on-write filesystem for container layers
  • Resource limits: Docker service drop-ins in docker.service.d/resource.conf configure resource constraints

7. Security

AppArmor

HAOS uses AppArmor to provide mandatory access control for containerized services. The hassos-apparmor.service loads profiles at boot via /usr/libexec/hassos-apparmor. AppArmor profiles for the Supervisor are downloaded from version.home-assistant.io during the build and stored at /mnt/data/supervisor/apparmor/.

Warning

AppArmor denies indicate a container attempted an operation outside its allowed profile. Check journalctl -t audit | grep DENIED to diagnose. Persistent denies after updates may indicate a profile mismatch — the Supervisor manages profile updates automatically.

Filesystem Protection

  • Read-only root: The system partition is squashfs/erofs, preventing runtime modification
  • Persistent overlay: Only /etc changes persist via the overlay partition
  • Bind mounts: Specific directories (/var/lib/docker, /var/lib/bluetooth, etc.) are bind-mounted from the data partition, isolating persistent state
  • Separate data partition: User data, Docker containers, and add-ons live on a separate ext4 partition, preventing system corruption from data issues

OTA Update Security

  • Signed bundles: All RAUC update bundles are cryptographically signed
  • Certificate chain: Three-tier CA (release, development, provisioning) for different deployment stages
  • Verification on install: RAUC validates the bundle signature before writing to disk
  • Rollback protection: Failed boots automatically revert to the last known-good slot

Network Security

  • mDNS only: The system is discoverable via mDNS (.local) only, not via LLMNR
  • Dropbear SSH: Minimal SSH server with persistent host keys via bind mount, configured via drop-in overrides for security hardening
  • NTP dispatcher: The NetworkManager dispatcher (10-ntp) ensures time synchronization updates when network state changes, preventing time-skew-based attacks

Docker Security

  • AppArmor profiles per container: Managed by the Supervisor
  • Container isolation: Each add-on runs in its own container with defined capabilities
  • Docker daemon patches: HAOS applies custom patches to Docker (in buildroot-external/patches/docker-engine/) including:
    • Respecting explicit AppArmor profiles on privileged containers
    • Protecting bridge subnets from direct external access

Caution

The Docker engine patches in buildroot-external/patches/docker-engine/ modify upstream Docker behavior. Patch 0002-bridge-protect-bridge-subnet-from-direct-external-ac.patch adds firewall rules to prevent external access to the Docker bridge subnet. Removing this patch would expose container networks to the local network.


8. Developer Internals

Repository Structure

home-assistant/operating-system/
├── Dockerfile                  ← Build container definition
├── Makefile                    ← Board-specific build targets
├── README.md                   ← Project overview
├── .gitmodules                 ← Buildroot submodule reference
├── .hadolint.yaml              ← Dockerfile linter config (ignores DL3008)
├── buildroot/                  ← Buildroot (git submodule)
├── buildroot-external/         ← HAOS customization layer
│   ├── Config.in               ← Kconfig menu for HAOS packages
│   ├── external.desc           ← Buildroot external descriptor
│   ├── external.mk             ← Buildroot external makefile
│   ├── busybox.config          ← BusyBox configuration
│   ├── meta                    ← Project metadata
│   ├── board/                  ← Per-board configurations
│   │   ├── arm-uefi/           ← Generic ARM UEFI boards
│   │   ├── hardkernel/         ← ODROID boards
│   │   ├── khadas/             ← Khadas VIM boards
│   │   ├── nabucasa/           ← NabuCasa Green
│   │   ├── pc/                 ← x86-64 and OVA
│   │   └── raspberrypi/        ← RPi 3/4/5/Yellow
│   ├── bootloader/             ← MBR images, U-Boot config
│   ├── configs/                ← Buildroot defconfigs
│   ├── genimage/               ← Disk image layout configs
│   ├── kernel/                 ← Kernel config fragments
│   ├── ota/                    ← RAUC config, CA certs, hooks
│   ├── package/                ← Custom packages
│   │   ├── bluetooth-rtl8723/  ← RTL8723 Bluetooth driver
│   │   ├── eq3_char_loop/      ← eQ-3 HomeMatic kernel module
│   │   ├── gasket/             ← Google Coral TPU driver
│   │   ├── generic_raw_uart/   ← Generic raw UART driver
│   │   ├── hailo-pci/          ← Hailo AI accelerator PCI driver
│   │   ├── hailo8-firmware/    ← Hailo-8 firmware blobs
│   │   ├── hardkernel-boot/    ← Hardkernel bootloader
│   │   ├── hassio/             ← Supervisor container pre-loading
│   │   ├── khadas-boot/        ← Khadas bootloader
│   │   ├── lxd-guest-agent/    ← LXD VM guest agent
│   │   ├── os-agent/           ← Home Assistant OS Agent
│   │   ├── pi-bluetooth/       ← Raspberry Pi Bluetooth
│   │   ├── qemu-guest-agent/   ← QEMU VM guest agent
│   │   ├── rockchip-blobs/     ← Rockchip binary firmware
│   │   ├── rpi-eeprom/         ← RPi EEPROM update tools
│   │   ├── rpi-rf-mod/         ← RPi RF module (HomeMatic)
│   │   ├── rtl88x2bu/          ← Realtek Wi-Fi driver
│   │   ├── tempio/             ← Template I/O (host tool)
│   │   ├── udisks2/            ← UDisks2 (patched for HAOS)
│   │   ├── vcgencmd/           ← VideoCore GPU command tool
│   │   └── xe-guest-utilities/ ← Xen VM guest utilities
│   ├── patches/                ← Patches for upstream packages
│   │   ├── docker-engine/      ← Docker security patches
│   │   ├── grub2/              ← GRUB enhancements
│   │   ├── libglib2/           ← GLib journal logging fix
│   │   ├── linux/              ← Kernel patches (IPv6 reachability)
│   │   ├── network-manager/    ← NM connectivity check fix
│   │   ├── rauc/               ← RAUC journal logging
│   │   ├── systemd/            ← systemd patches (hostname, journal, time)
│   │   ├── uboot/              ← U-Boot string-to-env command
│   │   └── uboot-tools/        ← fw_printenv lock file path
│   ├── rootfs-overlay/         ← Files overlaid onto root filesystem
│   │   ├── etc/                ← Configuration files
│   │   ├── mnt/                ← Mount point placeholders
│   │   └── usr/                ← Services, scripts, rules
│   └── scripts/                ← Build and utility scripts
├── Documentation/              ← Kernel version docs
├── scripts/                    ← Developer helper scripts
└── tests/                      ← Smoke and Supervisor tests

Package System

HAOS custom packages follow the Buildroot package convention:

File Purpose
Config.in Kconfig menu entry (dependencies, help text)
<package>.mk Buildroot makefile (download, build, install rules)
<package>.hash SHA256 hash for source verification
Patches (0001-*.patch) Applied to upstream source during build

Each package's .mk file defines:

  • *_VERSION — upstream version to download
  • *_SITE — download URL or GitHub repository
  • *_DEPENDENCIES — build-time dependencies
  • *_INSTALL_TARGET_CMDS — installation commands

Notable Custom Packages

os-agent (buildroot-external/package/os-agent/): The Home Assistant OS Agent provides a D-Bus interface for the Supervisor to communicate with the host OS. It handles OS operations like network management, disk operations, and system information queries.

hassio (buildroot-external/package/hassio/): Not a single binary but a set of build-time scripts that pre-load the Supervisor and plugin container images into the data partition. Contains create-data-partition.sh, dind-import-containers.sh, and fetch-container-image.sh.

udisks2 (buildroot-external/package/udisks2/): UDisks2 patched for HAOS with three patches:

  1. Allow explicitly disabling libsystemd-login
  2. Isolate authorization-specific functions
  3. Make polkit dependency optional

These patches enable UDisks2 to run without a full login/session manager or polkit daemon.

Guest Agents: Three guest agent packages support different virtualization platforms:

  • qemu-guest-agent — for KVM/QEMU VMs
  • lxd-guest-agent — for LXC/LXD containers
  • xe-guest-utilities — for Xen/XCP-ng VMs

Upstream Patches

HAOS patches several upstream packages to customize behavior:

Package Patches Purpose
Docker Engine 2 AppArmor profile respect on privileged containers; bridge subnet protection
systemd 8 Hostname on read-only /etc, journal gateway boots endpoint, time sync delay, environment variable paths
GRUB2 2 file_env command for loading vars from files; legacy loader for broken Intel NUCs
Linux kernel 1 IPv6 reachability test explicit enable option
NetworkManager 1 Restrict connectivity check to per-link DNS lookups
RAUC 1 Add SYSLOG_IDENTIFIER to structured logs
U-Boot 1 String-to-environment-variable read command
U-Boot tools 1 Use /run as default lock file location for fw_printenv
libglib2 1 Add SYSLOG_IDENTIFIER to structured logs

Kernel Configuration

Kernel configuration uses a layered fragment approach:

  1. Board-specific config (buildroot-external/board/<board>/kernel.config) — architecture and hardware-specific settings
  2. Version fragments (buildroot-external/kernel/v6.12.y/) — per-kernel-version features:
Fragment Purpose
hassos.config Core HAOS kernel features
docker.config Docker/container support (cgroups, namespaces, overlay)
device-support.config Hardware device drivers
device-support-pci.config PCI device support
device-support-wireless.config Wireless/Bluetooth drivers
device-support-wireless-pci.config PCIe wireless adapters

Additional board-specific kernel patches are applied from buildroot-external/board/<board>/patches/linux/.

Note

The script buildroot-external/scripts/check-dotconfig.py (using the vendored kconfiglib.py) validates that all kernel config fragments are correctly applied to the final .config. This prevents silent config regressions.

Build Scripts

Script Purpose
buildroot-external/scripts/post-build.sh Runs after root filesystem build — applies overlays, generates configs
buildroot-external/scripts/post-image.sh Runs after image creation — calls genimage, creates RAUC bundles
buildroot-external/scripts/rootfs-layer.sh Root filesystem layering helper
buildroot-external/scripts/hdd-image.sh HDD/SSD image creation for x86
buildroot-external/scripts/rauc.sh RAUC bundle creation and signing
buildroot-external/scripts/name.sh Version/name generation for build artifacts
scripts/enter.sh Enter the Docker build environment
scripts/entry.sh Docker container entry point
scripts/update-dtb.sh Update device tree blobs
scripts/update-firmware-rpi.sh Update RPi firmware files
scripts/update-kernel-rpi.sh Update RPi kernel
scripts/update-kernel-upstream.sh Update upstream kernel
scripts/check-kernel-patches.sh Verify kernel patches apply cleanly

Testing Strategy

HAOS uses labgrid for hardware-in-the-loop testing, combined with pytest.

Test Architecture

pytest
  └── labgrid (test automation framework)
       ├── ShellDriver (serial/SSH console interaction)
       ├── qemu-strategy.yaml (QEMU VM target definition)
       └── qemu_shell_strategy.py (QEMU-specific strategy)

Tests interact with a running HAOS instance (real hardware or QEMU VM) via shell commands, using shell.run_check() for command execution and shell_json() for JSON-parsed output.

Test Suites

Smoke Tests (tests/smoke_test/):

Test What It Validates
test_init System boots, containers running, ha os info responds
test_rauc_status RAUC reports kernel.0 as primary, version matches, no warnings
test_dmesg Kernel messages captured (diagnostic)
test_supervisor_logs Supervisor logs accessible
test_landing_page HTTP GET to localhost:8123 returns HTML
test_systemctl_status All systemd units status captured
test_systemctl_check_no_failed Zero failed systemd units
test_systemctl_no_cycles No systemd dependency ordering cycles
test_host_connectivity Host can reach checkonline.home-assistant.io, nmcli reports full connectivity
test_supervisor_connectivity Supervisor container can reach internet via docker0 bridge
test_hassio_connectivity CLI container can reach internet via hassio bridge
test_custom_swap_size Custom SWAPSIZE in /etc/default/haos-swapfile correctly applied after reboot
test_no_swap SWAPSIZE=0 correctly disables swap with no service failures
test_kernel_not_tainted /proc/sys/kernel/tainted is 0

Offline Test (tests/smoke_test/test_offline.py):

Test What It Validates
test_ha_runs_offline Home Assistant starts and serves the landing page without internet access

OS Update Tests (tests/smoke_test/test_os_update.py):

Test What It Validates
test_init System boots and Supervisor reaches latest version
test_os_update OS updates to latest stable via ha os update, system reboots to new version
test_boot_other_slot Boot slot switch works, system runs on previous version

Supervisor Tests (tests/supervisor_test/):

Test What It Validates
test_start_supervisor Supervisor starts, responds to ping, Core installs
test_check_supervisor Supervisor and network info APIs respond correctly
test_update_components All components (supervisor, audio, cli, dns, observer, multicast) can update
test_supervisor_is_updated Supervisor version matches latest
test_app_install Core SSH add-on installs and starts
test_supervisor_errors Resolution center health check passes, no unhealthy/unsupported entries
test_create_backup Backup creation succeeds
test_app_uninstall Core SSH add-on uninstalls cleanly
test_restart_supervisor Supervisor restarts and returns to healthy state
test_restore_backup Backup restore recovers add-on state
test_restore_ssl_directory Backup restore recovers specific folder (ssl)
test_no_apparmor_denies No AppArmor DENIED entries in audit log
test_kernel_not_tainted Kernel remains untainted after full test suite

Running Tests

cd tests
pip install -r requirements.txt
pytest --lg-env qemu-strategy.yaml smoke_test/
pytest --lg-env qemu-strategy.yaml supervisor_test/

Tip

The test_init test disables auto-updates before running the suite by setting auto_update: false in /mnt/data/supervisor/updater.json and restarting hassos-supervisor.service. This prevents background updates from interfering with test assertions.

Udev Rules

Rule File Purpose
/usr/lib/udev/rules.d/80-hotplug-cpu.rules Hot-plug CPU management
/usr/lib/udev/rules.d/99-com.rules RPi community device rules
rpi-rf-mod/82-rpi-rf-mod-leds.rules RPi RF module LED control

mDNS / DNS-SD

The file /usr/lib/systemd/dnssd/workstation.dnssd registers the system as a workstation service via DNS-SD, enabling automatic discovery on the local network.

Known Issues and Community Feedback

Based on GitHub issues tracked for this project:

Issue Status Impact
#2142 Open Bluetooth in VirtualBox/Proxmox VMs
#2988 Open LAN DNS resolution broken
#4642 Open Improve systemd shutdown ordering
#4481 Open Smarter default swap size formula
#4121 Open Python logging to systemd-journald
#4631 Open RPi EEPROM update feature
#4604 Open Better support for OS forks
#4223 Open CH341 serial driver not loading

Contributing

Development documentation is hosted at developers.home-assistant.io/docs/operating-system/. The documentation source is in a separate repository: home-assistant/developers.home-assistant.

The kernel versions used in the current branch are documented in Documentation/kernel.md.


9. Integration Points

Home Assistant Supervisor

The Supervisor communicates with the OS through:

  • os-agent — D-Bus interface for host operations (network, disk, system info)
  • Docker socket — Container lifecycle management
  • journald — Centralized logging via systemd-journal-gatewayd
  • /mnt/data — Shared data volume for add-on storage, backups, configuration

Virtualization Guest Agents

HAOS includes guest agent packages for major virtualization platforms:

Platform Agent Service Unit
KVM/QEMU qemu-guest-agent qemu-guest.service
LXC/LXD lxd-guest-agent lxd-agent.service
Xen/XCP-ng xe-guest-utilities xe-daemon.service

These agents provide host-guest communication for operations like graceful shutdown, filesystem freeze, and guest information reporting.

Hardware Acceleration

HAOS includes drivers for hardware accelerators:

Device Package Purpose
Google Coral TPU gasket Coral Edge TPU PCI driver for ML inference
Hailo-8 hailo-pci + hailo8-firmware Hailo AI accelerator for ML inference

Home Automation Hardware

Device Package Purpose
eQ-3 HomeMatic eq3_char_loop Kernel module for HomeMatic CCU communication
RPI-RF-MOD rpi-rf-mod Raspberry Pi radio frequency module (HomeMatic)
Generic Raw UART generic_raw_uart Raw UART access for radio modules
Raspberry Pi Bluetooth pi-bluetooth RPi-specific Bluetooth initialization
RTL8723 Bluetooth bluetooth-rtl8723 Realtek Bluetooth driver
RTL88x2BU Wi-Fi rtl88x2bu Realtek USB Wi-Fi driver