<!-- SPDX-License-Identifier: AGPL-3.0-or-later -->
# Einen Hokono-Mix und eine Directory-Authority als unabhängiger Betreiber aufsetzen

Stand 2026-09-21. Diese Anleitung ist für einen Betreiber geschrieben, der **nicht Hokono ist**, und so
konkret, dass ein Agent (z. B. Claude Code) sie auf einem Mac oder Linux-Rechner mit `hcloud`-CLI und
`ssh` abarbeiten kann. Öffentliche Fassung (Mix vollständig, Authority nur als Angebot): `https://hokono.app/registry/onboarding/ANLEITUNG.md`.
Dies ist die öffentliche Fassung: Abschnitt 4 (Authority) beschreibt nur das Angebot.

Grundsatz, der alles andere ordnet: **Hokono ist nie auf deiner Maschine.** Du bekommst keinen Zugang zu
unserer Steuerung, wir bekommen keinen zu deinem Host. Es wandern nur öffentliche Schlüssel und eine
IP-Adresse. Private Schlüssel (`node.key`, `wrap.key`, `da.env`, dein SSH-Key) verlassen deinen Host nie,
auch nicht „zur Prüfung“, auch nicht an uns.

## 0. Was heute geht und was nicht (ehrlich)

| | Heute möglich | Was danach noch auf Hokono-Seite passiert |
|---|---|---|
| **Mix** | Host aufsetzen, Binary aus der Registry mit Hash-Prüfung, gehärteter Betrieb, öffentliche Schlüssel liefern | Vetting durch zwei Authorities, Aufnahme in die Knotenliste und in die Allowlists der Flotte. Ab der nächsten Stunden-Epoche steht der Mix im signierten Consensus (seit 21.09. auch ohne unseren Steuerzugang, TASKS #111/#112). |
| **Directory-Authority** | Host aufsetzen, Schlüssel-Ceremony, öffentliche Schlüssel liefern | Deine Authority wird als Reserve in die Pin-Liste der App aufgenommen (App-Release). Mitsignieren braucht einen Signierweg ohne unseren Steuerzugang (TASKS #64/#113), der noch nicht gebaut ist. Authorities vergeben wir einzeln nach Prüfung; `dirauth`-Binary, cloud-init und Ceremony-Anleitung kommen auf Anfrage, nicht aus der Registry. |

## 1. Voraussetzungen und Regeln

Aus der Aufnahmepolitik (`ACCEPTANCE_POLICY.md`), gekürzt:

- **Identität:** benannte Person oder Firma, Kontaktweg, der binnen 48 h antwortet. Anonym betreiben geht
  nicht (Anonymität gilt für Nutzer, nicht für Betreiber).
- **Unabhängigkeit:** eigenes Hoster-Konto, eigene Rechnungsadresse. Ein Mix bei Hetzner ist in Ordnung,
  obwohl Hokono dort auch Knoten hat. Eine **Authority** sollte **nicht** bei Hetzner, Scaleway oder Vultr
  liegen (dort stehen unsere drei), sondern bei einem vierten Anbieter, idealerweise in einem anderen
  Rechtsraum als DE, PL und SE.
- **Betrieb:** keine Logs (`journald Storage=none`), SSH nur mit Schlüssel, statisches Binary aus der
  Registry oder eigener reproduzierbarer Build, Lizenz AGPL-3.0-or-later.
- **Reziprozität:** keine Bezahlung, kein Vertrag. Wer Knoten stellt, bekommt die Aufnahme und erscheint mit
  Name, Rechtsraum und Hoster auf der Betreiberliste der Website.
- **Grenzen:** höchstens 2 Verkehrsknoten und 1 Authority je Betreiber; 14 Tage Probezeit ohne
  `stable`-Flag; mehr als 24 h Ausfall in der Probezeit beendet sie.

Hardware: 1 vCPU / 1 GB reichen für einen Mix, die Anleitung nimmt Hetzner `cx23` (2 vCPU, 4 GB,
5,49 € netto/Monat, geprüft 2026-09-21). Für die Authority genügt dasselbe. Beide Rollen brauchen `linux/amd64`
(kein ARM: die Registry-Binaries sind x86-64).

## 2. Download- und Referenz-URLs

Alles Nötige liegt öffentlich in der **Node-Registry**. Die Quell-Repositories sind derzeit privat; du
brauchst sie nicht.

| Was | URL |
|---|---|
| Registry-Übersicht (Hashes, Build-Commit, Herkunft) | `https://hokono.app/registry/` |
| Manifest | `https://hokono.app/registry/SHA256SUMS` · `PLATFORM` · `BUILDINFO` · `PROVENANCE` |
| Mix-Binary (statisch, x86-64) | `https://hokono.app/registry/mixnode` |
| Authority-Schlüssel (öffentlich, Pin-Liste) | `https://hokono.app/registry/authorities.txt` |
| DA-Binary `dirauth` | nicht in der Registry; **auf Anfrage** (Hash steht öffentlich im Manifest: `581335ae…3e`) |
| Diese Anleitung (öffentliche Fassung) und Betreiber-Seite | `https://hokono.app/registry/onboarding/ANLEITUNG.md` · `https://hokono.app/betreiber/` |
| cloud-init Mix | `https://hokono.app/registry/onboarding/cloud-init-mix.yaml` |
| cloud-init Authority | **auf Anfrage** (liegt im Backend-Repo unter `infra/onboarding-hetzner/cloud-init-da.yaml`) |
| Prüfskript (von außen + per SSH) | `https://hokono.app/registry/onboarding/check.sh` |
| Aufnahmepolitik, Betreiber-Doku | `https://hokono.app/registry/onboarding/ACCEPTANCE_POLICY.md` · `OPERATOR_ONBOARDING.md` (Authority-Verfahren `DA_ONBOARDING.md` auf Anfrage) |
| Quellcode (AGPL) | `https://gitlab.com/hokono/backend-oss` *(privat bis zur Freigabe durch den Fachanwalt; Einladung auf Anfrage)* |
| Hetzner CLI | `https://github.com/hetznercloud/cli` (`brew install hcloud`) |

Manifest-Stand beim Schreiben: `mixnode` aus Commit `b938a44` =
`e5144558de0e407f0dabd309a8645ad7c5f1804a8e7b2526a274b628d7ee5b07` (Herkunft je Artefakt steht in
`PROVENANCE`; `BUILDINFO` nennt den Build-Commit der Gateways). Das Installationsskript prüft immer gegen das
**aktuelle** Manifest, nicht gegen diese Zahl.

**Peers** muss niemand pflegen: Der Mix holt das signierte Directory selbst von einem Gateway
(Bootstrap-Adressen stehen im cloud-init), prüft die Signaturen gegen die öffentlichen
Authority-Schlüssel aus `authorities.txt` und erlaubt genau die Knoten aus dem Consensus. Ohne gültiges
Directory leitet er nichts weiter. Neue Knoten kennt er nach dem nächsten stündlichen Abruf.

## 3. Mix aufsetzen

### 3.1 Vorbereitung auf deinem Rechner

```sh
brew install hcloud                      # oder: https://github.com/hetznercloud/cli/releases
hcloud context create hokono-mix         # fragt den API-Token deines Hetzner-Projekts ab
ssh-keygen -t ed25519 -f ~/.ssh/hokono-node -N ''      # eigener Schlüssel nur für diesen Knoten
mkdir -p ~/hokono-node && cd ~/hokono-node
curl -fsSLO https://hokono.app/registry/onboarding/cloud-init-mix.yaml
curl -fsSLO https://hokono.app/registry/onboarding/check.sh
```

Lege den API-Token in einem **eigenen Hetzner-Projekt** an (nur dieser Server darin). Der Token braucht
Lese- und Schreibrechte, wird nur von `hcloud` benutzt und gehört nicht in Chat-Verläufe. Statt
`hcloud context create` geht auch die Umgebungsvariable `HCLOUD_TOKEN` (praktisch für Agenten).

### 3.2 Platzhalter füllen und Server anlegen

```sh
sed -e "s|__SSH_PUBKEY__|$(cat ~/.ssh/hokono-node.pub)|" \
    -e "s|__OPERATOR_TAG__|<dein-kurzname>|" cloud-init-mix.yaml > my-mix.yaml
hcloud server create --name mix-<dein-kurzname> --type cx23 --image debian-12 --location nbg1 \
  --user-data-from-file my-mix.yaml
```

`<dein-kurzname>`: Kleinbuchstaben, Ziffern, Bindestrich, z. B. der Firmenname. Er wird als
Betreiberkennung im Consensus sichtbar. Standort frei wählbar (`nbg1`, `fsn1`, `hel1`). `hcloud` zeigt
nach dem Anlegen ein Root-Passwort an: nicht nötig, cloud-init schaltet den Root-Login ab.

Was cloud-init macht (3 bis 4 Minuten): Debian 12 aktualisieren, journald auf `Storage=none`, nftables
mit nur 22 und 1789, Passwort-Login aus, `mixnode` und `authorities.txt` aus der Registry laden und
**gegen das Manifest prüfen** (bricht bei Abweichung ab), lokalen Wickelschlüssel erzeugen, gehärtete
systemd-Unit anlegen, starten, cloud-init-Logs löschen. Beim
ersten Start erzeugt der Daemon sein Schlüsselpaar (X25519 ‖ ML-KEM-768) selbst und schreibt
`/var/lib/hokono/pubkeys.txt` mit dem öffentlichen Teil.

### 3.3 Prüfen

```sh
IP=$(hcloud server ip mix-<dein-kurzname>)
ssh-keyscan -H "$IP" >> ~/.ssh/known_hosts 2>/dev/null
bash check.sh "$IP" mix hokono-admin ~/.ssh/hokono-node
```

Der vierte Parameter ist der SSH-Schlüssel; alternativ `SSH_OPTS="-i <pfad>"` setzen.

Erwartete Ausgabe (Hash-Werte je nach Manifest-Stand):

```
22     offen
1789   offen (muss offen sein)
7443   zu (muss zu sein: kein Gateway)
PORTS OK
laufend  e5144558…5b07
platte   e5144558…5b07
manifest e5144558…5b07
HASH OK
journald: 0B
0.0.0.0:1789
0.0.0.0:22
--- pubkeys.txt (oeffentlich, Datei ist 0600 hokono -> sudo):
X_PUB=<64 hex>
K_PUB=<2368 hex>
```

Reihenfolge der Regeln: (1) Erst nach der Wartezeit zählt ein Ergebnis. (2) Weicht `PORTS` oder `HASH`
ab oder scheitert das Skript an SSH oder einer Datei, einmal nach zwei Minuten wiederholen. (3) Bleibt
`HASH WEICHT AB` oder `PORTS WEICHEN AB` bestehen, **nicht** weiterreichen, sondern die komplette Ausgabe
an `node@hokono.app`. Ein zu früher Lauf zeigt `1789 zu`, weil das Binary erst am Ende startet.

### 3.4 Was du an Hokono schickst (und was nie)

**Schicken** (Mail an `node@hokono.app`, gern PGP-verschlüsselt; ein Block, damit ein Agent ihn
unverändert übernehmen kann):

```json
{
  "role": "mix",
  "operator": "<dein-kurzname>",
  "contact": "<Name, E-Mail, ggf. PGP-Fingerprint>",
  "hoster": "hetzner",
  "location": "nbg1",
  "jurisdiction": "DE",
  "ip": "<öffentliche IPv4>",
  "X_PUB": "<aus pubkeys.txt>",
  "K_PUB": "<aus pubkeys.txt>",
  "mixnode_sha256": "<Zeile 'laufend' aus check.sh>",
  "bandwidth_mbit": 1000,
  "independence": "<Hinweis auf Registerauszug oder Hoster-Rechnung mit geschwärzten Beträgen>"
}
```

**Nie schicken:** `node.key`, `wrap.key`, den privaten SSH-Schlüssel, den Hetzner-Token, den Inhalt von
`/var/lib/hokono` außer `pubkeys.txt`. Wir fragen nie danach; wer danach fragt, ist nicht Hokono.

### 3.5 Was danach passiert

1. Zwei Authorities prüfen die Selbstauskunft unabhängig (WHOIS/ASN, Registerauskunft, Kontaktprobe).
2. Hokono trägt den Knoten in die Knotenliste ein und nimmt deine IP in die Peer-Allowlists der Flotte
   auf (Firewall der Gateways und Mixes auf Port 1789).
3. Ab der nächsten Consensus-Epoche (stündlich) steht dein Mix im signierten Dokument, zunächst ohne
   `stable`. Die App nutzt ihn ohne Update.
4. Nach 14 Tagen ohne Ausfall > 24 h wird `stable` gesetzt und du erscheinst auf der Betreiberliste.

## 4. Directory-Authority: Angebot, Material auf Anfrage

Eine Authority signiert stündlich die Knotenliste, sieht keinen Verkehr und hat keinen offenen
Dienst-Port. Der Client akzeptiert ein Dokument nur mit **2 von n** Signaturen gepinnter Authorities.
Weil zwei Authorities zusammen den Consensus bestimmen könnten, **vergeben wir Authorities einzeln** und
nach Prüfung, nicht über diese Seite.

Wer in Frage kommt: benannte Person oder Organisation mit öffentlichem Track-Record (Infrastruktur,
Freie Software, Bürgerrechte), eigener Hoster, der **nicht** Hetzner, Scaleway oder Vultr ist, und nach
Möglichkeit ein anderer Rechtsraum als DE, PL, SE. Bereitschaft, stündlich automatisiert zu signieren,
PGP-Kontakt für Vorfälle.

Anfrage an `node@hokono.app` mit Selbstauskunft (Identität, Hoster, Rechtsraum, Kontakt). Bei Eignung
liefern wir cloud-init, das `dirauth`-Binary (sein Hash steht bereits öffentlich im Manifest) und die
Ceremony-Anleitung. Der private Schlüssel entsteht auf deinem Host und verlässt ihn nie. Die Aufnahme
in die Pin-Liste der App ist ein App-Release; bis der automatisierte Signierweg für fremde Authorities
steht, bist du Reserve-Authority.

## 5. Betrieb

- **Updates:** Hokono veröffentlicht neue Binaries in der Registry und meldet sich. Auf dem Mix reicht
  `sudo /usr/local/sbin/hokono-install-mix.sh` (lädt, prüft Hash, startet neu). Schlüssel und
  Replay-Cache bleiben erhalten.
- **Peers:** kommen aus dem Consensus, stündlich neu. Fest ist nur die Bootstrap-Adresse
  (`DIRECTORY_FROM` in `hokono-install-mix.sh`, zwei Gateways). Ändern sich beide, nennen wir den
  neuen Wert; danach Skript erneut ausführen.
- **Rotation:** der Mix rotiert sein Schlüsselpaar alle 7 Tage mit 72 h Karenz von selbst; nichts zu tun.
- **Logs:** es gibt keine. `sudo journalctl --disk-usage` muss `0B` bleiben; die cloud-init-Protokolle
  löscht die Einrichtung am Ende selbst. Kein Monitoring-Agent, der
  Verkehr oder Verbindungen mitschreibt.
- **SSH:** nach der Einrichtung möglichst schließen (Port 22 aus `/etc/nftables.conf` entfernen,
  `nft -f /etc/nftables.conf`) und nur für Wartung öffnen, über die Hetzner-Firewall oder die Konsole.
- **Nachweis auf Anfrage:** `sha256sum /proc/$(pidof hokono-mixnode)/exe`, `journalctl --disk-usage`,
  `ss -tlnp`. Nichts davon erfordert unseren Zugriff.

## 6. Für den ausführenden Agenten

Checkliste (Mix) in Reihenfolge, mit Stopp-Bedingungen:

1. `hcloud` und `ssh` vorhanden, eigenes Hetzner-Projekt mit Token, SSH-Schlüssel erzeugt.
2. cloud-init geladen, zwei Platzhalter ersetzt, **keine anderen Änderungen**.
3. Server angelegt; 4 Minuten warten (`hcloud server describe <name>` zeigt `running`, cloud-init braucht
   danach noch 1 bis 3 Minuten).
4. `check.sh` mit dem SSH-Schlüssel als viertem Parameter ausführen. **Stopp**, wenn `PORTS WEICHEN AB`
   oder `HASH WEICHT AB`: nichts weiterreichen, Ausgabe an den Betreiber, der Hokono kontaktiert. Andere
   Fehler: einmal nach zwei Minuten wiederholen.
5. Nur die öffentlichen Werte in den JSON-Block übernehmen. **Stopp**, wenn im Block irgendwo `PRIV=`,
   `node.key`, `wrap.key` oder ein SSH-Privatschlüssel auftaucht.
6. Der Betreiber (nicht der Agent) verschickt den Block; er trägt die Selbstauskunft.

Zeitbedarf: Mix 15 Minuten, Wartezeit bei Hokono für Vetting und Aufnahme: Tage.
