Write down the network boundary, the subdomain, and two decided follow-ups

The route pull stays inside the tunnel. The operator's criterion was not
availability but "publicly reachable, yes or no" — and an endpoint that survives
a tunnel outage must by definition be reachable outside it. So nothing new opens
from outside, on the host or here.

The subdomain becomes the customer's choice at checkout, with suggestions from
their own name and a sentence saying the address is permanently public: every
Let's Encrypt certificate lands in the Certificate Transparency logs, which are
public, searchable and never deleted.

Also recorded, both decided and both getting their own spec: resetting a
Nextcloud to factory state with a 14-day safety backup, and an outage mail to
the operator after two consecutive failed checks — measured today that neither
an incident nor a mail exists, so a customer VM can fail unnoticed.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
feature/host-bootstrap
nexxo 2026-07-30 19:05:23 +02:00
parent c0cd367a0e
commit 32016d9b80
1 changed files with 123 additions and 1 deletions

View File

@ -236,6 +236,83 @@ statische Konfiguration, die das Skript schreibt.
---
## 8a. Das Netzbild, ausdrücklich
Vom Betreiber festgelegt, und der Grund für mehrere Entscheidungen oben.
| Auf dem Host | |
|---|---|
| **80/443** | öffentlich. Die Kunden-Clouds müssen erreichbar sein. |
| **22 (SSH)** | **nur im Tunnel.** Aus dem Netz nicht sichtbar. |
| **8006 (Proxmox)** | **nur im Tunnel.** Aus dem Netz nicht sichtbar. |
| alles übrige | zu |
| Bei CluPilot | |
|---|---|
| öffentlich | **nur, was heute schon offen ist** — Website und Portal |
| `register`, `progress`, `routes` | ausschließlich aus dem WireGuard-Subnetz |
**Es entsteht kein einziger neuer Weg von außen.** Das ist die härteste Bedingung
dieser Spec, und §11 Test 1 hält sie fest.
Der Preis, bewusst getragen: fällt die Steuerungs-VM aus, holt kein Host seine
Routentabelle. Die Kunden merken davon nichts — Traefik beantwortet Anfragen aus
seiner lokalen Tabelle weiter. Verzögert wird nur eine **Änderung** (eine frisch
nachgewiesene Kundendomain, eine Kündigung), und die holt der Host beim nächsten
Abruf **von selbst** nach. Das ist besser als heute, wo ein fehlgeschlagener
Schreibvorgang verloren ist und niemand es bemerkt.
Zur Klarstellung, weil es im Gespräch zweimal durcheinanderging: WireGuard hat
keine Verbindung, die abreißen kann — es ist zustandsloses UDP und nimmt den
Verkehr von selbst wieder auf. Was ausfallen kann, ist ein **Ende**: die
Steuerungs-VM oder der Host. Das repariert kein Protokoll, und es gilt für jede
Variante gleichermaßen.
---
## 8b. Die Subdomain gehört dem Kunden
Heute leitet `ReserveResources::uniqueSubdomain()` sie aus dem Kundennamen ab
(`Str::slug($customer->name).'-'.Str::random(5)`). Der Kunde wird nie gefragt.
**Künftig wählt er sie an der Kasse**, mit drei Vorschlägen aus seinem eigenen
Namen und der Möglichkeit, etwas anderes einzugeben. Leeres Feld → ein
unauffälliger Zufallsname.
### Warum an der Kasse und nicht später
Die Subdomain ist die **Kennung** der Instanz: `instances.subdomain`, der A-Record
in unserer Zone, der interne Hostname, das erste Zertifikat, ein Eintrag in
Nextclouds `trusted_domains`. Sie nachträglich zu ändern heißt, alles davon
gleichzeitig umzuhängen — eine Migration mit Ausfall.
**Nicht zu verwechseln mit der eigenen Domain des Kunden.** Die kommt später
**dazu** und ersetzt nichts: `ConfigureDnsAndTls` bildet
`$hostnames = array_filter([$fqdn, $customDomain])` und serviert beide. Dazunehmen
ja, umbenennen nein.
### Warum ein Hinweis danebensteht
Eine Subdomain ist **dauerhaft öffentlich** — nicht nur im DNS. Jedes
Let's-Encrypt-Zertifikat wird in die Certificate-Transparency-Protokolle
eingetragen; die sind öffentlich, durchsuchbar und werden nie gelöscht.
`mueller.clupilot.cloud` verrät damit für immer, dass ein Müller hier Kunde ist.
Einer GmbH ist das gleich, einer Arztpraxis womöglich nicht. Der Kunde soll das
wissen, bevor er wählt — deshalb der Satz neben dem Feld, und deshalb ein
neutraler Zufallsname als Vorgabe für alle, die nichts eintragen.
### Regeln
- **Sperrliste**, mindestens `www`, `mail`, `admin`, `api`, `app`, `ws`, `status`,
`vpn` — sonst nimmt sich jemand einen Namen, den die Plattform selbst braucht.
- **Eindeutig über alle Kunden**, ohne Rücksicht auf Groß- und Kleinschreibung.
- **Reserviert beim Absenden**, nicht erst wenn die VM steht: zwei gleichzeitige
Bestellungen dürfen nicht nach demselben Namen greifen.
- Länge und erlaubte Zeichen nach DNS-Regeln, keine führenden oder abschließenden
Bindestriche.
---
## 9. Die Host-Kette schrumpft
| Heute | Künftig |
@ -351,7 +428,52 @@ ist die Abnahme, und sie ist die einzige, die zählt.
---
## 14. Folgepunkte
## 14. Zwei beschlossene Vorhaben, die hier NICHT drin sind
Beide im selben Gespräch entschieden, beide bekommen einen eigenen Entwurf. Sie
stehen hier, damit die Entscheidungen nicht verlorengehen.
### Nextcloud zurücksetzen (Kundenfunktion)
Der Kunde kann seine Nextcloud auf Werkszustand zurücksetzen — wenn er etwas
zerschossen hat oder neu anfangen will. Technisch derselbe Ablauf wie eine
Erstbereitstellung, nur für einen Kunden, der schon bezahlt hat.
Beschlossen: **vorher ein Sicherungspunkt, 14 Tage aufbewahrt**, mit einer
Wiederherstellung, die der Kunde selbst auslösen kann. Nur der Kontoinhaber, nicht
jeder Platz. Subdomain zur Bestätigung abtippen statt nur klicken — „neu starten"
und „zurücksetzen" lesen sich zu ähnlich. Sperrfrist zwischen zwei Versuchen.
Bestätigung im Modal nach R23.
**Die Adresse bleibt:** dieselbe Subdomain, dasselbe Zertifikat, eine hinterlegte
eigene Domain bleibt hinterlegt. Der Kunde bekommt eine leere Nextcloud unter
seiner gewohnten Adresse, keine neue Adresse.
### Störungsmeldung an den Betreiber
**Gemessen, dass es das heute nicht gibt:** `SyncMonitoringStatus` läuft alle fünf
Minuten und schreibt den Zustand mit, legt aber **keinen Vorfall an** und schickt
**keine Mail**. In `app/Mail/` gibt es keine einzige Störungsmeldung — alle
vorhandenen Mails gehen an Kunden. Eine Kunden-VM kann also ausfallen, ohne dass
jemand es erfährt.
Beschlossen: **zwei Fehlmessungen in Folge** (der Zeitplan misst fünfminütig, das
sind die gewünschten zehn Minuten) lösen eine Störung aus. Ein einzelner Aussetzer
nicht.
**Fällt ein ganzer Host aus, kommt EINE Meldung** — „Host pve-fsn-1 antwortet
nicht, 40 Instanzen betroffen" — statt vierzig einzelner. Vierzig Mails sagen
nicht, dass es ein Host ist; eine sagt es sofort. Einzelne VMs melden sich
weiterhin einzeln.
Damit es Signal bleibt und nicht Lärm: keine Meldung während eines angekündigten
Wartungsfensters, keine für gekündigte oder abgeschaltete Instanzen, **eine Mail je
Störung** statt alle fünf Minuten eine neue, und eine Entwarnung, wenn es zurück
ist.
---
## 15. Folgepunkte
- Die zwei Seed-Hosts aus `DatabaseSeeder` entfernen. Sie stehen auf `active`,
haben keinen Token und tragen Adressen aus RFC 5737.