Skip to content
← All articles
Project introduction

DasherControl: a homelab dashboard built around workspaces

Listen to the audio story

DasherControl: taming the homelab tabs · 1:56 · AI-written script, synthetic voices

Transcript

Ava: Too many browser tabs, one for every service in your homelab. Antoine got tired of exactly that.

Andrew: I know that pain. Twelve tabs, and you still can't find the right one.

Ava: So he started DasherControl. The idea is a workspace of applets: bookmarks and embedded apps arranged on a dashboard, with a few Docker controls close by.

Andrew: What's under the hood?

Ava: A Vue frontend, and on the backend Rust with Rocket and Diesel. The interesting part is that the dashboard has two separate paths. Saving a layout goes through workspace handlers and database records. Restarting a container goes through an adapter called Shiplift to Docker.

Andrew: So the database doesn't touch Docker at all.

Ava: Right, and an applet isn't a running container either. Keeping those paths apart helps explain both permissions and failure states.

Andrew: Speaking of permissions, who owns a workspace?

Ava: A user does. The list handler reads the tenant identifier from a token, and the handler that returns applets checks the workspace's tenant first. But Antoine is honest that the file also has older create and delete paths with different checks. So you'd review authorization on every operation before using it as a shared service.

Andrew: So it's an experiment, not a security-reviewed product.

Ava: Exactly. And there's a UI gotcha too. The Docker list helpers return an empty list after an error, so an empty dashboard could mean nothing is running, or that Docker couldn't be reached. In a new version he'd make those two states look different.

Andrew: Any trouble with embedding apps?

Ava: Yes. The README records iframe login failures, because some apps restrict embedding. A dashboard like this needs an external link as a fallback.

Andrew: It's also an older project, so the screenshot and demo GIF show the interface as it was, not compatibility with current dependencies.

Ava: The full write-up has the diagram and links to the source.

DasherControl dashboard screenshot from the project repository
Table of contents

I started DasherControl because my homelab services kept spreading across browser tabs. The idea was a workspace of applets: bookmarks and embedded applications arranged in a dashboard, with a few Docker controls nearby.

1. Two paths behind the same dashboard

flowchart LR
  Dashboard["Dashboard"] --> Workspace["Save workspace"]
  Workspace --> Database[("Workspace records")]
  Dashboard --> Action["Container action"]
  Action --> Docker["Docker via Shiplift"]

Saving a layout goes through workspace handlers and database records. Restarting a container goes through the Shiplift adapter to Docker. PostgreSQL does not execute the Docker action, and an applet is not itself a running container. Keeping those paths separate helps explain both permissions and failure states.

Follow the handlers and Docker boundary in the architecture note.

2. A workspace has an owner

The frontend uses Vue, while the backend uses Rust, Rocket and Diesel. In src/workspaces/handler.rs[1], the list handler reads the tenant identifier from a token. The handler that returns applets checks the workspace’s tenant before returning its contents.

The create-with-applets route also derives the tenant identifier from the token. That is the intended ownership model: a saved layout belongs to a user, and applets belong to a workspace.

The file contains older create and delete paths with different checks. Their presence is a reason to inspect authorization across every operation before using this as a shared service. This article describes an experiment, not a security review of a deployed system.

3. Docker is a separate boundary

src/containers/docker.rs[2] wraps Shiplift calls for listing containers and images, pulling images, creating containers, and stopping or restarting them. This separates the dashboard’s workspace model from Docker operations.

It also exposes a UI problem: the list helpers return an empty vector after a Docker error. An empty dashboard could therefore mean either “nothing is running” or “the service could not be reached.” I would make those states visibly different in a new version.

4. What the browser can embed

The README records iframe login failures. Applications can restrict embedding, and authentication inside a frame may behave differently from an ordinary tab. A dashboard needs an external link for those services even when an iframe works for others.

This is an older project. The repository’s screenshot and optional GIF preserve the interface as it was; they do not demonstrate compatibility with current dependencies.

Play the original demo GIFOriginal DasherControl recording showing workspace and applet interactions

Browse the source and original README[3]. Both illustrations come from its images directory.

References

  1. antoinebou12. (). src/workspaces/handler.rs. [Source file or documentation] github.com.
  2. antoinebou12. (). src/containers/docker.rs. [Source file or documentation] github.com.
  3. antoinebou12. (). DasherControl. [Software repository] github.com.

References use this article’s publication date.