# homehub ships an empty password, a random session key and a theme that only applies in light mode

> A self-hosted family dashboard with fourteen feature toggles, a file share, a media downloader and a PDF compressor, aimed at a Raspberry Pi in someone's cupboard. There is no per-user account model and the maintainer says so himself: one person, working evenings. The configuration file is where the design decisions are, and several of them are quietly load bearing.

**surajverma/homehub** — A private, lightweight, no-login, self-hosted family utility for your home and it comes with no config PWA.

- Repository: https://github.com/surajverma/homehub
- Stars: 1,245 · Forks: 75
- Language: HTML
- License: MIT
- Published: 2026-09-10 · Updated: 2026-09-10 · Language: en
- Canonical page: https://hysenlabs.com/projects/surajverma-homehub

## The example config leaves the password empty and the signing key random

Two defaults in the configuration decide who can reach the application.

The first is the password field. The example sets it to an empty string with a comment saying to leave it blank for passwordless access, and the getting started text describes it as an optional password that protects the whole site. So the default state of a fresh install is a dashboard with no authentication at all, reachable from anywhere the host is reachable.

The second is the session signing key, which appears in the compose file as an environment variable with a default of empty and a comment saying it should be set in an environment file and falls back to a random value if it is not provided.

A random fallback is the right default for cryptography and the wrong default for a session key. If it changes on every start, then every restart invalidates every session, and everyone using the application is signed out whenever the container is recreated. Setting it explicitly costs one line.

The user model is worth stating plainly as well. There are no accounts. Family members are a list of names in the configuration file, used by the status and presence features, and the example list includes a country name among the names. Everyone who opens the site is the same user, and nothing in the file records who wrote a note or finished a chore.

## Fourteen feature toggles, and the feature list names a widget the toggles do not include

The customisation story is one file. Every feature has a boolean under a toggles key, and the example turns all of them on. The container run itself is one command once that file exists:

```bash
docker compose up -d
```

Counting the entries in the toggles block gives fourteen: shopping list, media downloader, PDF compressor, QR generator, notes, shared cloud, who is home, personal status, chores, recipes, expiry tracker, URL shortener, expense tracker and calendar.

Compare that with the prose list of what the application does, which names shared notes, shared cloud, shopping list, chore tracker, calendar and reminders, who is home, the expense tracker, the media downloader, a recipe book, an expiry tracker, a URL shortener, a PDF compressor, weather updates and a QR generator.

Two entries do not line up. The weather widget is in the prose and is not one of the fourteen toggles, because it has its own configuration block with its own enable flag and a good half a dozen settings. And the personal status toggle appears in the configuration with no named feature in the prose, which suggests it is the switch behind the presence feature rather than a separate one.

The instructions call out one toggle by name, saying the shared calendar can be enabled through the calendar toggle, which is consistent with all of them being on by default in the example. So the configuration is complete and the marketing list is the imprecise document.

## A custom theme applies to light mode, and dark mode uses its own values

Colour is configurable, and there is a catch that the tips section states in one line.

The application follows the system dark or light preference automatically, and there are nine colour keys to override: two accents, a background, a card background, a text colour, and four sidebar values covering the background, the text, the link text and the link border.

The catch is the last tip. Dark mode adapts automatically, and the variables listed above apply to light mode, while dark mode uses tuned counterparts chosen for contrast. So a family that spends its evenings on a dark-themed laptop will see the tuned palette rather than the one in the configuration file.

That is a defensible design decision, since a hand-picked light background on a dark desktop is usually unreadable. It is also the kind of thing that reads as a bug the first time someone customises the accent colour and nothing changes on half the devices in the house.

One of the nine values takes an alpha channel, and the tips suggest raising its opacity to increase sidebar contrast, with a concrete example. So the intended way to tune the sidebar is opacity rather than a different colour, which is worth knowing before you go looking for a border colour setting that does not exist.

## The weather widget sends the browser's location to a third party service

The headline claims are that all data stays on your network, with no cloud and no tracking. The optional weather widget is where that needs qualifying.

The widget is powered by a free weather API that is not self-hosted, it is hidden by default, and it has its own configuration block. The keys are an enable flag, an optional label, latitude, longitude, timezone, a units choice between metric and imperial with metric as the default, and a view choice between compact and detailed.

The two coordinates are described as optional, with the instruction to leave them empty to use browser geolocation. So the default configuration for someone who enables the widget and does not think about the coordinates is: the browser reports where it is, that location goes to a third party weather service, and the answer comes back to a dashboard that otherwise keeps everything local.

There is a timezone key too, with examples of city zones, and a note that if it is unset the API infers the zone from the request.

The two view modes explain how much is fetched. The compact view shows current temperature, condition, feels like, wind with direction and gusts, humidity and recent precipitation. The detailed view adds today's forecast with sunrise, sunset, ultraviolet index, rain probability and highs and lows.

Nothing here is alarming on its own. It is simply the one feature in the file that leaves the network, and it leaves it by default as far as coordinates are concerned.

## One worker, synchronous, which a download will sit on

The container's command line is the whole deployment story in one line: a WSGI server, one worker, the synchronous worker class, bound to all interfaces on port 5000, with access and error logs both written to standard output.

One worker is a reasonable choice for a household application and a meaningful constraint. With a single synchronous worker, one request is processed at a time. The features list includes a media downloader that saves video and music from other sites, and that request does not return until the download finishes. So the dashboard and every other feature wait behind a download on the same worker.

The two packages in the runtime image that exist for those two features are visible in the build file. A multimedia framework is installed for media handling, and a PostScript and PDF tool is installed for the PDF compressor. Neither is a Python library you would import; both are command line programs the application shells out to.

Writing the logs to standard output is the other detail worth noting, and it is the right choice: it means the container's log driver captures everything without a volume or a log file to rotate.

## The image copies the builder's whole bin directory into a lean runtime

The build is in two stages on the same Alpine based Python image, and the split is about build tools rather than about the application.

The builder stage installs a compiler toolchain, compression and image library headers, and Node with its package manager. It installs the Python requirements, then installs the Node dependencies and runs the stylesheet build, which compiles the utility CSS framework from a single input file into a minified output file. Templates are copied in before that build because the utility class names are read from them.

The runtime stage installs the four runtime packages, copies the installed Python site packages and the entire local binary directory from the builder, copies the application, and copies the built stylesheet back across.

Copying the whole binary directory rather than naming the executables you need is a broad copy. It brings across the application server and anything else installed in that location in the builder, which is simpler to write and larger than it needs to be.

One build detail is neat. A build argument for the application version defaults to the word dev, it is injected by the build pipeline, and it becomes an environment variable used as the service worker cache version. So the pipeline is what busts the browser cache. Locally, where nothing is injected, the cache version never changes.

## Every requirement is unpinned, and the test runner ships in the image

The dependency file is thirteen lines long and every line is a bare package name with no version constraint.

That is a choice with a specific consequence for this kind of project. The stated target is a small computer such as a single board computer running unattended on a home network, updated by pulling a new image. The image itself is pinned by tag, but every time that image is rebuilt, the Python packages inside it resolve to whatever is newest that day. Two installations of the same tag, built weeks apart, can contain different libraries.

The list itself is worth reading for what it reveals. Two database and form libraries, the YAML parser, the password and form-validation helpers, a QR code generator, the media downloader tool, an image library, the WSGI server, an HTML sanitiser, the HTTP client, and the test runner.

The sanitiser is the one to notice for the notes feature: shared notes in a family app are one of the places where HTML from one member is rendered for another, and having a sanitiser in the dependency list is a sign that was thought about.

The test runner is the odd entry. It sits in the same list as the runtime packages rather than in a development list, so it is installed into the image that runs the household. The repository does have a tests directory, so the tests exist; shipping the runner is a cost choice, not a testing one.

## Three version numbers that do not agree, and a config example that stops mid-comment

There are three version numbers in play and no single one is authoritative.

The JavaScript manifest in the repository root says 1.0.0. The published releases are at 0.2.4, and before that 0.2.3.4 and 0.2.3.3, which shows a fourth segment appearing during the 0.2 line. The compose file pulls the image by its latest tag. So a manifest that says 1.0.0 sits beside a release line that is still in the 0.2 series, and the deployment takes whatever latest currently points at.

The manifest also has a description that is narrower than the application: collaborative task and reminder management, where the feature list is fourteen items including a downloader and a compressor. Its only real jobs are the two stylesheet commands, since this is a Python application that borrows Node to build its CSS.

The configuration example stops partway through. The family member list is followed by the reminders block, whose first comment explains that a key controls how reminder times are displayed, and that comment ends mid-word in the middle of describing the allowed values. So the one thing a first time installer is most likely to need guidance on, the reminder settings, is the part you cannot read.

Two smaller operational notes. The configuration file is mounted into the container read only, so a change to colours, toggles or the password needs a container restart to take effect. And the maintainer note at the top of the file is unusually candid: one person, a full time job, evenings and weekends, and expectations of slow responses. The last commit is dated 9 August 2026.

## Conclusion

homehub fits a household that wants a shared list, a shared calendar and a downloader on hardware it already owns, and it does not fit a household that needs accounts, permissions or an audit trail. Three things to set before anyone uses it. Put something in the password field, because the example ships it empty and that field is the only thing between your family network and the notes. Put something in the session signing key, because the default is a fresh random value on each start, which means every restart signs everyone out. And decide whether the weather widget stays off, because with the coordinates left blank it uses the browser's location to call a third party service.

## FAQ

### How do I run homehub?

Copy the example configuration to your own file, set the instance name, add the family members and optionally a password, then use the provided compose file. The compose run command brings the container up detached, the image is pulled from the GitHub container registry by its latest tag, the app listens on port 5000, and you open that address in a browser.

### Does homehub need a login?

Not by default. The example configuration sets the password to an empty string with a comment saying to leave it blank for passwordless access. Setting it protects the whole site, and there are no individual accounts; family members are a list of names used by the presence features, so everyone is the same user.

### What does homehub store on disk?

Four host directories are mounted into the container, for uploads, downloaded media, compressed PDFs and the application data directory, plus the configuration file which is mounted read only. That makes backup a matter of copying four directories, and losing the data directory means losing the database.

### Can homehub download video and music?

There is a media downloader that saves videos or music from other sites to your server. The download tool and an image library are two of the Python requirements, and the container image installs a multimedia framework at runtime, which is what the downloader and the media handling depend on.

### How do I change the colours in homehub?

Through nine keys under the theme section of the configuration file: two accent colours, background, card background, text, and four sidebar colours including a link border that takes an alpha value, where the tips suggest raising its opacity for contrast. The file is mounted read only, so a change needs a restart, and the listed values apply to light mode while dark mode uses its own tuned values.

## Sources

- [Issues](https://github.com/surajverma/homehub/issues)
- [License: MIT](https://github.com/surajverma/homehub/blob/main/LICENSE)
- [README](https://github.com/surajverma/homehub/blob/main/README.md)
- [Releases](https://github.com/surajverma/homehub/releases)
- [surajverma/homehub on GitHub](https://github.com/surajverma/homehub)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/surajverma-homehub
