Getting System Statistics from Beszel into Home Assistant

While the native Home Assistant System Monitor is excellent for basic oversight, integrating Beszel—a lightweight hub-and-node monitoring solution—elevates infrastructure management to a professional level. Here is how it compares to standard tools and the popular go-hass-agent (please see my article about its integration with HA):

1. Multi-Node Centralization & Docker Awareness
The standard HA integration monitors only the local host. Beszel uses a “hub and agent” model to unify all your servers in one view. Unlike native sensors, it provides deep Docker awareness, allowing you to see which specific container is spiking the CPU or leaking memory.

2. Proactive Disk Health (S.M.A.R.T.)
While standard integrations usually only report “Disk Usage %,” Beszel can monitor S.M.A.R.T. statistics. It tracks temperature, power-on hours, and critical failure indicators (like reallocated sectors). This allows Home Assistant to alert you before a drive fails, rather than just telling you it’s full.

3. Historical Trends vs. Database Bloat
Native HA sensors can bloat your database tracking high-frequency metrics. Beszel is optimized for time-series data, providing high-resolution charts without taxing the Home Assistant recorder.

Beszel vs. go-hass-agent:

FeatureBeszelgo-hass-agent
Primary FocusServer/Homelab InfrastructureDesktop/Laptop Integration
VisualsBuilt-in, high-performance chartsDepends on HA Lovelace cards
Storage HealthIntegrated S.M.A.R.T. support

Integrated S.M.A.R.T. support,

But doesn’t work on Raspberry PI at least

ContainerizationPer-container resource metricsBasic host-level metrics
System ControlMonitoring only (Read-only)Can trigger commands (Sleep/Lock)

The Verdict: Choose go-hass-agent for desktop control (like volume or sleep); choose Beszel for reliable server monitoring and proactive disk health tracking across your entire homelab.

After publishing the article about go-hass-agent I got questions “why not Glances”, so please see the following comparison if you are concerned:
Both Beszel and Glances are powerful tools for monitoring system resources, but they serve very different philosophies in the Home Assistant ecosystem. Glances is a classic, feature-rich “everything-and-the-kitchen-sink” monitor, while Beszel is a modern, distributed visualization suite.

1. Architecture and Scaling
Glances: Primarily a standalone tool. To monitor multiple servers in Home Assistant, you typically have to run an instance on each machine and add them as separate integrations. It can be resource-heavy because it gathers hundreds of data points simultaneously.

Beszel: Built specifically for a hub-and-node setup. You run one “Hub” (which connects to Home Assistant) and tiny “Agents” on all your other systems. It is significantly lighter on the CPU and RAM of the monitored nodes.

2. Data Visualization & History
Glances: Excellent for real-time “what is happening right now” snapshots. While it can export to databases, the native Home Assistant integration mostly provides current sensor states.

Beszel: Built with time-series charts at its core. It provides beautiful, smooth historical graphs for CPU, RAM, and Network right out of the box, whereas Glances requires you to build your own graphs in Lovelace using the raw sensor data.

3. Docker and S.M.A.R.T. Depth
Glances: Provides a massive list of processes and basic Docker stats. It is great for seeing “which process is lagging my PC.”

Beszel: Offers superior Docker awareness, grouping resources by container name automatically. Crucially, it has built-in S.M.A.R.T. monitoring for disk health, which is often easier to configure than the complex Python dependencies sometimes required for Glances to see hardware sensors.

FeatureBeszelGlances
PhilosophyClean, distributed visualizationComprehensive “Top” replacement
Setup ComplexityVery Low (Docker-first)Medium (Python or Docker)
Multi-ServerNative (Single Dashboard)Requires multiple HA integrations
Resource UsageUltra-lightweight agentModerate to High
Historical DataBuilt-in high-res chartsRaw sensors only (requires InfluxDB/Grafana for charts)
Actionable AlertsFocus on health/trendsFocus on thresholds/processes

The Verdict: Use Glances if you need to monitor a single powerful machine and want to see every single process, fan speed, and IP connection in real-time.

Use Beszel if you have a homelab with multiple servers/VMs and want a beautiful, low-overhead way to track long-term health, disk S.M.A.R.T. status, and Docker performance within Home Assistant.

Table of Contents
    Add a header to begin generating the table of contents

    Adding Beszel Docker into Home Assistant docker setup ecosystem

    I have my entire Home Assistant Docker ecosystem in the /opt/HA  folder, so I use that path, but feel free to change it according to your preferences.

    Let’s start with the creation of the necessary folders for Beszel Hub and Beszel Agent:

    sudo mkdir -p /opt/HA/beszel/beszel_agent_data
    sudo mkdir -p /opt/HA/beszel/beszel_data

    Beszel Hub Setup

    The next step is adding Beszel hub container to your HA Docker setup.

    Open your docker-compose file and add the config for Beszel:

      beszel:
        image: henrygd/beszel:latest
        container_name: beszel-hub
        restart: unless-stopped
        ports:
          - "8090:8090"
        volumes:
          - /opt/beszel/beszel_data:/beszel_data
        hostname: beszel
        networks:
         home_assistant:
           aliases: 
             - beszel
           ipv4_address: 172.20.0.7
    
      
      home_assistant:
        container_name: ha
        image: "ghcr.io/home-assistant/home-assistant:stable"
        restart: unless-stopped
        hostname: ha 
        depends_on: 
          - zigbee2mqtt
        volumes:
          - /opt/HA/homeassistant:/config
          - /etc/localtime:/etc/localtime:ro
          - /run/dbus:/run/dbus:ro
        privileged: true
        network_mode: host
        extra_hosts:
          - "zigbee2mqtt:172.20.0.2"
          - "core-mosquitto:172.20.0.3"
          - "hass-configurator:172.20.0.4"
          - "portainer:172.20.0.5"
          - "sunsynk:172.20.0.6" 
          - "beszel:172.20.0.7"
     
    
    networks:
      home_assistant: 
        driver: bridge 
        name: home_assistant    
        ipam:
          config:
            - subnet: 172.20.0.0/16

    Sure, you could take the easy route by setting network_mode: host and letting your containers share the host’s network. It definitely saves time since you don’t have to worry about configuring internal networks or aliases.

    However, I usually recommend keeping containers isolated in their own bridge network. Here’s why I think it’s worth the extra couple of lines of config:

    • Better Security: Even on a home server, it’s a good habit to follow the principle of least privilege. If one container is compromised, isolation helps keep the rest of your system safe.
    • Cleaner Traffic: It keeps container-specific ‘chatter’ and broadcast traffic off your main home network, which helps prevent unnecessary congestion.

    Now start your Beszel container:

    sudo docker compose up -d --remove-orphans

    Beszel Agent Setup

    “With everything up and running, head over to your Beszel web interface at http://YOUR_HA_IP:8090 to create your admin account. Once you’re logged in, adding your first system is a breeze:

    1. Start the setup: Click the + Add System button in the top-right corner of the UI.

    2. Identify the instance: Give it a name like ‘Home Assistant’ so you can easily find it later.

    3. Set the IP: Fill in the Host/IP field with your Home Assistant IP (this is mainly for your own reference).

    4. Grab the config: Click Copy Docker Compose to get the configuration you’ll need for the agent.

    Adding Beszel Agent

    Your copied Docker Compose configuration should look like this. Notice that it includes the KEY specific to your instance, which is what allows the agent to talk to your hub securely:

    services:
      beszel-agent:
        image: henrygd/beszel-agent
        container_name: beszel-agent
        restart: unless-stopped
        network_mode: host
        volumes:
          - /var/run/docker.sock:/var/run/docker.sock:ro
          - ./beszel_agent_data:/var/lib/beszel-agent
          # monitor other disks / partitions by mounting a folder in /extra-filesystems
          # - /mnt/disk/.beszel:/extra-filesystems/sda1:ro
        environment:
          LISTEN: 45876
          KEY: 'SECRET_1'
          TOKEN: SECRET_2
          HUB_URL: http://YOUR_INSTANCE_IP:8090

    ⚠️ Heads-up: The default configuration actually skips over a pretty vital feature—SMART disk monitoring. If you want Beszel to track the health of your physical drives and warn you about potential failures, the agent needs a bit more ‘room to breathe’ so it can talk directly to your hardware.

    To enable this, you’ll want to use the version below.

    beszel-agent:
        image: henrygd/beszel-agent:alpine
        container_name: beszel-agent
        restart: unless-stopped
        network_mode: host
        privileged: true
        cap_add:
        - SYS_RAWIO # required for S.M.A.R.T. data
        - SYS_ADMIN # required for NVMe S.M.A.R.T. data
        volumes:
          - /var/run/docker.sock:/var/run/docker.sock:ro
          - /opt/beszel/beszel_agent_data:/var/lib/beszel-agent
          - /dev:/dev
          # monitor other disks / partitions by mounting a folder in /extra-filesystems
          - /BACKUP/.beszel:/extra-filesystems/sdb1:ro
        devices:  # Explicitly pass your disks (replace/add as needed)
          - /dev/sda:/dev/sda
        environment:
          LISTEN: 45876
          KEY: 'SECRET_1'
          TOKEN: SECRET_2
          HUB_URL: http://172.20.0.7:8090
          SMART_DEVICES:
            /dev/sda:sat,/dev/sdb:sat
    

    ⚠️ Here is what you need to change and why:

    • The :alpine Tag: We use henrygd/beszel-agent:alpine because it comes pre-packaged with smartmontools, which is the actual software that reads your disk health.

    • network_mode: host: This allows the agent to see your host’s network interfaces directly to give you accurate bandwidth statistics.

    • cap_add & devices: These give the container the specific “capabilities” and hardware access it needs to query your physical SSDs or HDDs without giving it full, unrestricted access to the whole system.

    • HUB_URL: In this setup, we point the agent to the Beszel Hub’s internal Docker IP. This keeps your monitoring traffic isolated within Docker rather than sending it out to your router and back.

    • SMART_DEVICES: This tells the agent exactly which disks to check and what “type” they are (like nvme or sat).

    Finding Your Disk Types

    Before you update your config, you need to know how your system identifies your disks. You can find this using the smartctl utility on your host machine:

    sudo apt install smartmontools
    sudo smartctl --scan
    /dev/sda -d sat # /dev/sda [SAT], ATA device
    /dev/sdb -d sat # /dev/sdb [SAT], ATA device
    

    As you can see, smartctl utility provides types of attached disks e. g. sat in my case.

    After adding and adjusting Beszel Agent Docker compose config into your Home Assistant docker-compose.yml start your Docker container:

    sudo docker compose up -d --remove-orphans

    If you configured your Beszel Agent properly, you should see statistics of your system:

    Your Beszel is configured, so you can start to integrate in into Home Assistant!

    Home Assistant Configuration

    Ingress Panel config for Beszel

    Firtst of all, you have to install HACS_Ingress plugin into your Home Assitanse, so follow this article for instalation and initial config.

    Beszel is very sensetive for URL paths, so you should be careful with configs to make it works.

    1. Navigate to File Additor in your Home Assistant and add configuration below into HA configuration.yaml file:

    ingress:
      beszel:
        work_mode: ingress
        title: "Beszel Hub"
        ui_mode: toolbar
        icon: "mdi:monitor-dashboard"
        url: "http://beszel:8090"
        # The 'rewrite' in NGINX for the request path is handled automatically here.
        # However, if Beszel's UI uses absolute paths (like "/static/main.js"), 
        # you may need the body rewrite below:
        rewrite:
          # Fixes only the root-relative assets (prevents doubling up)
          - mode: body
            match: 'href="/assets/'
            replace: 'href="$http_x_ingress_path/assets/'
          - mode: body
            match: 'src="/assets/'
            replace: 'src="$http_x_ingress_path/assets/'
          # Fixes the main entry points
          - mode: body
            match: 'href="/manifest.json"'
            replace: 'href="$http_x_ingress_path/manifest.json"'
          - mode: body
            match: 'src="/_/'
            replace: 'src="$http_x_ingress_path/_/'

    ⚠️ Heads-up: The hostname in url must strictly correspond to your docler-compose config in beszel section: hostname: and aliases:

    ...
    hostname: beszel
        networks:
         home_assistant:
           aliases: 
             - beszel
           ipv4_address: 172.20.0.7
    ...       
           

    Also it must correspond to hostname in Home Assisstant section:

    ...
    extra_hosts:
          - "beszel:172.20.0.7"
    ...       
           

    2. Reload Ingress config:

    Reload Ingress Config

    Now, you should see “Beszel Hub”, but if you click it in your Home Assistant sidebar, you will see a blank screen or a loading error, don’t panic. This happens because Home Assistant’s Ingress (the system that puts apps into the sidebar) adds a unique path prefix to the URL.

    Basically, Beszel is looking for its files in the “lobby,” but Home Assistant has tucked it away in a “specific room.” We just need to tell Beszel where it’s being hosted so it can find its own assets.

    The Fix: Setting the APP_URL

    You’ll need to edit the Beszel Hub (not the agent) section of your docker-compose.yml file. Add the APP_URL environment variable and point it to your Home Assistant Ingress URL.

    Here is how that section should look:

    beszel:
        image: henrygd/beszel:latest
        container_name: beszel-hub
        restart: unless-stopped
        ports:
          - "8090:8090"
        volumes:
          - /opt/beszel/beszel_data:/beszel_data
        environment:
          - APP_URL=https://YOUR_DOMAIN:8123/api/ingress/beszel
        hostname: beszel
        networks:
         home_assistant:
           aliases: 
             - beszel
           ipv4_address: 172.20.0.7
         
           

    ⚠️ Precision is Key: Building your APP_URL

    To make this work, your APP_URL variable needs to be a combination of your Base Address and a Strict Path.

    1. The Variable Part (Your Base Address)

    This depends entirely on how you access Home Assistant:

    • Protocol: Use https:// if you have an SSL certificate (Nginx, Let’s Encrypt, Cloudflare), otherwise use http://.

    • Domain/IP: Use your local IP (e.g., 192.168.1.50) or your external domain (e.g., myhome.duckdns.org).

    • Port: Include your port (usually :8123) unless you are using a proxy that hides it.

    2. The Strict Part (The Ingress Path)

    This part is non-negotiable. It must be exactly: /api/ingress/beszel

    Note: Do not add a trailing slash or any extra characters at the end of this string, or the routing will break.

    Apply you docker compose changes:

    sudo docker compose up -d --remove-orphans

    Now Beszel should be accessible in your ingress panel.

    ⚠️ Heads-up:

    Once you set the APP_URL to the Ingress path, Beszel expects that specific prefix (/api/ingress/beszel) to be part of every request. This creates a bit of a “Catch-22” for how you log in:

    • Option A: Integrated Mode (Home Assistant Sidebar)

      • Setup: APP_URL is configured in your docker-compose.yml.

      • Result: It works perfectly inside your Home Assistant UI, but if you try to go to http://YOUR_IP:8090 directly, the page will likely be blank or show “404 Not Found” errors because the paths don’t match.

    • Option B: Standalone Mode (Direct Access)

      • Setup: APP_URL is removed or commented out.

      • Result: You can access Beszel directly at http://YOUR_IP:8090, but the sidebar link in Home Assistant will break.

    Why can’t I have both?

    Beszel’s web server needs to know its “Base URL” to serve its internal files (like images and scripts). It can only have one Base URL at a time. When we set it to the Ingress path, we are telling the app: “You no longer live at the front door; you now live in the ‘Home Assistant’ room.”

    How to switch back?

    If you decide you’d rather use Beszel as a standalone app and don’t care about the sidebar integration:

    1. Open your docker-compose.yml.

    2. Delete or comment out (#) the line for APP_URL.

    3. Run docker-compose up -d to apply the changes.

    4. Access it directly via its IP and Port.

    Add Beszel Statistics to Home Assistant as Sensors.

    While you can find several Beszel integrations in HACS, most currently lack support for S.M.A.R.T. disk health. To bridge this gap, we’ll use Home Assistant’s REST API sensors to pull that data directly.

    Why integrate if you already have the UI?

    The answer is simple: Actionable Notifications. Having a dashboard is great, but you don’t want to be checking it manually every hour. By bringing these metrics into Home Assistant, you can automate alerts for:

    • Thermal Protection: Get notified of system overheating if a fan fails or ambient temperatures spike.

    • Drive Health: Receive a heads-up on disk degradation before it turns into a data-loss disaster.

    The Integration Strategy: 3 Key Endpoints

    Beszel’s API (built on PocketBase) is robust but requires a specific workflow to access data securely. We will set up three separate REST sensors to handle the following:

    1. The Access Token (Authentication): For security, Beszel doesn’t allow “anonymous” data scraping. We first need to send your credentials to an authentication endpoint to receive a temporary bearer token.

    2. General System Metrics: Once we have our token, this endpoint provides the “bread and butter” stats: CPU load, RAM usage, and system temperatures.

    3. S.M.A.R.T. Data: Because hardware-level disk health is a bit more specialized, it lives in its own endpoint. This is where we’ll grab those vital signs for your HDDs and SSDs.

    By the end of this setup, you’ll have a complete set of sensors ready for your Home Assistant dashboard and automation engine.

    Get Access Tocken

    Let’s start with the first sensor for getting an access token and storing it for further usage.

    Navigate to File Additor in your Home Assistant and add the configuration below into HA configuration.yaml file:

    rest:
     - resource: "http://beszel:8090/api/collections/_superusers/auth-with-password"
       method: POST
       payload: '{"identity":"YOUR_USERNAME", "password":"YOUR_PASSWORD"}'
       timeout: 30
       headers:
          Content-Type: "application/json"
       scan_interval: 12000
       sensor:
        name: "Beszel API Token"
        value_template: '{{ value_json.token }}'   # Shows first part of token or error
        json_attributes:
          - record
           

    ⚠️ Heads-up:

    To make sure this works on the first try, pay close attention to these three things:

    • The Resource URL: The hostname in the URL (beszel in my example) must strictly match the name or alias you gave the Beszel container in your docker-compose.yml. Since they are in the same Docker network, HA will find it by name.

    • Credentials: Replace YOUR_USERNAME and YOUR_PASSWORD with the admin credentials you created when you first opened the Beszel web interface.

    • The “First Time” Restart: This is a common trap! If this is your first time adding a rest: sensor to Home Assistant, a simple “Reload YAML” won’t work. You must go to Settings > System and perform a full Restart to initialize the REST integration.
      Otherwise, you can reload your REST entities:

    Reload Rest Config

    Once Home Assistant has restarted, let’s make sure it successfully grabbed the token:

    1. Navigate to Developer Tools > States.

    2. Search for sensor.beszel_api_token.

    3. The Result: If everything is correct, the “State” column should be filled with a long string of random characters. That is your active token!

    Pro-Tip: If the state says unknown or unavailable, check your Home Assistant logs (Settings > System > Logs). It will usually tell you if there was a connection timeout or an “Unauthorized” error due to a typo in your password.

    Get Generic information

    Back to File Additor in your Home Assistant and add the configuration below into HA configuration.yaml file:

     - resource: "http://beszel:8090/api/collections/systems/records/System_ID"
       method: GET
       headers:
         Authorization: "Bearer {{ states('sensor.beszel_api_token') }}"
         Content-Type: "application/json"
       scan_interval: 60
       sensor:
          - name: "Beszel HA Server Status"
            value_template: "{{ value_json.status }}"
            icon: mdi:server
          - name: "Beszel HA CPU Usage"
            value_template: "{{ value_json.info.cpu | round(1) | default('unknown') }}"
            unit_of_measurement: "%"
            icon: mdi:cpu-64-bit
          - name: "Beszel HA RAM Usage"
            value_template: "{{ value_json.info.mp | round(1) | default('unknown')}}"
            unit_of_measurement: "%"
            icon: mdi:memory
          - name: "Beszel HA Disk Usage"
            value_template: "{{ value_json.info.dp | round(1) | default('unknown')}}"
            unit_of_measurement: "%"
            icon: mdi:harddisk
          - name: "Beszel HA Temperature"
            value_template: "{{ value_json.info.dt | round(1) | default('unknown')}}"
            unit_of_measurement: "°C"
            icon: mdi:thermometer
          - name: "Beszel HA Network Throughput"
            value_template: "{{ value_json.info.b | round(2) | default('unknown')}}"
            unit_of_measurement: "MB/s"
            icon: mdi:transfer
          - name: "Beszel HA /BACKAP Usage"
            unique_id: "beszel_ha_sdb1_usage"
            # Accesses the specific partition key
            value_template: >
              {{ value_json.info.efs.sdb1 | default(0) }}
            unit_of_measurement: "%"
            icon: mdi:partition
           

    ⚠️ Heads-up:

    To make sure this works on the first try, pay close attention to the following things:

    • The Resource URL: The hostname in the URL (beszel in my example) must strictly match the name or alias you gave the Beszel container in your docker-compose.yml. Since they are in the same Docker network, HA will find it by name.

    • System_ID: While Beszel’s API can return data for every system you have registered at once, I don’t recommend doing it that way. Parsing a giant “blob” of data for multiple machines makes troubleshooting much harder. It’s much cleaner to create a dedicated sensor for each system using its unique ID.

      How to Find Your System ID

      1. Open your Beszel Web UI.

      2. Click on the “Person” icon (Account/User menu) in the top-right corner.

      3. Select the Systems menu.

    Systems menu

    4. Find the system you want to monitor (e.g., “Home Assistant”) and look for the ID column. It will be a string of random letters and numbers (like 7j3n2k9m4l).

    Beszel Systems List
    • Names and unique_id: Adjust them according to your wishes.

    • Mount points: Beszel checks attached partitions’ usage by devices names. So, your template {{ value_json.info.efs.sdb1 | default(0) }} must be corresponded to disk name sdb1 in Beszel Agent configuration: 

        volumes:
          - /BACKUP/.beszel:/extra-filesystems/sdb1:ro
    • The Restart: After you restart Home Assistant, you might notice that your new sensors show a status of “Unknown” Don’t panic! This is perfectly normal behavior. Here’s why it happens:

      • The Race Condition: Home Assistant fires off all its REST API calls simultaneously when it boots up.

      • The Token Delay: Your data sensors (System Stats and SMART data) are trying to talk to Beszel at the exact same time the “Token Sensor” is trying to get authenticated.

      • The Result: Because the data sensors don’t have a valid token yet, Beszel rejects their first request.

      The Fix: Just wait for the next “update interval” (usually a minute or two). On the second try, the Token Sensor will have its data ready, and your metrics will pop into life.

    Get SMART information

    Back to File Additor in your Home Assistant and add the configuration below into HA configuration.yaml file:

     - resource: "http://beszel:8090/api/collections/smart_devices/records/Disk_ID"
       method: GET
       headers:
          Authorization: "Bearer {{ states('sensor.beszel_api_token') }}"
          Content-Type: "application/json"
       scan_interval: 120
       sensor:
          - name: "Beszel HA SDA Health"
            unique_id: "beszel_sda_health_id"
            value_template: "{{ value_json.state | default('unknown')}}"
          - name: "Beszel HA SDA Temp"
            unique_id: "beszel_sda_temp_id"
            value_template: "{{ value_json.temp | default('unknown')}}"
            unit_of_measurement: "°C"
          - name: "Beszel HA SDA Pending Sectors"
            unique_id: "beszel_sda_pending_id"
            value_template: "{{ value_json.attributes | selectattr('id', 'eq', 197) | map(attribute='rv') | first | default(0) }}"

    ⚠️ Heads-up:

    To make sure this works on the first try, pay close attention to the following things:

    • The Resource URL: The hostname in the URL (beszel in my example) must strictly match the name or alias you gave the Beszel container in your docker-compose.yml. Since they are in the same Docker network, HA will find it by name.

    • Disk_ID: Just like the System ID, we need a specific Disk ID to pull the S.M.A.R.T. data. Since each physical drive has its own unique health record in Beszel’s database, you need to point Home Assistant to the exact one you want to monitor. 

      To find your Disk ID, follow the same path as before:

      1. In the window opened in the previous step backend settings window), look for the smart_devices menu on the left side panel.

      2. Find the disk you want to track (e.g., /dev/sda or your NVMe drive).

      3. Copy the string from the ID column for that specific disk.

    Beszel Disks List
    • Names and unique_id: Adjust them according to your wishes.

    • The Restart: Again, you will be faced with “Unknown” sensors states, but you already know how to deal with it.

    Conclusion

    Congratulations! You have successfully turned Beszel from a standalone dashboard into a deeply integrated engine for your Home Assistant setup.

    By setting up these REST sensors, you’ve done something most off-the-shelf integrations can’t: you’ve gained direct access to your hardware’s “vital signs,” specifically those crucial S.M.A.R.T. disk stats.