SICHERUNG (tools/sichern.ps1, taeglich 04:30 als geplante Aufgabe).
Die Datenbank wird nicht kopiert, sondern ueber SQLites eigene
Sicherungsschnittstelle herausgeholt (server/src/backup.ts): im WAL-Modus
liegt das Zuletzte noch nicht in media.db, und selbst alle drei Dateien zu
kopieren ist nicht sicher, wenn waehrenddessen geschrieben wird. Die Bilder
kommen aus einem NUR LESEND eingehaengten Volume dazu.
Und sie prueft sich selbst: auspacken, Datenbank oeffnen, Medien/Token/
Benutzer zaehlen, mit dem laufenden Dienst vergleichen, sonst Fehler. Einmal
wirklich zurueckgespielt -- leeres Volume, zweiter Dienst, Anmeldung mit dem
echten Passwort, Bild abgerufen, Byte fuer Byte identisch. Eine Sicherung, die
nie zurueckgespielt wurde, ist eine Hoffnung.
ANMELDEBREMSE. Das Formular steht oeffentlich, und scrypt macht einen Versuch
teuer -- aber teuer ist nicht selten. Fuenf freie Versuche je Adresse, dann
Sperre ab 30 s mit Verdopplung bis 15 min, 429 samt Retry-After und einem Text,
der sagt wie lange. Erfolg setzt zurueck. Nur im Speicher: wer sich aussperrt,
startet den Container neu. Durchgemessen bis zur Erholung.
VORSCHAUBILDER. sharp erzeugt beim Upload eine 320er WebP-Fassung unter
/data/thumbs, ausgeliefert unter /t/<pfad>. Gemessen: 131502 -> 13078 Bytes,
Faktor 10; eine Galerieseite faellt von 7,5 MB auf 766 KB. KEINE Spalte in der
Datenbank -- ob es eine Vorschau gibt, sagt das Dateisystem, und die Galerie
faellt bei 404 aufs Vollbild zurueck. Eine zweite Wahrheit, die auseinander-
laufen kann, gibt es damit gar nicht erst. Ein Knopf zieht Fehlendes nach und
nennt Zahlen statt "fertig".
SCHRITT 5. Die Fivemanage-Dateien liegen in legacy/ mit Erklaerung; unsere
docker-compose.media.yml heisst jetzt docker-compose.yml. Drei Volumes und drei
Abbilder geloescht, rund 670 MB -- nachgezaehlt war vorher, dass kein Bild
darin lag.
Nebenbefund: `npm i sharp` scheitert auf diesem Rechner nicht an sharp, sondern
an better-sqlite3 -- der Host laeuft auf Node 24 (ABI 137), node-gyp uebernimmt
und findet keine Bauwerkzeuge. Genau die Falle aus dem Dockerfile. Eingetragen
wurde mit --package-lock-only, gebaut wird im Abbild auf Node 22.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Schritt 4. React 18, TypeScript, Vite 5, Tailwind 4 (CSS-first), Lucide,
Zustand; kein Konsta. Quelle in server/ui, Build nach server/web (gitignored),
im Abbild von einer eigenen Docker-Stufe gebaut.
JEDER KNOPF GIBT RUECKMELDUNG -- und zwar erzwungen, nicht vorgenommen:
- api.ts haelt den EINZIGEN fetch und GENAU EINE Fehlerklasse. Der
Fivemanage-Fehler war, zwei zu haben: geworfen wurde `new Error`, geprueft
auf `instanceof ApiError`, und damit verschwand jeder Fehlschlag lautlos.
- store.ts haelt run(): Aktion rein, Erfolgstext rein, und es meldet bei
Erfolg diesen und bei Fehlschlag den Text DES DIENSTES. Wer darueber geht,
kann keinen stillen Knopf bauen.
- Jeder wartende Knopf ist gesperrt und zeigt einen Kreisel. Der zweite Klick
eine Sekunde spaeter war der Weg zu neunzehn gleichnamigen Organisationen.
- Fehlermeldungen bleiben stehen, bis jemand sie wegklickt. Ein Fehler, der
von allein verschwindet, ist einer, den niemand gelesen hat.
@vitejs/plugin-react ist auf ^4 festgenagelt: die 6 verlangt vite ^8. In den
peerDependencies nachgesehen -- Vite 5.4.21 liegt in der Schnittmenge von
plugin-react@4 und @tailwindcss/vite@4.
Am laufenden Container nachgemessen: / kommt als text/html, assets/*.js als
text/javascript, *.css als text/css (die MIME-Falle aus Schritt 1 traegt), und
/tokens, /speicher, /konto liefern dieselbe index.html -- die SPA-Rueckfall-
route tut, wofuer sie gebaut wurde.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
/studio shot adder, und das Bild lag Sekunden spaeter unter
https://fivemanage.d4rkst3r.de/f/vehicles/adder.webp. Von der Dienstseite
gegengeprueft statt der Logzeile geglaubt: 132908 Bytes hier wie dort,
derselbe SHA-256, ausgeliefert als image/webp, erste Bytes RIFF....WEBP --
ein echtes WebP und kein falsch benanntes PNG.
Damit ist die letzte Frage aus dem Pruefstand beantwortet: PerformHttpRequest
verhaelt sich in FiveM wie die Faelschung, Kopfzeilen und base64-Rumpf kommen
unveraendert an, der Rueckruf erreicht den Event-Handler.
Als ungeprueft benannt bleibt, was ungeprueft ist: ein ganzer Serienlauf ueber
900 Fahrzeuge, und Upload.put -- die wartende Form, die der Lauf nicht nimmt.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Der Stack laeuft unter https://fivemanage.d4rkst3r.de, hinter NPM mit
Let's-Encrypt-Zertifikat, Container auf Port 9101.
DER NAME IST EINE UMKEHR, und sie steht ausfuehrlich im ROADMAP: hier stand,
dass fivecdn und fivemanage wegfallen, weil wir kein Fivemanage betreiben. Das
Argument gilt weiter -- es ist nur teurer als das, was dagegen steht. Der Name
war bereits fertig verkabelt: DNS da, NPM-Host da, Zertifikat gueltig bis
09.11.2026, Ziel host.docker.internal:9101, und dieser Port wurde frei, als die
Lite-Container gingen. Unser Stack auf 9101 kostet damit null Klicks. Der
Wechsel auf media.d4rkst3r.de bleibt billig, weil keine Adresse in der
Datenbank steht.
Ueber die oeffentliche Adresse durchgemessen: Anmeldung durch echtes HTTPS
(der Fall, den curl bisher nicht bezeugen konnte), Token mit Praefix-Fessel,
403 mit Text fuer anderswo/ und fuers Loeschen, Upload und Abruf Byte fuer
Byte identisch.
Und ein Befund aus dem Fotostudio-Anschluss: die Pfadmeldung war irrefuehrend.
SEGMENT verlangt als ERSTES Zeichen einen Buchstaben oder eine Ziffer, die
Meldung sprach aber nur von "nicht mit Punkt beginnend" -- ein fuehrender
Unterstrich faellt ebenso durch. Kein erfundener Fall: das Fotostudio legt
seine Leerbilder als "_plate" ab. Jetzt nennt die Meldung die Regel.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
1. Es gibt keine zweite Maschine. Gebaut wurde auf DEM Server -- hier laufen
Gitea, Portainer, NPM und die Nextcloud. Die Notiz "auf dieser Maschine
gibt es weder Docker noch WSL" stammt aus der Zeit vor Docker Desktop.
Zum Betrieb fehlt damit kein Umzug, sondern nur der oeffentliche Auftritt:
DNS, ein Host in NPM mit TLS, ein echtes Passwort.
2. Die Portliste war unvollstaendig -- 8443 (Nextcloud AIO) fehlte. Neu
gemessen aus "docker ps", nicht aus der Erinnerung. 9100/9101 sind frei,
seit die Lite-Container weg sind; wir bleiben trotzdem auf 9102.
3. "Bis dahin bleibt der Lite-Stack als Vergleichsmassstab laufen" gilt nicht
mehr: die Container sind geloescht. Was liegen blieb, sind drei Volumes und
die Abbilder. Alle drei Volumes schreibgeschuetzt durchgezaehlt -- KEIN
einziges Bild, minio besteht aus 244 KB reiner .minio.sys. Loeschen kostet
also nichts; es ist nur noch nicht getan.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Der Bau stand ungeprueft im Repo, und alles daran war Behauptung: ob
`npm ci` die fertige Binaerdatei zieht, ob das Volume greift, ob der
Healthcheck etwas taugt. Jetzt nachgesehen, auf einer Maschine mit Docker
Desktop 29.6.2:
- better-sqlite3 kommt als Binaerdatei, nicht aus node-gyp (datiert Mai 2025,
kein Makefile daneben). Node 22, ABI 127 -- die Festnagelung traegt.
- Derselbe Durchstich wie in Schritt 1, diesmal gegen den Container: 24
Pruefungen, keine durchgefallen. Am Grundgeruest war nichts zu aendern.
- Healthcheck meldet healthy; das Volume traegt ueber einen Containerwechsel;
Compose bricht ohne PUBLIC_URL/ADMIN_PASSWORD ab, wie das :? verspricht.
Neu aufgefallen, weil der Container es sichtbar macht: im Volume liegen VIER
Dinge, nicht zwei. SQLite laeuft im WAL-Modus, und das WAL hielt nach wenigen
Uploads 152 KB, die in media.db noch nicht standen -- eine Sicherung nur ueber
media.db waere unvollstaendig. Steht jetzt bei den offenen Entscheidungen.
Und ein Zeuge weniger: curl taugt fuer die Secure-Cookie-Falle nicht, er
schickt das Cookie auch ueber http und meldet Erfolg. Was zaehlt, ist der
Browser.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
"Pruefen statt raten" stand bisher nur in einer Notiz auf einer Maschine.
Wer dieses Projekt auf einem anderen Rechner aufmacht, faengt sonst ohne
sie an -- und genau dort wird gleich weitergearbeitet.
Dazu die vier Faelle aus diesem Repo, die erst beim Messen aufgefallen
sind, als Beleg statt als Behauptung: der Einhaengepunkt in c.req.path,
das Sternchen, das kein Parameter ist, das try/catch um createReadStream,
das Secure-Cookie, das ueber localhost funktioniert und ueber eine
LAN-Adresse nicht.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Auf dieser Maschine gibt es weder Docker noch WSL. Das Abbild ist also
ungebaut und der Container nie gelaufen; das gehoert auf eine Maschine
mit Docker, bevor jemand darauf baut.
Was trotzdem geprueft ist:
Node 22 ist festgenagelt, und das ist kein Zufall. better-sqlite3 11.10.0
liefert fertige Binaerdateien nur fuer ABI 108 (Node 20), 115, 127
(Node 22) und 131 -- Node 24 hat ABI 137 und fehlt. Der naheliegende
Griff zur neuesten Version faellt damit auf node-gyp zurueck und braucht
python3, make und g++ im Abbild. Aus den Veroeffentlichungen des Projekts
abgelesen, nicht aus dem Gedaechtnis.
node dist/index.js -- der Startbefehl des Abbilds -- laeuft und antwortet
auf /health. Bis hierher war der Dienst nur je ueber tsx gestartet
worden. Der Healthcheck gibt Exitcode 0 bei laufendem und 1 bei totem
Dienst.
Dazu eine Falle, die im Compose steht, weil sie teuer ist:
NODE_ENV=production setzt das Sitzungs-Cookie auf Secure. Wer den
Container ohne HTTPS aufruft, bekommt auf die Anmeldung 200 -- und ist
trotzdem nicht angemeldet, weil der Browser das Cookie still verwirft.
Die naechste Anfrage ist 401. Im Browser gegen eine LAN-Adresse
nachgemessen. Die naheliegende Gegenprobe ueber localhost fuehrt in die
Irre: das gilt Browsern als sicherer Kontext und funktioniert.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
fivecdn.d4rkst3r.de und fivemanage.d4rkst3r.de fallen weg -- wir betreiben
kein Fivemanage, also tragen unsere Adressen auch nicht dessen Namen.
Dashboard und API liegen an der Wurzel, die Dateien unter /f/.
Der Ein-Namen-Betrieb war bis jetzt nicht ausdrueckbar. Der Kommentar in
config.ts versprach "leer lassen, wenn alles unter einem Namen laufen
soll", aber optional() faellt bei leerem Wert auf den Host aus PUBLIC_URL
zurueck -- und dann gilt JEDE Anfrage als Anfrage an den Dateiwirt: kein
Dashboard, keine API, /health gibt 404 und die Anmeldung 405 "hier gibt
es nur Dateien". Nichts ist kaputt, und niemand kommt darauf. Deshalb ist
der Ein-Namen-Betrieb jetzt der Standard und der zweite Name die Ansage.
PUBLIC_URL ist nur noch der Ursprung; das /f haengt der Dienst selbst an.
Wer es mitschriebe, bekaeme Adressen mit /f/f/, und das faellt erst auf,
wenn das erste Bild fehlt. Praefix und Route haengen jetzt an derselben
Stelle (config.filePrefix), damit die zurueckgegebene Adresse und die
Route, die sie ausliefert, nicht auseinanderlaufen koennen.
Beide Betriebsarten durchgemessen: mit einem Namen kommt
.../f/vehicles/adder.png zurueck und liefert die Datei; mit gesetztem
FILES_HOST kommt sie ohne Praefix, liegt unter dem Dateihost, ist am
Dashboard-Namen zusaetzlich unter /f/ erreichbar, und unter dem Dateihost
gibt es weiterhin keine API. Welche Betriebsart laeuft, sagt der Dienst
in der zweiten Startzeile.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Der Durchstich steht: anmelden, Token anlegen, Bild hochladen, unter der
zurueckgegebenen URL abrufen -- Byte fuer Byte identisch, auch unter dem
Dateihost.
server/.env.example ist die Datei, die .gitignore ohnehin schon erwartet
hat. Wichtigster Eintrag darin ist FILES_HOST: ohne ihn nimmt der Dienst
den Host aus PUBLIC_URL, lokal also localhost. Dann gilt jede Anfrage als
Anfrage an den Dateiwirt, und dort gibt es absichtlich weder Dashboard
noch API -- /health antwortet 404, die Anmeldung 405 "hier gibt es nur
Dateien". Nichts ist kaputt, der Dienst tut genau das, was er soll, nur
eben unter dem einen Namen, den man lokal hat. In Produktion sind es zwei
verschiedene Namen und der Standard stimmt.
Das dev-Skript liest die .env jetzt mit --env-file (funktioniert unter
tsx, nachgeprueft).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Das Grundgeruest war typgeprueft, aber nie gelaufen. Beim ersten Start
haben sich sechs Dinge gezeigt, alle nachgemessen statt vermutet:
1. Die Token-Pruefung hing an '*' und galt damit auch fuer /api/dash/*,
das daneben liegt. Das Dashboard bekam "Token fehlt oder ist
unbekannt" auf die Anmeldung, obwohl es nie einen Token haben kann.
Sie haengt jetzt an den drei eigenen Pfaden.
2. DELETE /api/media/... und GET /api/exists/... sahen am Ziel vorbei.
c.req.path traegt den Einhaengepunkt mit, das replace(/^\/media\//)
schnitt ihn nicht weg -- aus vehicles/adder.png wurde
api/media/vehicles/adder.png. Loeschen fand nie etwas, exists meldete
immer false. Jetzt :pfad{.+}; Hono liefert den Parameter fertig
dekodiert (an einer Probe gemessen), ein zweites decodeURIComponent
waere eine Dekodierung zu viel.
3. Verzeichnisdurchstieg in der SPA-Rueckfallroute: GET /..%5Cpackage.json
hat unter Windows die Datei ausgeliefert. Hono reicht %5C durch,
path.join behandelt den Backslash dort als Trenner, und eine
Eindaemmung gab es nicht. Unter Linux traegt genau dieser Angriff
nicht -- Glueck, keine Abwehr. Jetzt dieselbe resolve-Pruefung wie in
storage.ts.
4. Die Auskunft "Oberflaeche ist nicht gebaut" war unerreichbar.
createReadStream meldet eine fehlende Datei asynchron, das try/catch
darum fing nichts. Ergebnis war ein leerer 200 samt ENOENT im Log.
5. CSS und JS kamen als application/octet-stream -- die MIME-Tabelle
kennt nur Medientypen, das Dashboard haette weder Stylesheet noch
Modul geladen. Die Oberflaeche bekommt eine eigene Tabelle: in der
geteilten fehlt html mit Absicht, sonst koennte jeder mit einem
Upload-Token eine Seite unter fivecdn.d4rkst3r.de veroeffentlichen.
6. Kaputtes JSON endete als nackter "Internal Server Error".
Ausgerechnet das -- ein 500 ohne ein Wort dazu ist der Fehler, wegen
dem wir hier neu bauen. Jetzt 400 mit Text.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Ein Container statt vier: Hono, SQLite, Dateien auf einer Platte. Kein
PostgreSQL, kein MinIO, kein ClickHouse. Das ist nicht die kleine Loesung,
sondern die, die man nicht pflegt — eine Sicherung ist ein cp -a.
Der Ausloeser war nicht der Funktionsumfang von Lite, sondern dessen
Zustand. web/src/utils/http-util.ts wirft jeden Fehler als new Error(...),
die Hooks pruefen auf "instanceof ApiError" — damit wird jeder Fehlschlag
lautlos verschluckt. "Create organization" meldet weder Erfolg noch
Misserfolg; das Ergebnis waren 19 gleichnamige Organisationen, die sich auch
nicht loeschen lassen, weil die Route fehlt. Von allem, was Lite darueber
hinaus kann, haben wir nichts gebraucht.
Zwei Hostnamen, ein Prozess: unter FILES_HOST gibt es ausschliesslich
Dateien — kein Dashboard, keine API, nichts anzumelden. Das haelt die
oeffentliche Adresse frei von Angriffsflaeche und die URLs huebsch, ohne
/f/-Praefix. Die Vorlage im Handy bleibt {model}.webp.
Der Pfad ist der Schluessel: X-Path legt die Datei genau dort ab, wo der
Aufrufer sie erwartet. Bei Lite haetten wir die zurueckgegebenen Adressen in
einer urls.json mitschleppen muessen — vorhersagbare URLs sind fuer das
Fotostudio die ganze Voraussetzung.
storage.ts bereinigt Pfade NICHT, es lehnt sie ab. Ein zurechtgebogener Pfad
legt die Datei unter einem anderen Namen ab als dem erwarteten, und das faellt
erst auf, wenn das Bild fehlt.
Typprueft. Noch nicht gestartet, noch nicht getestet — das ist der naechste
Schritt und steht in ROADMAP.md.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Die Organisation wird angelegt. NewOrganizationRoute.tsx ruft nur mutate(data)
ohne onSuccess, ohne Navigation, ohne Meldung — die Seite bleibt einfach
stehen. Im Container-Log steht dazu nichts, weil der Handler nur im Fehlerfall
protokolliert; genau dieses Schweigen ist der Hinweis, dass es geklappt hat.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Das Tracing-Rauschen alle fuenf Minuten ist kein Fehler und laesst sich in
beta.23 nicht abstellen: otlpEndpoint ist eine Konstante, ENV waehlt nur
zwischen TLS und unverschluesselt. Da die Adresse localhost lautet, hilft auch
kein Jaeger-Container daneben — der muesste sich den Netzwerk-Namensraum
teilen.
Wichtiger: wenn ein Knopf in der Oberflaeche nichts tut, steht der Grund im
Log und nie auf dem Bildschirm. http-util.ts wirft jeden Fehler als
new Error(...) weiter, die Hooks pruefen auf "instanceof ApiError" — das ist
danach nie wahr. 401, 500 und ein falscher Rumpf sehen alle gleich aus.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Der Stack lief, meldete alle Container gesund — und beide Adressen gaben 502.
Grund: kein einziger Port veroeffentlicht. Die standen in
docker-compose.hostports.yml, und Portainer hat die nicht angewandt.
Das war mein Anleitungsfehler. Ich hatte geschrieben, man koenne unter
"Compose path" zwei Pfade mit Komma angeben. Portainer nimmt dort EINE Datei.
Die Ergaenzung wurde nicht etwa abgelehnt, sondern stillschweigend ignoriert —
die schlechteste Art zu scheitern, weil danach alles gesund aussieht.
Eine Trennung, die man nicht anwenden kann, ist keine. Die Ports stehen jetzt
in docker-compose.yml, wo dieser Server sie ohnehin braucht.
docker-compose.proxynet.yml bleibt als der sauberere Weg fuer einen Proxy im
selben Docker-Netz, jetzt aber mit dem Hinweis, dass er ueber Portainer-aus-
Repo nicht zu haben ist. Hier trifft er nicht zu: NPM liegt auf 172.17.0.3 im
Standard-Bridge-Netz.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Zwei Funde beim Lesen von pkg/storage/s3/s3.go und der .env.template des
Projekts.
BUCKET_DOMAIN fehlte. AWS_ENDPOINT ist nur der Weg, auf dem Lite die Dateien
HINLEGT — http://minio:9000, Containername im internen Netz, und das ist
richtig so. Die oeffentliche Adresse, die Lite nach dem Upload zurueckgibt,
baut es aus BUCKET_DOMAIN. Die Variable steht nicht im README des Projekts,
nur in dessen .env.template (BUCKET_DOMAIN=http://localhost:9000/lite-dev,
also Endpunkt plus Bucket). Ohne sie waere jeder Upload scheinbar geglueckt
und das Bild von aussen nicht abrufbar — ein Fehler, der erst im Handy
auffaellt und dort nach einem CDN-Problem aussieht.
minio-init faellt weg, und zwar nicht nur als Ballast: Lite legt den Bucket
beim Start selbst an und setzt dabei die oeffentliche Leserichtlinie. Es
ueberspringt beides, wenn der Bucket schon existiert ("already exists.
skipping creation and policy application"). Mein Init-Container kam ihm zuvor
und haette damit genau die Richtlinie verhindert, die er ersetzen sollte. Dass
es trotzdem funktioniert haette — mc anonymous set download tut dasselbe —
macht es nicht besser, sondern nur unauffaelliger.
AWS_REGION folgt jetzt deren Vorlage (eu-west-1 statt auto). Fuer MinIO ist
sie gleichgueltig, das SDK verlangt aber eine.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
"panic: pgdriver: invalid scheme: lite"
Die Anwendung geht direkt in den PostgreSQL-Treiber; DB_DRIVER wird nicht
ausgewertet. Die MySQL-DSN (lite:pass@tcp(db:3306)/...) liest der Treiber als
URI und findet als Schema den Benutzernamen.
Der Fehler war meiner, und die Ursache lehrreich: ich hatte MySQL aus deren
docker-compose.test.yml uebernommen, weil die als einzige zeigt, wie der
App-Container verdrahtet wird. Sie benutzt aber fivemanage/lite:latest von
Docker Hub — und diese Reihe steht bei beta.16 still. Das README sagt
postgres://, und es hat recht. Ich habe der aelteren Datei mehr geglaubt als
der Doku, weil sie konkreter aussah.
Damit faellt auch die Behauptung, MySQL genuege und man koenne den vorhandenen
QBox-Server mitbenutzen. Stimmt fuer diese Fassung nicht.
Das Volume heisst jetzt pgdata statt db: wer den Stack schon mit MySQL laufen
hatte, bekommt eine frische Ablage, statt dass PostgreSQL ueber ein
MySQL-Verzeichnis stolpert. Das alte bleibt als Waise liegen.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Ich hatte die Ports an 127.0.0.1 gebunden — enger und auf den ersten Blick
richtiger. Nur erreicht host.docker.internal das auf diesem Server nicht: die
Anfrage kommt aus dem NPM-Container ueber die Docker-Bruecke herein, nicht
ueber Loopback, und ein an 127.0.0.1 gebundener Port nimmt sie nicht an.
Der Beleg stand die ganze Zeit in der Containerliste: d4rkbot (3080),
cdn-files (8090) und portainer sind alle ohne 127.0.0.1-Praefix
veroeffentlicht, und NPM erreicht sie. So laeuft es hier, also laeuft es so.
Damit macht die FIREWALL den Port zu und nicht die Bindung — das steht jetzt
ausdruecklich in beiden Dateien, mitsamt den Befehlen zum Nachsehen. Wer weiss,
dass Loopback bei ihm erreicht wird, setzt BIND_ADDR=127.0.0.1.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Die Containerliste des Servers beantwortet beides.
Der NPM-Container hat 172.17.0.3 und liegt damit im Standard-Bridge-Netz,
nicht in "web". Meine Vermutung, "web" sei das Proxy-Netz, war falsch — es
gilt Weg B ueber den Host, so wie d4rkbot auf 3080 und cdn-files auf 8090
schon laufen. Im README steht das jetzt als Feststellung und nicht mehr als
Wahrscheinlichkeit.
Und die Ergaenzung wollte ausgerechnet 9000 und 8080 oeffnen — beide vergeben,
an Portainer und an nextcloud-aio. Jetzt 9100 und 9101, und ueber
MINIO_HOST_PORT und LITE_HOST_PORT einstellbar: die naechste Kollision ist dann
eine Variable und keine Dateiaenderung. Im Container bleibt es bei 9000 und
8080; nur die Seite zum Host wandert.
Belegt waren: 80, 81, 443, 2224, 3000, 3080, 3478, 8000, 8080, 8090, 8443,
9000, 9443, 11000.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
"network proxy declared as external, but could not be found".
Die Hauptdatei verlangte ein externes Netz namens proxy, das es auf diesem
Server gar nicht gibt — und die Ergaenzung fuer host.docker.internal half
nicht, weil die Basis es trotzdem forderte. Das war die falsche Reihenfolge:
der Weg nach aussen ist gerade das, was sich je Aufbau unterscheidet, und
gehoert damit nicht in die Basis.
Jetzt ist docker-compose.yml neutral — von aussen nicht erreichbar, und das
ausdruecklich. Dazu waehlt man eine von zwei Ergaenzungen:
docker-compose.proxynet.yml Proxy haengt im selben Netz (http://minio:9000)
docker-compose.hostports.yml Proxy geht ueber den Host
Die Netzliste dieses Servers zeigt kein "proxy", aber ein "web" — ein
Bridge-Netz ohne Stack, also die uebliche Konvention fuer einen Reverse Proxy.
PROXY_NETWORK steht deshalb auf "web", mit dem Hinweis, es nachzusehen statt zu
glauben.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
'docker.io/fivemanage/lite:0.1.0-beta.23: not found' — und zwar zu Recht.
Ich hatte die Registry aus deren docker-compose.test.yml uebernommen
(fivemanage/lite:latest, also Docker Hub) und den Tag aus den GitHub-Releases
(beta.23). Jede Haelfte fuer sich stimmte, die Kombination nicht.
Nachgesehen statt geraten:
ghcr.io/fivemanage/lite beta.18 bis beta.23 und latest
docker.io/fivemanage/lite endet bei beta.16
Docker Hub wird offenbar nicht mehr gepflegt. Das README des Projekts hat es
richtig: dort steht ghcr.io.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Der bisherige Befehl war Bash und lief in Windows PowerShell 5.1 nicht — dort
gibt es weder printf noch openssl. Die PowerShell-Fassung steht jetzt zuerst,
Bash daneben.
Zwei Fallen sind darin vermerkt, beide bereits hineingetreten:
RandomNumberGenerator::Fill gibt es erst ab .NET 6; Windows PowerShell 5.1
laeuft auf .NET Framework und kennt nur ::Create().GetBytes().
Set-Content -Encoding utf8 schreibt in 5.1 ein BOM voran. Dann heisst die
erste Variable nicht DB_PASSWORD, und der Stack startet mit einer fehlenden
Angabe, deren Grund man nicht sieht. Der Inhalt ist ohnehin ASCII.
Dazu der Hinweis, dass Get-Random hier nicht taugt: es ist nicht
kryptografisch sicher, und erzeugt wird ein Token-Signaturgeheimnis.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Die Compose war fuer den sauberen Weg gebaut: NPM im selben Netz, kein Port
offen. Auf diesem Server laeuft NPM aber anders — Bot und Hub haengen dort an
`http://host.docker.internal:3080`, also ueber den Host. So wie sie war, haette
NPM `minio` gar nicht gefunden.
docker-compose.hostports.yml legt deshalb die beiden noetigen Ports offen, und
zwar an 127.0.0.1 gebunden: damit ist der Port vom Internet aus zu, und nur der
Host kommt heran.
Mit einem Vorbehalt, der in der Datei steht: ob `host.docker.internal` eine
Bindung an 127.0.0.1 ueberhaupt erreicht, haengt an der Docker-Fassung. Unter
Linux fuehrt der Weg ueber die Docker-Bruecke statt ueber Loopback, dann muss
die Bindung 0.0.0.0 lauten und die Firewall den Port zumachen. Klappt es nicht,
ist die Bindung nicht der Fehler, sondern der Weg.
Sauberer bleibt Weg A — NPM ins Netz `proxy` haengen. Dann braucht es diese
Datei gar nicht.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Ein Ablageort fuer alle Resourcen statt Nextcloud plus rclone von Hand. Der
Unterschied ist nicht der Speicher — den gibt es schon — sondern ein
Schreibweg ueber HTTP: sobald ein Script hochladen soll, fehlt er, und Lite
bringt ihn mit, samt Token je Resource und einer Oberflaeche zum Nachsehen.
Zusammengestellt aus fivemanage/lite: dessen README, der
deployments/docker-compose.yml (Entwicklung, startet die App gar nicht) und der
deployments/docker-compose.test.yml (zeigt die App-Verdrahtung und dass MySQL
genuegt und ClickHouse nicht Pflicht ist).
Zwei Fassungen, und der Unterschied ist Absicht:
docker-compose.yml fuer den Betrieb ueber Portainer aus diesem Repo.
Keine offenen Ports, nur der Reverse Proxy
spricht mit der App.
docker-compose.local.yml zum Ausprobieren auf Docker Desktop. Ports offen,
kein Proxy. Eine beta.23 gehoert erst auf einen
Rechner, an dem nichts haengt.
Ohne ClickHouse und Jaeger: beides ist Logging und Tracing, fuer das Ablegen
von Bildern nicht noetig, und ClickHouse ist eine schwere Abhaengigkeit.
Ein Init-Container legt den Bucket an und stellt ihn auf oeffentlich lesbar.
Ohne diesen Schritt schlaegt der erste Upload fehl, und die Meldung nennt den
Grund nicht.
Healthchecks mit depends_on/condition, sonst startet die App gegen eine
Datenbank, die noch nicht antwortet, und beendet sich — beim ersten Hochfahren
jedes Mal.
NICHT laufen gelassen: Docker war von hier nicht erreichbar. Das YAML ist
geprueft, das Compose-Schema nicht.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>