Zurück zum Blog

Wir haben eine Firma gegründet, die nichts verkauft

Wir haben eine Firma gegründet, die nichts verkauft

Datum 10. August 2026
Kategorie Development
Lesezeit 7 Minuten

Das Produkt ist eine Platte mit einem Loch

Wer im Sommer eine mobile Klimaanlage betreibt, kennt das Problem: Der Abluftschlauch muss irgendwie nach draußen. Die übliche Lösung ist ein Handtuch im Fensterspalt. Die unübliche Lösung ist eine Acrylplatte mit einem Loch darin.

Daraus lässt sich ein Startup machen — jedenfalls auf dem Papier. Also entstand an einem Nachmittag eine vollständige Unternehmenswebsite: Produktkonfigurator, Abo-Modelle, Investor Relations, Karriereseite, Statusseite mit Verfügbarkeitszusage. Alles in der Tonalität, die man von überfinanzierten Tech-Unternehmen kennt. Das Produkt bleibt dabei durchgehend ein Loch.

Der Witz funktioniert nur, wenn die Form vollkommen ernst bleibt. Sobald die Seite zwinkert, ist sie nur noch albern. Deadpan heißt: Die Feature-Matrix ist echte Feature-Matrix-Handwerkskunst — sie listet nur zufällig „Durchlass vorhanden" als Merkmal, das erst im mittleren Tarif verfügbar wird.

Satire ist ein Anforderungskatalog

Interessanterweise verlangt eine Parodie dieselbe Sorgfalt wie das Original. Die Statusseite musste echte Postmortems haben, sonst wirkt sie nicht. Also gibt es sie — mit Ursachenanalyse, Dauer und abgeleiteter Konsequenz:

Störung vom 14.06. — Totalausfall der Kühlleistung, 4 h 12 min

Root Cause: Kunde hat das Fenster geschlossen.
Konsequenz: Der Fenstergriff wird künftig ab Werk verplombt.

Der Punkt daran: Genau so klingen echte Postmortems, wenn die Ursachenanalyse beim erstbesten Symptom stehen bleibt und die Konsequenz dann das Symptom bekämpft statt der Ursache. Die Satire schreibt sich hier von selbst, weil das Muster real ist. Wer beim Lesen kurz zusammenzuckt, hat vermutlich schon einmal ein solches Postmortem geschrieben.

Zweites Beispiel, ebenfalls aus dem Leben gegriffen: Eine Störung wird als „externer Faktor" eingestuft und aus der Verfügbarkeitsberechnung herausgerechnet. Die 99,997 % bleiben unberührt. Kennt man.

Die Falle: nginx vererbt Security-Header nicht

Jetzt zum Teil, der auch außerhalb von Satireprojekten nützlich ist.

Die Seite läuft als statisches nginx-Image hinter einem Reverse Proxy. Die Security-Header waren im server-Block definiert: Content-Security-Policy, X-Content-Type-Options, Referrer-Policy, Permissions-Policy. Sah gut aus. Beim Test vor dem Livegang kam dann das hier zurück:

Cache-Control: no-cache, no-store, must-revalidate

Mehr nicht. Keine CSP. Kein nosniff. Nichts.

Die Ursache: add_header wird in nginx nicht in einen location-Block vererbt, sobald dort selbst ein add_header steht. Die Header werden nicht zusammengeführt — die inneren ersetzen die äußeren vollständig.

Und weil jede Location ihr eigenes Caching-Verhalten setzte, hatte auch jede ein eigenes add_header Cache-Control .... Damit waren in jeder einzelnen Location sämtliche Security-Header still verschwunden. Die Konfiguration war syntaktisch fehlerfrei, nginx -t war zufrieden, die Seite lieferte brav aus. Nur eben ohne Schutz.

Die Lösung ist unspektakulär: Header in eine eigene Datei auslagern und in jede Location per include einbinden.

# snippets/security-headers.conf
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Content-Security-Policy "default-src 'self'; ..." always;

# In JEDER location wiederholen:
location / {
    include /etc/nginx/snippets/security-headers.conf;
    add_header Cache-Control "no-cache, no-store, must-revalidate" always;
}

Die eigentliche Lehre steckt aber nicht in der Lösung, sondern im Ablauf: Der Fehler fiel nur auf, weil vor dem Livegang tatsächlich gemessen wurde, was der Server ausliefert — statt zu prüfen, was in der Konfigurationsdatei steht. Ein Blick in die Config hätte den Fehler nie gezeigt. Die Config war ja korrekt. Sie war nur wirkungslos.

Merksatz: Eine Einstellung gilt erst dann als vorhanden, wenn sie in der Antwort des Servers messbar ist.
curl -sI https://ihre-domain.example | grep -i 'content-security\|x-content-type\|referrer'

Warum keine CDNs

Die Seite nutzt ein CSS-Framework, ein Icon-Set und zwei Schriftarten. Der Standardweg wären drei CDN-Einbindungen, fertig in dreißig Sekunden. Stattdessen liegen alle Dateien lokal im Image. Das kostet einmalig Aufwand und bringt vier Dinge:

  • Datenschutz. Jede CDN-Einbindung schickt die IP-Adresse jedes Besuchers an einen Drittanbieter — noch bevor irgendein Cookie-Banner erscheint. Bei einer öffentlichen Seite ist das kein Detail.
  • Verfügbarkeit. Die Seite funktioniert auch dann, wenn ein CDN gerade Störung hat. Fremde Verfügbarkeit ist nicht die eigene.
  • Eine strengere CSP. Ohne externe Quellen kann die Policy bei default-src 'self' bleiben. Jede zusätzlich erlaubte Herkunft ist eine Ausnahme, die man später nur schwer wieder los wird.
  • Reproduzierbarkeit. Das Image enthält alles. Der Build von heute ergibt in zwei Jahren dieselbe Seite.

Der Preis: Aktualisierungen muss man selbst nachziehen. Für eine statische Seite ist das ein guter Tausch.

Der Stack, der nichts anfassen darf

Die Vorgabe an dieses Projekt war klar: Ein Spaßprojekt darf unter keinen Umständen den ernsthaften Rest der Infrastruktur gefährden. Das ergab vier Entscheidungen:

Entscheidung Begründung
Eigener Compose-Stack in eigenem Verzeichnis Keine gemeinsam genutzte Datei, die man beim Bearbeiten beschädigen kann
Kein veröffentlichter Host-Port Der Reverse Proxy erreicht den Container über das gemeinsame Netzwerk. Ohne Port-Veröffentlichung entstehen keine neuen Firewall-Regeln — und damit kein Risiko, bestehende Regelreihenfolgen durcheinanderzubringen
Feste Speicherobergrenze Ein Container mit Fehlverhalten kann den Host nicht leerlaufen lassen
Kein automatisches Update Bei einer öffentlich erreichbaren Seite wird bewusst manuell aktualisiert, nach Benachrichtigung über ein neues Basis-Image

Dazu kam eine Baseline: Vor dem Deployment wurden die kritischen Invarianten der Umgebung gemessen — Reihenfolge der Firewall-Regeln, Weiterleitung des HTTPS-Verkehrs, Zustand aller Container. Nach dem Deployment dasselbe noch einmal. Beide Male identisch.

Das klingt nach Overhead für eine Witzseite. Es dauert aber zwei Minuten und beantwortet im Zweifelsfall die einzig wichtige Frage: War ich das?

Fazit

Das Projekt hat ungefähr einen Nachmittag gedauert und drei Dinge geliefert: eine Seite, die Leute zum Lachen bringt, eine nginx-Lektion, die ab jetzt in der Betriebsdokumentation steht, und die Bestätigung, dass sauberes Vorgehen auch bei Unsinnsprojekten praktisch keine Zeit kostet.

Die Seite selbst finden Sie unter lochimfenster.matzka.cloud. Der Konfigurator beherrscht Hexagon-Durchlässe. Die Nierenform gilt als ergonomisch.

Rechtlicher Hinweis: Es werden keine echten Fenster beschädigt. Das Widerrufsrecht erlischt allerdings, sobald das Loch gestanzt wurde — dies ist naturgemäß der Fall.