Self-hosted service
hywax/mafl avatar
hywax/mafl

Mafl: a YAML-configured start page where the backend makes the third-party calls

Minimalistic flexible homepage

756 stars62 forksTypeScriptMIT

At a glance

What is it?
Mafl is a self-hosted homepage builder written in TypeScript and shipped as a Docker image. Its distinguishing choice is that requests to services like IP lookup and weather run server-side, and the whole page is driven by a config.yml file rather than a database.
Who is it for?
Adopt Mafl if you already run Docker or a Proxmox LXC and want a start page whose third-party calls leave from the server rather than the browser, and you are comfortable editing /opt/mafl/data/config.yml or ./mafl/config.yml by hand. Skip it if you want a GUI-driven editor or a large catalog of ready-made widgets, because the README lists only three services: Base, IP API and OpenWeatherMap.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 101 days ago.
What is it written in?
Mainly TypeScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 15, 2026, and from our analysis. They are not legal advice.

DEEP OPEN-SOURCE ANALYSIS

The problem Mafl targets: a start page that is not a browser-side widget board

Most self-hosted start pages are a grid of links you fill in through a web form, with any live data fetched directly by your browser. Mafl takes a different position on both points. The README states that all requests to third-party services occur in the backend, which is presented under the heading Privacy. That means an IP lookup or a weather card is resolved by the Mafl server process, not by the tab you have open. If your browser sits behind a VPN, a content blocker or a corporate proxy, the value you see in the card reflects the server's network position instead of your own. For a homelab box with a stable outbound route, that is usually the behaviour you want. For a laptop that roams between networks, it is a mismatch you should notice before you file a bug.

The second position is configuration as a file. The README describes setup as a few lines of yaml, and every install path it documents ends at a config.yml. There is no mention of a database, a migration step or an admin account. The unit of work is a service card, and the README describes the Base service as the main card that the other services are built on top of. Grouping and tags exist as features, so a config can be organised into sections rather than one flat list. The audience is the person who already edits compose files and Nginx snippets and would rather keep a start page in version control next to them.

How the pieces fit: a Node server, a data directory and a card model

The repository is TypeScript, and the README's Node instructions are the clearest view of the architecture. You clone the repository, run yarn install, then yarn build, then yarn preview. The README notes that the application starts with a basic configuration located in the data folder. So the runtime is a Node server that reads its configuration from a directory on disk, and the Docker path mounts that same directory as a volume at /app/data/. The container listens on port 3000, which is the port the compose example maps.

Services are the extension point. The README lists three: Base, IP API and Weather, with Weather linked to an OpenWeatherMap page in the docs. Each is a card type you place in the config, and Base is the parent that the others derive from. That is a narrower service catalog than the feature list might suggest, and it is worth reading the docs page for each service before assuming a card you want already exists. Icons are handled separately from services: the README supports Iconify, any valid emoji, a remote URL, or a local file referenced by name. Language is a config property, lang, and the README says the app should auto-detect your language and set it in settings, with the config value as the fallback. Ten locales are listed, and the contributing guide covers adding another.

Themes are described as several ready-made options plus the ability to write your own. The README does not specify the theme file format or where custom themes live, so treat theme authoring as something to confirm against the docs site rather than the README. PWA support is listed as a feature, which means the page can be installed as an application; the README does not describe the manifest or service worker details.

Getting it running: Docker, Node and the Proxmox LXC script

The Docker path is the shortest. The README gives a compose file with image hywax/mafl, restart unless-stopped, ports 3000:3000, and a bind mount of ./mafl/ to /app/data/. The image is published to Docker Hub as hywax/mafl and to the GitHub container registry as ghcr.io/hywax/mafl, so you can pin to either registry depending on your mirror setup.

The Node path is for building from source. git clone https://github.com/hywax/mafl.git, then yarn install, then yarn build, then yarn preview. The README uses yarn but states that npm or pnpm work as well. The server reads the data folder from the working tree in this mode, so the config lives inside the checkout rather than in a separate mounted volume.

The Proxmox path is a community script. The README gives a single command to run in the Proxmox VE shell: bash -c "$(wget -qLO - https://github.com/community-scripts/ProxmoxVE/raw/main/ct/mafl.sh)". After that, you edit the config with nano /opt/mafl/data/config.yml. The README credits @tteck for the LXC script, and the script itself lives in the community-scripts/ProxmoxVE repository rather than in Mafl. That matters for maintenance: a change to the LXC template is not a Mafl release, and the two can move independently.

What the README does not give is a config schema. There is no annotated example of a service entry, no list of required keys, and no description of what happens when a key is misspelled. The docs site is the place to look, and the README links to per-service pages under mafl.hywax.space/services/ for Base, IP API and OpenWeatherMap.

Where Mafl is the wrong tool

The service catalog is the first constraint. Three card types (Base, IP API, Weather) is a small set, and the README does not describe a plugin API for writing your own. If your start page needs a card that queries Proxmox, checks whether a container is up, or reads a feed, the README gives no route to that. The proxmox topic on the repository refers to the install target, not to a Proxmox service card.

Configuration is file-only. Nothing in the README describes a web UI for editing services, and the Proxmox instructions tell you to open config.yml in nano. That is fine for one person maintaining one page, and awkward for a household where someone else wants to add a link. There is no mention of a reload endpoint either, so the README does not tell you whether editing config.yml takes effect without restarting the process. Verify that before you plan an edit workflow around it.

There is a version gap worth naming. The repository listing shows v0.15.4 tagged in July 2024, with v0.15.3 and v0.15.2 before it, while the last push to the default branch is dated 2026. The README's feature list and docs may describe behaviour that landed after the newest tag, so a container pinned to a release tag is not necessarily the same software the README describes. Nothing in the supplied material says which tag the hywax/mafl image points to by default, so pin explicitly if that distinction matters to you.

The alternative: a static generated dashboard

The closest contrast is a static homepage generator, the kind that takes a YAML or TOML file, renders a single HTML page at build time, and serves it as a plain file behind any web server. The difference is where the work happens and what runs continuously. A static generator produces an artifact you can host on a CDN or an Nginx root with no Node process. Mafl runs a server, and that server is the reason the privacy claim holds: the IP API and weather calls are made by the backend. A static page cannot do that without a proxy you write yourself, and any live data has to be fetched by the browser, which is exactly the exposure Mafl is designed to avoid.

The trade is operational surface. A static page has no port 3000, no container to restart, and no volume to back up. Mafl has all three. It also has a PWA layer and multi-language support that a hand-written static page would need to reimplement. So the choice is not about which is better in general. If your start page is a list of links with icons, a static generator is less to run and less to break. If you specifically want server-side lookups and a card model you can group and tag, Mafl is doing something the static approach does not attempt.

Licence, upgrades and what a Mafl update actually costs

Mafl is MIT licensed. That is permissive: you can use, modify and redistribute it, including in commercial settings, provided the copyright notice and licence text are kept. This is a summary of the licence identifier in the repository, not legal advice; read the LICENSE file for the actual terms.

The upgrade mechanics are the part to plan for. The Docker path means pulling a new tag and recreating the container, and the config survives because it lives in the mounted volume. The Node path means pulling the repository, re-running yarn install and yarn build, then restarting yarn preview. The Proxmox path mixes the two: the app files come from the community script's layout under /opt/mafl, and your config sits at /opt/mafl/data/config.yml. Because the LXC script is maintained outside the Mafl repository, an update to the script and an update to Mafl are separate events, and the README does not describe how the script handles an existing install.

There is no migration tooling mentioned anywhere in the README, which is consistent with a file-based config: there is nothing to migrate. The cost of an upgrade is therefore the cost of reading the CHANGELOG for renamed or removed config keys. The README links to CHANGELOG.md at the repository root, and that is the file to check before bumping a pinned tag. If you run the container without a pinned tag, you are accepting whatever the default tag resolves to at pull time, and the README does not state what that is.

Who this is for, and the checks to run before you commit

The fit is a self-hoster who already runs Docker or Proxmox, wants a start page that is one YAML file in a volume, and cares that weather and IP data are fetched by the server rather than the browser. The three-service catalog is enough if your page is mostly links and groups with one or two live cards. The multi-language list is broad, and the icon options (Iconify, emoji, URL, local file) cover most visual needs without a separate asset pipeline.

The misfit is anyone who needs a card type Mafl does not ship, anyone who wants to edit the page from a browser, and anyone who expects a release cadence matching the commit activity on the default branch. The README does not describe a plugin system, and it does not describe a config reload path, so both of those are open questions rather than settled limitations.

Before deploying, do three concrete things. Read the per-service docs pages for Base, IP API and OpenWeatherMap at mafl.hywax.space/services/, since the README gives no config schema and those pages are where the keys must live. Check CHANGELOG.md against the tag you intend to pin, because the newest release listed is v0.15.4 from July 2024 and the default branch has moved since. And decide your config's home up front: ./mafl/ mounted at /app/data/ for Docker, or /opt/mafl/data/config.yml for the Proxmox LXC, because those two paths are what the README documents and mixing them will produce a page that ignores your edits.

Editorial conclusion

Adopt Mafl if you already run Docker or a Proxmox LXC and want a start page whose third-party calls leave from the server rather than the browser, and you are comfortable editing /opt/mafl/data/config.yml or ./mafl/config.yml by hand. Skip it if you want a GUI-driven editor or a large catalog of ready-made widgets, because the README lists only three services: Base, IP API and OpenWeatherMap. Before deploying, check the CHANGELOG and the docs site for what changed after v0.15.4, since the last tagged release in the repository listing is from July 2024 while the default branch has received commits since.

Official sources

  1. hywax/mafl on GitHub
  2. License: MIT
  3. Project website
  4. README
  5. Releases
Community notes

Community notes