Skip to content

MDAPI Homelab

A self-hosted, production-grade Kubernetes homelab running on bare metal — built around GitOps, zero-trust secrets, and modern DevSecOps practices.

What is this?

This site documents the architecture of MDAPI (Martino Dell'Ambrogio's Personal Infrastructure), a personal homelab that runs a full-stack cloud-native environment at home. It is intended as a reference for architecture decisions, security practices, and operational patterns — not a tutorial, but a real-world example of how these technologies fit together.

For the longer story of how MDAPI started on an ISDN line in the 1990s and arrived at its current shape, see About MDAPI.

The stack is built to mirror enterprise-grade principles: declarative GitOps configuration, hardware-backed secret management, automated certificate lifecycle, container image CVE scanning, and a multi-cluster management plane.

Stack at a Glance

Layer Technology
Kubernetes distribution Harvester HCI (RKE2 + KubeVirt)
Cluster management Rancher
GitOps Fleet (multi-cluster)
Ingress ingress-nginx + ModSecurity WAF
TLS cert-manager + Let's Encrypt (DNS-01 via RFC 2136)
Storage Longhorn (block on FusionIO, 2-replica) + Ceph (in-cluster bulk via Rook) + Garage (S3) + TrueNAS (NFS/iSCSI via democratic-csi)
Secrets Akeyless with customer fragment on CipherTrust Manager
Identity Keycloak (OIDC/SSO) + OpenLDAP
Image updates Keel (digest-based polling)
CI/CD GitLab (self-hosted EE) with Grype+Syft CVE scanning
Observability VictoriaMetrics (long-term metrics) + Prometheus / Alertmanager + Grafana · Cribl + OpenObserve on Ceph RGW (indexed logs)
Automation Windmill (scheduled infrastructure health monitoring)
Edge router BPI-R4 running OpenWrt 25.12 (custom fork)
External access sslh (protocol demux: HTTPS / SSH / OpenVPN on a single port)

Architecture at a Glance

Five tiers, separated by responsibility. The edge terminates external traffic; the cluster runs every workload; storage and secrets are addressed as distinct planes rather than per-service concerns. Each subsequent page in this site drills into one slice of the diagram.

flowchart TB
    subgraph ext["External"]
        clients["Clients<br/>web · mobile"]
        offsite["Off-site backup<br/>Backblaze B2 + SFTP"]
    end

    subgraph edge["Edge — BPI-R4 (custom OpenWrt fork)"]
        sslh["sslh<br/>HTTPS · SSH · OpenVPN<br/>demuxed on :443"]
    end

    subgraph k8s["Harvester HCI — RKE2 + KubeVirt — qui · quo · qua"]
        plat["Platform<br/>Rancher · Fleet · cert-manager<br/>ESO · Keel · Reloader"]
        ingress["Ingress + WAF<br/>ingress-nginx + ModSecurity"]
        apps["Applications<br/>GitLab · OwnCloud · Paperless · Keycloak<br/>Home Assistant · Plex · Joplin · …"]
        obs["Observability<br/>Prometheus + Alertmanager<br/>Cribl + OpenObserve"]
    end

    subgraph storage["Storage"]
        longhorn["Longhorn<br/>in-cluster block on FusionIO"]
        ceph["Ceph (Rook)<br/>in-cluster bulk · RWX + S3"]
        garage["Garage S3<br/>3-node external"]
        truenas["TrueNAS<br/>salt + pepper"]
    end

    subgraph sec["Secret store"]
        akeyless["Akeyless SaaS<br/>+ CipherTrust customer fragment<br/>(on-premise)"]
    end

    clients --> sslh --> ingress --> apps
    plat -.->|"declarative"| apps
    plat -.->|"declarative"| ingress
    apps --> longhorn
    apps --> ceph
    apps --> garage
    garage --- truenas
    longhorn -->|"backup"| garage
    garage -->|"daily rclone"| offsite
    apps -.->|"ExternalSecret"| akeyless
    obs -.->|"observe"| apps

Solid arrows are request and data flow; dashed arrows are the management and observability planes (declarative reconcile, secret fetch, metric and log scrape).

Cluster Contexts

Three Kubernetes clusters, all managed through Rancher and Fleet:

Cluster Location Purpose
mdapi-rancher Local (Rancher management) Fleet controller, cluster-scoped resources
mdapi-prod Bare metal (homelab) All production workloads
mdapi-test Rackspace Spot Ephemeral staging environment

Design Principles

Everything is declarative. All cluster state lives in the mdapi/fleet GitLab repo at https://gitlab.mdapi.ch/mdapi/fleet (public mirror). No kubectl apply is ever run directly — every change is a git commit.

Secrets never touch git. Secrets are stored in Akeyless SaaS with an on-premise customer fragment (the plaintext never leaves the local network). Kubernetes workloads fetch them via the External Secrets Operator at runtime.

TLS everywhere, automated. cert-manager issues certificates via Let's Encrypt — DNS-01 (RFC 2136 against a self-hosted BIND9 authoritative nameserver with TSIG) for the public domains, and HTTP-01 for names under the internal-only home.tillo.ch zone.

Security is layered. ModSecurity WAF on all ingresses, OIDC for user-facing apps, CVE scanning in every CI pipeline, network-level protocol demultiplexing at the edge.

Source

  • Fleet GitOps repo: https://gitlab.mdapi.ch/mdapi/fleet (public mirror)
  • This documentation: docs.mdapi.ch · source at https://gitlab.mdapi.ch/mdapi/docs