Install Home Assistant on Ubuntu
Why Ubuntu Specifically?
Ubuntu is the most common server distribution for self-hosting, and Home Assistant runs well on it with Docker. But Ubuntu has a few platform-specific requirements that trip people up: host networking configuration for device discovery, udev rules for stable USB dongle paths, D-Bus access for Bluetooth integrations, and NetworkManager for Home Assistant’s network management features.
This guide covers the Ubuntu-specific setup. For the general Docker Compose walkthrough, see the main Home Assistant guide.
Prerequisites
- Ubuntu 22.04 LTS or 24.04 LTS (server or desktop)
- Docker and Docker Compose installed (guide)
- 2 GB of RAM minimum (4 GB recommended)
- 32 GB of free disk space
- A Zigbee or Z-Wave USB dongle (optional, for local device control)
- Root or sudo access
Install Docker on Ubuntu
If Docker is not installed yet:
sudo apt update
sudo apt install -y ca-certificates curl gnupg
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
sudo chmod a+r /etc/apt/keyrings/docker.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
sudo usermod -aG docker $USER
Log out and back in for the group change to take effect.
Platform Setup
Install Required System Packages
Home Assistant’s Bluetooth and network integrations depend on system services. Install them:
sudo apt install -y dbus network-manager bluez
- dbus — Inter-process communication. Home Assistant uses D-Bus to communicate with BlueZ for Bluetooth device discovery.
- network-manager — Home Assistant’s network integration can manage your server’s network connections through NetworkManager. Not strictly required, but enables the Network panel in HA’s settings.
- bluez — Linux Bluetooth stack. Required for Bluetooth integrations (ESPHome Bluetooth Proxy, iBeacons, BLE sensors).
Configure NetworkManager
By default, Ubuntu Server uses Netplan with networkd as the renderer. Home Assistant’s network integration works best with NetworkManager. To switch:
# Check current Netplan renderer
cat /etc/netplan/*.yaml
Edit your Netplan config (e.g., /etc/netplan/01-netcfg.yaml) to use NetworkManager:
network:
version: 2
renderer: NetworkManager
Apply the change:
sudo netplan apply
If you prefer to keep networkd (which is fine for servers), Home Assistant will still work — you just will not see network management options in the HA UI.
Set Up USB Device Passthrough with udev Rules
If you use Zigbee or Z-Wave USB dongles, Linux assigns device paths like /dev/ttyUSB0 dynamically. The path can change after a reboot if you have multiple USB serial devices. Udev rules create stable symlinks so your device is always at a predictable path.
Find your dongle’s vendor and product ID:
lsusb
Look for your device. Example output:
Bus 001 Device 004: ID 10c4:ea60 Silicon Labs CP210x UART Bridge
The 10c4:ea60 is the vendor:product ID pair. Get the serial number for a more specific rule:
udevadm info -a -n /dev/ttyUSB0 | grep '{serial}'
Create a udev rule at /etc/udev/rules.d/99-usb-serial.rules:
# Zigbee dongle — Sonoff Zigbee 3.0 USB Dongle Plus (Silicon Labs CP2102N)
SUBSYSTEM=="tty", ATTRS{idVendor}=="10c4", ATTRS{idProduct}=="ea60", ATTRS{serial}=="YOUR_SERIAL_HERE", SYMLINK+="zigbee", MODE="0666"
# Z-Wave dongle — example Aeotec Z-Stick Gen5
SUBSYSTEM=="tty", ATTRS{idVendor}=="0658", ATTRS{idProduct}=="0200", SYMLINK+="zwave", MODE="0666"
Replace YOUR_SERIAL_HERE with your dongle’s actual serial number. Reload udev rules:
sudo udevadm control --reload-rules
sudo udevadm trigger
Verify the symlink was created:
ls -la /dev/zigbee /dev/zwave
Now your Zigbee dongle is always at /dev/zigbee regardless of USB enumeration order.
Docker Compose Configuration
Create the directory structure:
sudo mkdir -p /opt/homeassistant/config
Create /opt/homeassistant/docker-compose.yml:
services:
homeassistant:
container_name: homeassistant
image: ghcr.io/home-assistant/home-assistant:2026.3.1
volumes:
- /opt/homeassistant/config:/config
- /etc/localtime:/etc/localtime:ro
- /run/dbus:/run/dbus:ro
devices:
- /dev/zigbee:/dev/zigbee # Zigbee USB dongle (via udev symlink)
# - /dev/zwave:/dev/zwave # Z-Wave USB dongle (uncomment if used)
environment:
- TZ=America/New_York
restart: unless-stopped
network_mode: host
Why Host Networking on Ubuntu
Home Assistant uses mDNS (port 5353), SSDP (port 1900), and UPnP for automatic device discovery. These protocols rely on broadcast/multicast traffic that does not cross Docker’s bridge network boundary. With network_mode: host, the container shares the host’s network stack directly. Home Assistant binds to port 8123 on all host interfaces.
The trade-off: you cannot use Docker’s port mapping (ports: directive is ignored with host networking). Port 8123 is exposed directly on the host.
Why Not Privileged Mode
The main guide uses privileged: true for simplicity. On Ubuntu, you can avoid privileged mode by being explicit:
- Mount
/run/dbus:/run/dbus:rofor Bluetooth (instead of granting full host access) - Map specific USB devices via
devices:using udev symlinks (instead of accessing all host devices) - Keep
network_mode: hostfor device discovery
This follows the principle of least privilege. Only use privileged: true if you encounter permission issues you cannot resolve with explicit device mappings.
D-Bus for Bluetooth
The /run/dbus:/run/dbus:ro volume mount gives Home Assistant read-only access to the host’s D-Bus socket. This is required for:
- Bluetooth device discovery — scanning for BLE devices
- ESPHome Bluetooth Proxy — using ESP32 devices as remote Bluetooth scanners
- iBeacon tracking — presence detection with Bluetooth beacons
Without this mount, Bluetooth integrations fail silently or show “Bluetooth not available” in the HA UI.
Make sure the D-Bus service is running:
sudo systemctl status dbus
It should be active. On Ubuntu, it always is by default.
Start the Stack
cd /opt/homeassistant
docker compose up -d
Verify it is running:
docker compose logs -f homeassistant
Access the web UI at http://<your-ubuntu-server-ip>:8123.
systemd Auto-Restart
Docker’s restart: unless-stopped handles container restarts, but you may want a systemd service for tighter integration with Ubuntu’s init system. This gives you systemctl commands, boot ordering, and journal logging.
Create /etc/systemd/system/homeassistant.service:
[Unit]
Description=Home Assistant
Requires=docker.service
After=docker.service network-online.target
Wants=network-online.target
[Service]
Type=oneshot
RemainAfterExit=yes
WorkingDirectory=/opt/homeassistant
ExecStart=/usr/bin/docker compose up -d
ExecStop=/usr/bin/docker compose down
ExecReload=/usr/bin/docker compose restart
TimeoutStartSec=300
[Install]
WantedBy=multi-user.target
Enable and start:
sudo systemctl daemon-reload
sudo systemctl enable homeassistant
sudo systemctl start homeassistant
Now Home Assistant starts automatically on boot and can be managed with:
sudo systemctl status homeassistant
sudo systemctl restart homeassistant
sudo journalctl -u homeassistant -f
Configuration
Ubuntu Firewall (UFW)
If UFW is active, allow the ports Home Assistant needs:
# Home Assistant web UI
sudo ufw allow 8123/tcp
# mDNS for device discovery
sudo ufw allow 5353/udp
# SSDP for device discovery
sudo ufw allow 1900/udp
# Zigbee2MQTT web UI (if using)
sudo ufw allow 8080/tcp
# MQTT broker (if using)
sudo ufw allow 1883/tcp
Verify:
sudo ufw status
Automatic Updates with Watchtower (Optional)
Home Assistant releases monthly updates. You can automate updates with Watchtower, but be aware that HA updates occasionally introduce breaking changes. The safer approach is manual updates by changing the image tag in docker-compose.yml.
If you want automatic updates anyway:
watchtower:
container_name: watchtower
image: containrrr/watchtower:1.7.1
volumes:
- /var/run/docker.sock:/var/run/docker.sock
environment:
- WATCHTOWER_CLEANUP=true
- WATCHTOWER_INCLUDE_STOPPED=true
- WATCHTOWER_SCHEDULE=0 0 4 * * * # 4 AM daily
restart: unless-stopped
Monitor the update log: docker logs watchtower.
Platform-Specific Tips
- AppArmor and Docker. Ubuntu enables AppArmor by default. If Home Assistant fails to access USB devices or D-Bus despite correct configuration, check if AppArmor is restricting the container. Run
dmesg | grep apparmorto look for denials. You can addsecurity_opt: - apparmor:unconfinedto the container definition as a last resort. - Snap Docker vs APT Docker. Do not use the
dockersnap package. It runs in a confined namespace that breaks volume mounts and device access. Use the official Docker APT repository as shown in the prerequisites. - Ubuntu Pro / Livepatch. These do not interfere with Home Assistant. Kernel live patches apply without rebooting, so your HA container stays running.
- Multicast DNS resolution. Ubuntu includes
systemd-resolvedwhich handles.localmDNS resolution. This complements Home Assistant’s discovery rather than conflicting with it. Do not disablesystemd-resolvedfor Home Assistant (unlike Pi-hole, which needs port 53).
Troubleshooting
USB Device Not Found After Reboot
Symptom: Home Assistant loses connection to the Zigbee/Z-Wave dongle after a reboot. The device path changed from /dev/ttyUSB0 to /dev/ttyUSB1.
Fix: Set up udev rules as described above. Use the stable symlink (/dev/zigbee) in your Docker Compose instead of /dev/ttyUSB0. After creating the udev rule, unplug and replug the dongle, then restart the container.
Bluetooth “Not Available” in HA
Symptom: Bluetooth integration shows “Bluetooth adapter not found” even though the host has Bluetooth hardware.
Fix: Verify D-Bus is mounted:
docker inspect homeassistant | grep -A2 dbus
Check that BlueZ is installed on the host:
sudo systemctl status bluetooth
bluetoothctl list
If BlueZ is not running, start it:
sudo systemctl enable bluetooth
sudo systemctl start bluetooth
Restart the Home Assistant container after fixing.
Device Discovery Fails on Ubuntu with Multiple Network Interfaces
Symptom: Devices on your LAN are not auto-discovered, even with host networking enabled.
Fix: If your Ubuntu server has multiple network interfaces (common with VMs or servers with both Ethernet and Wi-Fi), mDNS traffic may be going out the wrong interface. Check your default route:
ip route show default
Make sure the default route uses the interface connected to your IoT network. If needed, set a static route or disable unused interfaces.
Permission Denied on /dev/ttyUSB0
Symptom: PermissionError: [Errno 13] Permission denied: '/dev/ttyUSB0' in Home Assistant logs.
Fix: Add your user to the dialout group:
sudo usermod -aG dialout $USER
Or set MODE="0666" in the udev rule (as shown above) to make the device world-readable/writable. Restart udev and the container.
Container Fails to Start After Ubuntu Upgrade
Symptom: After upgrading Ubuntu (e.g., 22.04 to 24.04), Home Assistant container fails to start with various errors.
Fix: Ubuntu major upgrades can change kernel versions, D-Bus socket paths, or AppArmor policies. Steps:
- Verify Docker is running:
sudo systemctl status docker - Pull a fresh image:
docker compose pull - Check D-Bus socket path:
ls -la /run/dbus/system_bus_socket - Recreate the container:
docker compose up -d --force-recreate
Related
Get self-hosting tips in your inbox
Get the Docker Compose configs, hardware picks, and setup shortcuts we don't put in articles. Weekly. No spam.
Comments