HomePage: Services Dashboard (Rev: 09/14)

docker compose setup for HomePage with Dashdot and Watchtower widgets from Komodo or Dockge, including detailing the dashboard setup for a multi-tab layout with four sections of content: system metrics, static content, dynamic applications (docker service discovery), and service monitors.

Sep 14, 2024
đź“‹
This post details setting up HomePage as part of a docker compose stack to create a service dashboard with system and service monitors, automatic service discovery (using Docker labels) and keyboard service search for QuickLaunch.
 
Revision: 20240914-0 (init: 20240908)
 
docker compose setup for HomePage with Dashdot and Watchtower widgets from Komodo or Dockge, including detailing the dashboard setup for a multi-tab layout with four sections of content: system metrics, static content, dynamic applications (docker service discovery), and service monitors.
 

Preamble

Services Map

Documentation is a crucial feature of a successful self-hosting methodology.
While migrating to Traefik and creating reverse proxies by adding dynamic configuration files or Docker labels, I documented the services’ map (on Notion, with multiple Table views).
A “Per Host” Table view (sorted by “Exposed Port”) for the services on one server is as follows:
notion image
Among the columns existing in the original Notion DataBase from which those views are created are:
  • Name: the service name — duplicates can exist if the service either uses multiple port (list all ports exposed) and/or is deployed on multiple Hosts
  • Host: the server name — a “single select” list of available servers
  • Exposed Port: any port exposed by the service, be it mapped to a reverse proxy or not
  • Slug base: the base url to use for each domain (if multiple), for example the home slug with the example.com domain; the full url is home.example.com
  • Domain mapping: for example.com, how the service is exposed via a reverse proxy (if it is): Traefik label, name of the Traefik dynamic yaml file, … if more than one domain, create as many “domain mapping” columns as needed
    • Per Domain, a “Added to “HomePage” checkmark as well as “Credentials stored in Password Manager” checkmark
  • Deployment Method: how the service is deployed, with entries from a mutli-selection list with content such as “Unraid”, “Dockge”, “Komodo”, “Docker Compose”, … i.e. make it easier to find the a given service in case of issues with it.
  • Tool url: where to find documentation in case of issue, more often than not GitHub repositories.
  • notes: Any notes relevant to the service; for example: “VNC-based, add /vnc.html to url”
  • Relationship: Notion DB allow linking components to other rows from the same table, for example for the “HomePage” service, it is using the “Docker Socket Proxy” service.

Automatic Discovery

Automation is another relevant component when attempting to maintain this knowledge map.
It is extremely difficult to keep multiple sources of truth synchronized to one another. As such, having some component automatically announce themselves is practical.
In the same way as when adding an entry to Traefik can be done using Docker labels, the dashboard solution we retained, Homepage can too automatically register Docker service using labels.

Homepage

A modern, fully static, fast, secure fully proxied, highly customizable application dashboard with integrations for over 100 services and translations into multiple languages. Easily configured via YAML files or through docker label discovery.
r/homelab and r/selfhosted are great places to discover people showcasing their “homepage dashboard”.
For this setup, we are using multiple features of the tool:
  • tabs to separate components per server and/or per purpose
  • widgets to display monitors and service details
  • quicklaunch to start a service from the keyboard (no mouse click)
  • a layout to separate multiple sections: metrics, static, dynamic and widgets
  • multiple instances to separate networks definitions (or use multiple Traefik domains, for example a domain1 for local network, and a domain2 for a reverse-proxy running over Tailscale where not all services are available)
 
Here is what our local setup provides (yours will likely differ):
notion image

Using docker labels

We will rely on homepage’s ability to perform Automatic Service Discovery using Docker labels. Those labels are homepage.group, homepage.name, homepage.icon, homepage.href, homepage.description as well as instance specific options.
The following are copy→adapt→paste option for a use-case with a single instance, multiple homepage instance and an Unraid XML template filler. In each case:
  • replace example.com and example.net with the INSTANCE domain
  • replace ALIAS with the application name
  • replace TAB with the tab name as defined in the layout: section of your settings.yaml file
  • replace SIGN with the expected icon name.
  • replace SLUG with the base url of the service you are connecting; it will be used with the domain name; for example if slug is home and the domain example.com, the href entry will be home.example.com
  • .instance allows separation between different homepages’ instance
    • Replace INSTANCE1 and INSTANCE2 with the value you will use for your instanceName: (in the settings.yaml file)
    • do not add an entry if a service does not exist for a given instance
  • We have added the TAB in the .description field to easily sort when using homepage’s quicklaunch option. It is also possible to use the host in that location. However you decide to use those, they are methods to differentiate multiple instance of a same .name

Single Instance

labels: - homepage.name=ALIAS - homepage.group=TAB_apps - homepage.icon=SIGN.png - homepage.href=https://SLUG.example.com/ - homepage.description=ALIAS (TAB)

Multiple homepage instances

labels: - homepage.name=ALIAS - homepage.group=TAB_apps - homepage.icon=SIGN.png - homepage.instance.INSTANCE1.href=https://SLUG.example.com/ - homepage.instance.INSTANCE2.href=https://SLUG.example.net/ - homepage.description=ALIAS (TAB)

Unraid with multiple instances

Although it is possible to manually “Add” “labels” for each required label using the Unraid WebUI, it is also possible to modify the Docker service’s XML file.
Those are in the /boot/config/plugins/dockerMan/templates-user folder and are named my-<SERVICE>.xml . Once we have found the match entry, we can edit it and copy the adapted lines before the final </Container> line:
<Config Name="homepage.name=ALIAS" Target="homepage.name" Default="" Mode="" Description="" Type="Label" Display="always" Required="false" Mask="false">ALIAS</Config> <Config Name="homepage.group=TAB_apps" Target="homepage.group" Default="" Mode="" Description="" Type="Label" Display="always" Required="false" Mask="false">TAB_apps</Config> <Config Name="homepage.icon=SIGN" Target="homepage.icon" Default="" Mode="" Description="" Type="Label" Display="always" Required="false" Mask="false">SIGN</Config> <Config Name="homepage.instance.INSTANCE1.href=https://SLUG.example.com/" Target="homepage.instance.INSTANCE1.href" Default="" Mode="" Description="" Type="Label" Display="always" Required="false" Mask="false">https://SLUG.example.com/</Config> <Config Name="homepage.instance.INSTANCE2.href=https://SLUG.example.net/" Target="homepage.instance.INSTANCE2.href" Default="" Mode="" Description="" Type="Label" Display="always" Required="false" Mask="false">https://SLUG.example.net/</Config> <Config Name="homepage.description=ALIAS (TAB)" Target="homepage.description" Default="" Mode="" Description="" Type="Label" Display="always" Required="false" Mask="false">ALIAS (TAB)</Config>
💡 After modifying the XML file, from Unraid’s “Docker” tab, Edit the Service then make and undo any change to enable the Save button. Save it to restart the updated service.

Preliminary installations

We will deploy services using docker compose. Although tools such as Dockge or Komodo are not a requirement, they provide a convenient method to deploy “stacks”. Please see the Dockge post for additional details for details on previous stacks deployments.
In particular, in our example configuration files, we will show how to integrate Dashdot and Watchtower (with metric collection) as widgets as well as automatically discovered docker services. Both were installed through instruction from that post.
We are sharing an example.com versions of the compose.yaml files we are using for those configuration (follow the direct links to the files, or the content relative to this post is posted at https://github.com/mmartial/geekierblog-artifacts/tree/main/20240908-homepage):
  • Dashdot’s compose.yaml. Please adapt:
    • DASHDOT_CUSTOM_HOST with the hostname of the system you are using DashDot with
    • DASHDOT_OVERRIDE_OS with the host OS
    • In the labels: section:
      • update with the .group value you intend to use (also update the .description)
      • update the .href to reflect the URL that matches your setup
      • Note that this example is only for a single instance, adapt if needed.
    • We are using a GPU version of the container. To use a CPU-only version:
      • use the mauricenino/dashdot:latest image instead of the :nvidia one
      • remove the deploy: content up to and including - gpu
    • No other labels beyond the watchtower one are presents. If needed, add other such as Traefik labels.
  • Watchtower’s compose.yaml. Where:
    • We are using a tab1-token value for WATCHTOWER_HTTP_API_TOKEN
    • We are exposing the service on port 28080
    • The command: line sets a schedule and enable the API mode. To learn more on how to manually trigger the update, see https://containrrr.dev/watchtower/http-api-mode/
    • No labels are presents for homepage, since the tool does not provide a WebUI. No other labels are added either; extend as needed.
    • We also do not include any environment variable to cover the user of shoutrrr notifications as the choice of method is left to the end user. Should you decide to use it, please adapt the following additional content for your environment: section as needed based on the list of available notification services (environment variables for API keys and such are recommended):
    • - WATCHTOWER_NOTIFICATIONS_HOSTNAME=myhost - WATCHTOWER_NOTIFICATIONS=shoutrrr - WATCHTOWER_NOTIFICATION_URL=...
Although we are not describing how to set reverse proxy configurations for those, in the further configuration steps we will rely on the following two urls for those services:
  • Dashdot at https://dashdot.example.com
  • Watchtower at https://watchtower.example.com

Docker Socket Proxy

Docker Socket Proxy “is a security-enhanced proxy for the Docker Socket” that limits the access to details to the ones the user allows. Unless, you have used it for other setup (such as installing Traefik), It is only required if you are using Homepage with tabs from more than a single server. We will proceed considering it was installed for our setup.
This setup will allow for containers from hosts other than the one starting Homepage to be self-discovered by Homepage from any server host. It is only to be used within a non-internet exposed local network. Even with this limitation, it is also recommended to add firewall rules to only allow connection to the exposed port from the authorized Homepage host’s IP. We will not use the tool using the privileged flag and will only share the docker socket as ready only so the connection can not perform any action on the running container.
Follow the link to obtain our proposed compose.yaml. The only access we grant ourselves is a read capability on CONTAINERS which allows us to get their status, usage and access to their labels (among other things) so we can display that information in Homepage.

Homepage installation

We are deploying Homepage using docker compose (either manually or through Dockge or Komodo). It is also available on Unraid or Kubernetes. After creating the stack, create a config directory within the stack directory (/opt/stacks/homepage if using Dockge or your installation path when using Komodo, for example /opt/komodo/stacks/homepage/config); the first run will have Homepage populate this directory with default files.
Our proposed compose.yaml uses homepage. specific labels to integrate Homepage’s Docker within our dashboard. Our file looks as follows:
services: homepage: image: ghcr.io/gethomepage/homepage:latest container_name: homepage ports: - 33009:3000 # changing the default exposed port to 33009 volumes: - ./config:/app/config # Make sure your local config directory exists - /var/run/docker.sock:/var/run/docker.sock:ro # remove if using Docker Socket Proxy, as seen in our configuration file - /tmp:/mountpoint:ro # a mountpoint to a disk that we want to monitor the available size of using the "resources" widget (in widgets.yaml) labels: - com.centurylinklabs.watchtower.enable=true # update with Watchtower - traefik.enable=true # (optional, remove if not using Traefik) This configuration follow the instructions set in the corresponding blog post - traefik.http.routers.home.entrypoints=https # HTTPs upgrade - traefik.http.routers.home.rule=Host(`home.example.com`) # here we are only providing the "main" homepage instance - homepage.group=host_dynamic # The layout uses the group to place content. We use the host_ entry to separate the tabs - homepage.name=Homepage # name of the application - homeage.icon=homepage.png # You can also use complete URLs for icons - homepage.instance.main.href=https://home.example.com/ # "main" instance behind a reverse proxy - homepage.instance.alt.href=https://home.example.net/ # "alt"-ernate instance behind a reverse proxy - homepage.description=HomePage (host) # Can be used to provide "quick launch" search content; having the host listed makes it simpler to find the right instance of a software in a multiple machine deployment
(If using Komodo, in the volumes: section, replace ./ with the full path location)
It is also possible to extend the volumes: section to use a local path for additional icons
To use a local icon, first create a Docker mount to /app/public/icons and then reference your icon as /icons/myicon.png. You will need to restart the container when adding new icons.
To use a remote icon, use the absolute URL (e.g. https://...).
 
After starting (or docker compose up -d) the stack, a few files will be added within the config folder:
The settings.yaml file allows you to define application level options. For changes made to this file to take effect, you will need to regenerate the static HTML, this can be done by clicking the refresh icon in the bottom right of the page.
Services are configured inside the services.yaml file. You can have any number of groups, and any number of services per group. […] Each service can have one service widget attached to it (often matching the service type[…]).
The widgets.yaml file will contain “Information widgets”.
Bookmarks are configured in the bookmarks.yaml file. They function much the same as Services, in how groups and lists work. They're just much simpler, smaller, and contain no extra features other than being a link out.
Docker instances are configured inside the docker.yaml file. Both IP:PORT and Socket connections are supported. [also in that section of the documentation are details about Automatic Service Discovery, Widgets and labels, showing stats per Docker container, and multiple Homepage instances support.

Proposed Homepage configuration

docker.yaml

Within our proposed docker.yaml file we are using the “Docker Socket Proxy” exposed to the LAN (in read-only mode), with a server’s IP of 192.168.22.11 (adapt as needed), naming it tab1-docker (multiple entries can be added if using multiple tabs). Commented in the file are other methods to access the docker information if homepage is running on the host where the docker services are running. This is needed for the Automatic Service Discovery of Docker services.

widgets.yaml

Our proposed widgets.yaml file can be used as the basis to a header for every page that will display the homepage’s hosting system resources details (cpu, memory, disk usage), a search box, the current time and weather.
More “Information widgets” can be configured as preferred.

settings.yaml

Our proposed settings.yaml file contains one tab definition. Adding tabs can be done by using the tab: name within the layout: section. This layout make use of tabs to separate items either per server or per purpose, at the user discretion. This tab will have four distincts sections: a tab1_metrics that will display dashdot widgets, a tab1_static section to add services (including some that do not have homepage. labels added), a tab1_apps section where the Automatic Service Discovery of Docker services is performed, and a tab1_monitors where we will display the Watchtower service widget.
This file is also set to be used as the main instance (on example.com), using 5-columns and with quicklaunch enabled to start services by simply typing its name or description.

services.yaml

Our proposed services.yaml file defines three of tab1's four sections ordered as in the layout: section of the settings.yaml file:
  • tab1_static for entries that are not accessible from Docker’s Automatic Service Discovery; either because those are not Docker container or because the service was started with no Homepage labels:. For the purpose of illustration of Homepage’s capabilities, in our example, we are using Dockge itself as discovered by the actual container name as running on the the tab1-docker server: .
  • Missing from this file are the tab1_apps . Those are automatically added from Docker’s Automatic Service Discovery for any service with the tab1_apps labels: entry (from any server defined in docker.yaml). As discussed earlier, this setup uses tabs to classify application either per server or per purpose.
  • tab1_monitors contains another service widget; here we are making use of the Watchtower service to informs us of “Scanned” or “Updated” container images.

Configuration results

Using the default configuration files we proposed (with the example.com urls), loading the Homepage url shows a functional page with no content.
notion image
 
With a few tweaks:
  • configuring the tab1-docker in docker.yaml
  • modifying the example.com to reflect our internal domain
  • uncommenting the first section from tab2's layout: in settings.yaml (done her for illustration purpose to show tab2)
  • extending the tab1_static section to manually include the Komodo stack which was used to deploy the main instance of Homepage
… homepage’s dashboard view automatically updates itself:
notion image
Where we can find the different sections of our setup:
  • the “informational widgets”, using the content from the widget.yaml
  • the settings.yaml layout: with tab1 and its four sections (in a 5-columns setup)
    • the tab1_metrics as defined in the services.yaml file
    • the tab1_static (also defined in services.yaml)
    • the tab1_apps automatically populated from any Docker services (as found on all the servers defined in the docker.yaml file) using the homepage.group=tab1_apps labels:
    • the tab1_monitors as specified in the corresponding section of the service.yaml file
  • the content of the bookmarks.yaml (which we have not altered) is present at the end of each page (or tab). This is because we have not defined its location per the layout: we defined in settings.yaml; by default un-anchored content is displayed on all pages.

Revision History

  • 20240914-0: Initial Release
  • 20240908-0: Initial Draft
Â