# Mistborn

> Case study: building Mistborn, an open-source private-cloud platform, solo across four years, 25 releases, and coverage in Linux Pro Magazine.

- Source: https://stevenfoerster.com/projects/mistborn/

Case study · Open source

A self-hosted private-cloud platform that made WireGuard VPN, network-wide DNS filtering, and a panel of collaboration services deployable by one person on commodity hardware.

- Solo founder-engineer: product, architecture, code, releases, docs, support
- 2020 - 2024
- Archived on GitLab after the v2.4 series; lessons carried into later platform work

Years maintained

4+

First commit March 2020, final release work December 2024

Tagged releases

25

v0.1 through v2.4.x across the two core repositories

Commits

800+

Effectively solo, across platform and container repos

Optional services

11+

Nextcloud, Jitsi, Vaultwarden, Home Assistant, Wazuh SIEM, and more

- WireGuard
- iptables
- Django
- PostgreSQL
- Redis
- Celery
- Traefik
- Pi-hole
- Docker

- [View source on GitLab](https://gitlab.com/cyber5k/mistborn)
- [Press coverage](https://stevenfoerster.com/projects/mistborn/#press)

## The problem

In 2020, secure private infrastructure had two price tags: an enterprise budget, or weeks of glue work. A team that wanted a VPN, network-wide ad and malware blocking, verified DNS, TLS, a reverse proxy, and a handful of self-hosted services had to assemble and harden each piece by hand, then keep that stack alive through upgrades.

Mistborn started from a concrete version of that problem: I wanted my family's devices protected on any network, and my own services reachable without exposing them to the internet. It generalized into a platform for small teams who wanted sole ownership of their data without hiring an infrastructure team. One install command, secure defaults, and every service off until you turn it on.

## My role

I was the founding (and effectively only) engineer for the project's whole life: more than 800 commits across the platform and container repositories, 25 tagged releases, and every support thread in between. When the product needed a feature, I scoped it; when a kernel module broke on Raspberry Pi, I debugged it; when users got stuck, the docs and the installer were mine to fix.

- Product scoping
- Architecture
- Django / Python backend
- Network & firewall engineering
- Docker packaging
- Multi-arch release engineering
- Documentation
- User support

## What I built

A Django control plane (PostgreSQL, Redis, Celery) orchestrating a WireGuard data plane. Pi-hole and DNSCrypt handle filtered, cryptographically verified DNS; Traefik fronts every web interface; iptables wraps the host so WireGuard is the only way in. Platform access is passwordless by design: a device's WireGuard key is its credential, with TOTP as an optional second factor, so there is no password to phish, reuse, or stuff. Everything runs in Docker with images published for amd64, arm64, and arm/v7, so the same platform fits a 2 GB VPS, a Raspberry Pi, or a 16 GB server running the optional Wazuh SIEM.

On top of that core, a service panel enables optional self-hosted apps (Nextcloud, Jitsi, Vaultwarden, Home Assistant, Rocket.Chat, Jellyfin, and more), each off by default, each isolated in its own container with its own systemd unit. Later versions added group-based access control, an OAuth2 single sign-on provider, a WebSocket status dashboard, and translations into eleven languages.

flowchart LR
  C\["Client devices"\] -->|"WireGuard tunnels"| WG\["WireGuard"\]
  WG --> DNS\["Pi-hole + DNSCrypt"\]
  WG --> TR\["Traefik reverse proxy"\]
  TR --> DJ\["Django control plane"\]
  DJ --> PG\[("PostgreSQL")\]
  DJ --> RD\[("Redis")\]
  DJ --> CW\["Celery workers"\]
  CW -->|"iptables + ipsets"| FW\["Host firewall"\]
  TR --> SVC\["Optional services: Nextcloud, Jitsi, Vaultwarden, Wazuh..."\]

## Hard decisions

Four calls that shaped the platform, with what they cost. Each one is unpacked further in the deep dives below.

Decision 01

### One WireGuard server instance per client

- Context: Per-user policy (MFA, kill switches, isolation) needs an enforcement point per device. A single shared interface makes per-client firewall targeting messy.
- Decision: A one-to-one mapping between each client and a server-side WireGuard instance on its own random UDP port, with PostUp and PostDown directives writing that client’s routes and iptables rules.
- Trade-off: Interface and port sprawl, and putting the server behind a port-forwarding router meant forwarding a moving target.
- Outcome: Clean per-device control, including a client-to-client toggle and per-profile rules. Once the policy model matured, the v2.1 rewrite consolidated new clients onto one shared listening port, making router setups trivial.

Decision 02

### Owning iptables directly alongside Docker

- Context: Docker publishes ports through PREROUTING NAT rules that bypass an INPUT DROP policy, so containers can answer the internet even on a host that looks locked down. UFW never sees it.
- Decision: Manipulate netfilter chains directly: disable UFW, persist a minimal deny-by-default ruleset with iptables-persistent, and add an explicit blocking rule for every container port Mistborn exposes.
- Trade-off: Owning raw iptables is a sharp tool. Every Docker upgrade was a potential rule-interaction bug, and I gave up the comfort of a friendly firewall frontend.
- Outcome: A power cycle always lands in a working, secure state, and a dedicated logging chain feeds a Metrics page so users can watch dropped probes instead of trusting me.

Decision 03

### MFA enforced at the network layer

- Context: The threat model included a stolen laptop carrying a valid WireGuard key. An application login screen alone leaves the tunnel, the internet path, and every service exposed.
- Decision: For MFA profiles, block internet and service access in iptables and Traefik until a TOTP check completes. Traefik validates server-side sessions per tunnel IP, and Celery periodic tasks expire sessions and clean up rules.
- Trade-off: Authentication state spans the kernel firewall, the reverse proxy, and a task queue. More moving parts, more support surface.
- Outcome: A valid WireGuard key without the second factor gets an attacker nothing: no internet egress, no services, just an HTTP 403. Signing out re-blocks access immediately.

Decision 04

### Unattended PostgreSQL major-version upgrades

- Context: Users self-host on machines I cannot reach, and the update script is the only delivery channel. PostgreSQL data directories do not survive major-version jumps.
- Decision: A dump-and-restore pipeline: back up to a compressed SQL dump, have the database container’s entrypoint read the dump’s source version, and restore into a fresh PostgreSQL 16 volume when it predates the running major. Any failure halts the process, with manual CLI escape hatches.
- Trade-off: Dump and restore is slower than pg_upgrade and needs disk headroom, but it is deterministic, verifiable, and backup-first by construction.
- Outcome: The v2.4.0 release moved live installs from PostgreSQL 11 to 16 (and Python 3.8 to 3.12) without me touching a single user machine.

## Outcomes

-   Longevity: 25 tagged releases from v0.1 in March 2020 through the v2.4 series, with active maintenance into December 2024 and a ground-up v2 rewrite based on what v1 taught me.
-   Independent coverage: featured by Linux Pro Magazine in print, video reviews from Awesome Open Source and DB Tech, and a 2024 Zero Trust writeup and founder interview from Webnestify, all bringing the project to builders I never would have reached alone.
-   Community-hardened reliability: bug reports from real homelab and VPS environments drove installer hardening, and demand pushed multi-arch image builds, including a Rust toolchain for 32-bit ARM.
-   Features users asked for, shipped: firewall penetration (WireGuard over UDP/53 and UDP/443 for restrictive networks) landed in v2.3 directly from user environments I could not have predicted.

## What went wrong, and the lessons I carry forward

### Installer fragility

Early installer logic assumed cleaner host environments than reality. Real users exposed all the edge cases quickly.

### Too many knobs too early

I added flexibility before I had strong defaults, which made onboarding harder than it needed to be.

### Docs lagged architecture

The system changed faster than the docs. That mismatch created avoidable support overhead.

What I do differently now

-   Treat docs and upgrade paths as first-class features from the beginning.
-   Constrain configuration surfaces until real usage patterns stabilize.
-   Design for failure visibility before feature expansion.

## Where it lives now

The codebase is open source on [GitLab](https://gitlab.com/cyber5k/mistborn) and is no longer under active development. Its lessons about repeatable deployment, network-layer policy, upgrades, and operator support carried into later platform work, including GovCon Enclave.

Go deeper

## The engineering war stories

### [Multi-tenant WireGuard: one VPN server per client, orchestrated with iptables](https://stevenfoerster.com/notes/wireguard-multi-tenancy-with-iptables/)

How per-client WireGuard instances, generated PostUp/PostDown rules, and Docker-aware firewall chains delivered per-device policy.

Read the deep dive

## What users said

Anonymized excerpts from unsolicited email sent by people running Mistborn.

> “Just wanted to reach out and tell you what a fantastic project Mistborn is. I have been telling everyone I can about it. It was the one I was looking for to tell my clients about for security at home.”

CEO of a cybersecurity services firm · 2024

> “I set both up to compare them. Yours, hands down, with the foundation of popular apps built in. I am hooked.”

A homelab enthusiast comparing VPN platforms · 2020

> “You changed my point of view. I finally got Mistborn working for me, my family, and a handful of true friends, and I am not afraid of the command line anymore.”

A self-hosting newcomer · 2021

> “Thank you for building such a powerful system, and thank you even more for publishing it free and open source.”

A user on a heavily censored network · 2021

## Commercial inquiries

Mistborn also drew unprompted inquiries about licensing, reselling, white-labeling, and sponsorship, from users in several countries. Anonymized excerpts:

-   “I am reaching out to inquire about reselling Mistborn, unlocking the professional features along with branding options. I would like to incorporate it into my portfolio and explore the terms for becoming a partner, including my company logo.”

    An IT reseller · 2024

-   “I read on your page that there is a reselling option. Would you mind explaining how it works? Compliments for your super useful creation.”

    A private user · 2024

-   “There are some features I would love to see added, and I would love to be a sponsor of the project. I will be subscribing to your top tier. Could we set up a call to talk through future ideas?”

    A supporter · 2021

-   “I think you, and Mistborn, can be an important part of our team and project going forward.”

    CEO of a cloud-alternative services company · 2023


## Press & Independent Coverage

Mistborn was featured by Linux Pro Magazine, Awesome Open Source, DB Tech, and Webnestify.

> “Mistborn is the rare open-source project that takes security seriously at the architecture level instead of bolting it on. For the right workload it does in one install what would otherwise be a month of glue work.”

Simon Gajdosik, Webnestify · May 2024

-   [Linux Pro Magazine](https://www.linuxpromagazine.com/Issues/2020/240/Mistborn) (Nov 2020)
-   [Awesome Open Source](https://www.youtube.com/watch?v=hekP0_crotw) (Jul 2020)
-   [DB Tech](https://www.youtube.com/watch?v=UE_OuAOgoZI) (May 2021)
-   [Webnestify](https://webnestify.cloud/insights/cybersecurity-hardening/mistborn-zero-trust-vpn-suite/) (May 2024)

- [Linux Pro Magazine (Nov 2020)](https://www.linuxpromagazine.com/Issues/2020/240/Mistborn)
- [Awesome Open Source (Jul 2020)](https://www.youtube.com/watch?v=hekP0_crotw)
- [Webnestify (May 2024)](https://webnestify.cloud/insights/cybersecurity-hardening/mistborn-zero-trust-vpn-suite/)

## Building something from zero?

Mistborn is what I do with a hard problem and an empty repo: scope the product, design the architecture, ship it, support the people who run it, and stay honest about what went wrong. If you are working out what to look for in a founding engineer, I am glad to share what the job actually demands and how to recognize someone who can carry it.

- [Get in touch](https://stevenfoerster.com/contact/)
- [More about me](https://stevenfoerster.com/about/)
