Home Assistant VPS Install: Smart Home Control Center via Docker

Step-by-step guide to installing Home Assistant on a cloud VPS with Docker Compose. Access and coordinate your smart home devices remotely and securely.

Core System Architecture

To self-host Home Assistant on a Virtual Private Server (VPS), we deploy a multi-container stack using Docker Compose. Because the VPS is located outside your local network, the setup uses a Caddy reverse proxy to manage automatic SSL/TLS certificate acquisition and handle traffic routing securely over HTTPS.

graph TD
    Client[Web/Mobile Client] -->|HTTPS :443| Caddy[Caddy Reverse Proxy]
    Caddy -->|HTTP :8123| HA[Home Assistant Core]
    HA -->|Localhost| DB[(SQLite / PostgreSQL)]
    HA -->|MQTT :1883| Mosquitto[Mosquitto MQTT Broker]

Directory Structure

Before executing any commands, construct the following directory structure on your VPS to isolate configuration files and ensure persistent volume bindings:

mkdir -p /opt/homeassistant/config
mkdir -p /opt/homeassistant/caddy_data
mkdir -p /opt/homeassistant/caddy_config
mkdir -p /opt/homeassistant/mosquitto/config
mkdir -p /opt/homeassistant/mosquitto/data
mkdir -p /opt/homeassistant/mosquitto/log

Set the ownership of the directories to match the user executing the containers:

chmod -R 755 /opt/homeassistant

Docker Compose Configuration

Create the main stack definition file /opt/homeassistant/docker-compose.yml with the following configuration:

version: '3.8'

services:
  homeassistant:
    container_name: homeassistant
    image: ghcr.io/home-assistant/home-assistant:stable
    volumes:
      - /opt/homeassistant/config:/config
      - /etc/localtime:/etc/localtime:ro
    environment:
      - TZ=America/New_York
    restart: unless-stopped
    privileged: true
    network_mode: host

  mosquitto:
    container_name: mosquitto
    image: eclipse-mosquitto:latest
    restart: unless-stopped
    ports:
      - "1883:1883"
      - "9001:9001"
    volumes:
      - /opt/homeassistant/mosquitto/config:/mosquitto/config
      - /opt/homeassistant/mosquitto/data:/mosquitto/data
      - /opt/homeassistant/mosquitto/log:/mosquitto/log

  caddy:
    container_name: caddy
    image: caddy:latest
    restart: unless-stopped
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - /opt/homeassistant/Caddyfile:/etc/caddy/Caddyfile
      - /opt/homeassistant/caddy_data:/data
      - /opt/homeassistant/caddy_config:/config
    network_mode: host
[!NOTE] We use network_mode: host for both Home Assistant and Caddy. Home Assistant relies heavily on network discovery (mDNS, UPnP) to detect smart devices. If run inside a bridged Docker network, it cannot listen to broadcast packets on the host physical interface, rendering auto-discovery non-functional.

Configuring MQTT (Mosquitto)

Create the configuration file for the Eclipse Mosquitto MQTT broker at /opt/homeassistant/mosquitto/config/mosquitto.conf:

persistence true
persistence_location /mosquitto/data/
log_dest file /mosquitto/log/mosquitto.log
listener 1883

## Authentication
allow_anonymous false
password_file /mosquitto/config/passwords

Generate the password file and create a user (e.g., ha_mqtt_user) inside the Mosquitto container:

docker run --rm -it -v /opt/homeassistant/mosquitto/config:/mosquitto/config eclipse-mosquitto:latest mosquitto_passwd -c /mosquitto/config/passwords ha_mqtt_user

Configuring Reverse Proxy & SSL via Caddy

Create the /opt/homeassistant/Caddyfile to define routing and handle automatic Let's Encrypt SSL certificates:

your-domain.example.com {
    reverse_proxy localhost:8123 {
        header_up Host {host}
        header_up X-Real-IP {remote}
        header_up X-Forwarded-For {remote}
        header_up X-Forwarded-Proto {scheme}
    }
}

Replace your-domain.example.com with your actual domain name pointing to your VPS public IP.


Home Assistant Reverse Proxy Trust

By default, Home Assistant blocks requests coming from reverse proxies unless explicitly configured to trust them. Add the following block to /opt/homeassistant/config/configuration.yaml to prevent 400: Bad Request errors:

http:
  use_x_forwarded_for: true
  trusted_proxies:
    - 127.0.0.1
    - ::1

If you ever change Caddy to run on a bridged docker network, you must include the bridge subnet (e.g., 172.18.0.0/16) under trusted_proxies.


Launching the Stack

Navigate to the project directory and pull the images:

cd /opt/homeassistant
docker compose pull

Start the containers in detached mode:

docker compose up -d

Verify that all containers are running successfully:

docker compose ps

You can now access your Home Assistant instance at https://your-domain.example.com and complete the initial onboarding wizard.