Kein alter Stand mehr im Zwischenspeicher, Einsetzer heisst HoneyBar-Proxy

Die HoneyBar kommt bei fremden Apps ueber deren eigenen Ursprung — das
loest CSP, CORS und COEP auf einmal, setzt sie aber auch deren Zwischen-
speicher aus. Eine alte HoneyBar dort sieht aus wie ein Fehler in HoneyOS.
Statt no-cache jetzt no-store, must-revalidate; dazu ein Abschnitt in der
README, wie man einen haengengebliebenen Stand erkennt.

Und der nginx davor heisst nicht mehr 'Einsetzer', sondern HoneyBar-Proxy
(Dienst und Behaelter honeybar-proxy bzw. <app>-honeybar). Er ist ein
Reverse Proxy, der die HoneyBar einsetzt — der alte Name sagte das
Gegenteil von dem, was man im docker ps sehen will. LEISTE_PORT heisst
jetzt HONEYBAR_PROXY_PORT.
This commit is contained in:
marc committed 2026-08-29 22:36:56 +02:00
1 parent 53ab62d220
commit 6fe6533667
4 files changed
+63 -33

No files matched your search

+34 -10
View File
@@ -229,7 +229,7 @@ hinein, ihre Stile nicht hinaus. Sie schiebt den Seiteninhalt um 32 px nach unte
Vorschau ohne Einbau: `/honeybar/demo.html`.
### Weg 2 — fertige Apps: ein Einsetzer davor
### Weg 2 — fertige Apps: ein HoneyBar-Proxy davor
Für Werkzeuge, die man **nicht selbst geschrieben hat**, gibt es keinen
`<script>`-Tag zum Ändern — den setzt ein kleiner nginx ein, während er die
@@ -295,7 +295,7 @@ schickt — und das tun die meisten:
| `HONEYOS_APPS_KEY` | steht im Quelltext der Seite | **bleibt auf dem Server** |
| Aufwand | eine `sub_filter`-Zeile | drei `location`-Blöcke |
Bei der zweiten reicht der Einsetzer auch `/honeybar/` und die zwei Abfragen der
Bei der zweiten reicht der HoneyBar-Proxy auch `/honeybar/` und die zwei Abfragen der
HoneyBar durch, unter *seiner* Adresse. Für den Browser ist damit alles derselbe
Ursprung, und die drei Hürden fallen auf einmal weg. Durchgereicht werden dabei
**nur** `/api/apps` und `/api/weather`, und nur lesend (`limit_except GET`) —
@@ -328,29 +328,29 @@ services:
networks:
honeybar:
external: true # legt der Einsetzer-Stapel an
external: true # legt der HoneyBar-Proxy-Stapel an
```
Zwei Änderungen, mehr nicht:
1. **`ports:` fällt weg.** Die App braucht kein Loch nach außen mehr — der
Einsetzer spricht sie im Docker-Netz unter ihrem Namen an (`bentopdf:8080`;
HoneyBar-Proxy spricht sie im Docker-Netz unter ihrem Namen an (`bentopdf:8080`;
die `8080` ist der Port *im* Behälter und bleibt, die `8888` war nur die
Klinke an der Außenseite). Ginge Pangolin weiter direkt auf die App, wäre der
Einsetzer umgangen und die HoneyBar fehlte. Zum Nachsehen darf ein `ports:`
HoneyBar-Proxy umgangen und die HoneyBar fehlte. Zum Nachsehen darf ein `ports:`
ruhig stehen bleiben — dann hast du zwei Wege: direkt ohne HoneyBar, über
Pangolin mit.
2. **Das Netz `honeybar` dazu.** Es entsteht im Einsetzer-Stapel; hier wird es
2. **Das Netz `honeybar` dazu.** Es entsteht im HoneyBar-Proxy-Stapel; hier wird es
nur als `external` mitbenutzt. Deshalb jenen Stapel zuerst starten.
Dazu noch zwei Zeilen im Einsetzer (`$ziel` und `$appid`) und in Pangolin die
Dazu noch zwei Zeilen im HoneyBar-Proxy (`$ziel` und `$appid`) und in Pangolin die
Ressource von der App auf `honeybar:80` umstellen. Fertig.
#### Was es kostet
Nicht viel, aber nicht nichts:
- **Ein Ausfallpunkt mehr.** Ist der Einsetzer weg, sind die Apps dahinter weg —
- **Ein Ausfallpunkt mehr.** Ist der HoneyBar-Proxy weg, sind die Apps dahinter weg —
nicht nur ihre HoneyBar. `restart: unless-stopped` ist deshalb Pflicht; ein
nginx, der nur durchreicht, fällt praktisch nie aus.
- **Eine Stelle mehr zum Pflegen.** Je App zwei Zeilen, und beim Umbenennen
@@ -366,7 +366,7 @@ Nicht viel, aber nicht nichts:
strenge CSP und COEP mitbringt: HoneyBar, Apps und Wetter erscheinen, ohne dass
an dessen Kopfzeilen etwas geändert wird.
- [`beispiele/mehrere-apps/`](beispiele/mehrere-apps/) — **HoneyOS und ein
Einsetzer für beliebig viele Dienste in einem Stapel.** Zwei Tabellen oben in
HoneyBar-Proxy für beliebig viele Dienste in einem Stapel.** Zwei Tabellen oben in
der Datei sagen, welcher Name zu welchem Behälter gehört und welche App das
für HoneyOS ist; eine neue App sind zwei Zeilen. Die HoneyBar hebt die aktuelle
App hervor, sobald `$appid` der `ID` in der App-Liste entspricht — genau wie
@@ -378,7 +378,7 @@ Nicht viel, aber nicht nichts:
Das Netz `honeybar` legt dieser Stapel selbst an, unter festem Namen. Die
fremden Dienste treten ihm bei (`networks: [default, honeybar]` und
`honeybar: {external: true}`); ihre eigenen `ports:` können dann ganz weg,
erreichbar ist nur noch der Einsetzer. Deshalb diesen Stapel zuerst starten. Ein Host, der in der Tabelle fehlt, bekommt **404** statt einer
erreichbar ist nur noch der HoneyBar-Proxy. Deshalb diesen Stapel zuerst starten. Ein Host, der in der Tabelle fehlt, bekommt **404** statt einer
geratenen Weiterleitung — sonst wird aus einem Tippfehler in Pangolin eine
stille Umleitung irgendwohin. WebSocket-Verbindungen (Uptime Kuma, Dashboards,
alles mit Live-Anzeige) gehen durch, dafür sorgt `upgrade.conf`.
@@ -443,6 +443,30 @@ eingebettetes Bild einer fremden Seite eine Abmeldung auslösen. Der Punkt
erscheint nur, wenn HoneyOS selbst anmeldet; hinter einem Proxy oder im offenen
Betrieb fehlt er.
## Wenn die HoneyBar veraltet aussieht
Die HoneyBar wird bei Weg 2 über den **eigenen Ursprung der App** ausgeliefert
(`/honeybar/honeybar.js`). Das ist der Kniff, der CSP, CORS und COEP auf einmal
erledigt — es setzt sie aber zugleich dem Zwischenspeicher dieser App aus, und
dem ihres Service Workers, falls sie einen hat. Eine alte HoneyBar dort sieht
aus wie ein Fehler in HoneyOS: Ein neuer Menüpunkt fehlt, obwohl der
Schreibtisch ihn längst hat.
HoneyOS liefert seine Dateien deshalb mit `Cache-Control: no-store` aus. Bleibt
trotzdem etwas hängen, hilft die Probe von Hand:
```bash
curl -s https://<app-adresse>/honeybar/honeybar.js | grep -c sysmenu
```
Kommt dort **0**, ist die ausgelieferte Datei alt — dann läuft HoneyOS noch auf
einem älteren Abbild (`docker compose pull && up -d`). Kommt **2**, liegt es am
Browser: einmal hart neu laden (Strg+Umschalt+R), und bei einer installierten
PWA deren Daten löschen.
**Am schnellsten zu sehen ohne Werkzeug:** Stehen im App-Streifen der HoneyBar
Symbole neben den Namen? Dann ist sie aktuell.
## Wer angemeldet ist
Steht auf dem Schreibtisch, als eigenes Widget: Bild, Name und Begrüßung, aus
+10 -10
View File
@@ -1,7 +1,7 @@
# ─────────────────────────────────────────────────────────────────────────────
# BentoPDF mit HoneyBar — alles über den eigenen Ursprung.
#
# Pangolin → einsetzer → bentopdf
# Pangolin → honeybar-proxy → bentopdf
# ↘ honeyos (nur /honeybar/ und zwei Abfragen)
#
# Der Kniff: Die HoneyBar wird nicht von honeyos.… geladen, sondern über die
@@ -16,7 +16,7 @@
# im Quelltext der Seite steht er nicht.
#
# docker compose up -d
# → in Pangolin die Ressource auf einsetzer:80 zeigen lassen,
# → in Pangolin die Ressource auf honeybar-proxy:80 zeigen lassen,
# und in HoneyOS BentoPDF als App eintragen (ID: bentopdf, URL: die
# öffentliche Adresse, exakt so, wie du sie im Browser aufrufst).
# ─────────────────────────────────────────────────────────────────────────────
@@ -25,13 +25,13 @@ services:
image: ghcr.io/alam00000/bentopdf-simple:latest
container_name: bentopdf
restart: unless-stopped
# Kein ports: nötig — erreichbar ist nur noch der Einsetzer davor.
# Kein ports: nötig — erreichbar ist nur noch der HoneyBar-Proxy davor.
# (Zum direkten Nachsehen ohne HoneyBar ruhig eins lassen.)
networks: [honeybar]
einsetzer:
honeybar-proxy:
image: nginx:alpine
container_name: bentopdf-einsetzer
container_name: bentopdf-honeybar
restart: unless-stopped
depends_on: [bentopdf]
ports:
@@ -39,15 +39,15 @@ services:
# Pangolin auf demselben Wirt im Host-Netz läuft — hängt es in einem
# eigenen Behälter oder auf einer anderen Maschine, kommt es dort nicht
# hin. Am saubersten: kein ports:, und Pangolin (bzw. sein Newt) tritt
# dem Netz `honeybar` bei und spricht `einsetzer:80` direkt an.
- "${LEISTE_PORT:-8185}:80"
# dem Netz `honeybar` bei und spricht `honeybar-proxy:80` direkt an.
- "${HONEYBAR_PROXY_PORT:-8185}:80"
configs:
- source: einsetzer
- source: honeybar
target: /etc/nginx/conf.d/default.conf
networks: [honeybar]
configs:
einsetzer:
honeybar:
# `$$` ist hier ein einfaches `$` für nginx. Ein einzelnes `$` setzt
# dagegen Compose ein — genau das ist bei ${HONEYOS_APPS_KEY} gewollt:
# der Schlüssel kommt aus der .env und landet nur in der Konfiguration
@@ -60,7 +60,7 @@ configs:
resolver 127.0.0.11 valid=30s ipv6=off;
# Uploads nicht hier begrenzen — nginx nimmt sonst bei 1 MB nichts
# mehr an, und jede App mit Dateiupload waere hinter dem Einsetzer
# mehr an, und jede App mit Dateiupload waere hinter dem HoneyBar-Proxy
# kaputt. Wieviel erlaubt ist, entscheidet die App dahinter.
client_max_body_size 0;
+12 -12
View File
@@ -1,22 +1,22 @@
# ─────────────────────────────────────────────────────────────────────────────
# HoneyOS und ein Einsetzer für beliebig viele fremde Dienste.
# HoneyOS und ein HoneyBar-Proxy für beliebig viele fremde Dienste.
#
# außen ──► Pangolin ──► honeyos (der Schreibtisch)
# Pangolin ──► einsetzer ──► bentopdf:8080 (App mit HoneyBar)
# Pangolin ──► honeybar-proxy ──► bentopdf:8080 (App mit HoneyBar)
# │ ──► uptime-kuma:3001
# └──► honeyos:8080 (HoneyBar + zwei Abfragen)
#
# Die fremden Dienste brauchen kein `ports:` mehr — erreichbar sind sie über
# ihren Namen im Netz `honeybar`, und nach außen führt nur der Einsetzer.
# ihren Namen im Netz `honeybar`, und nach außen führt nur der HoneyBar-Proxy.
#
# Eine neue App hinzufügen heißt: zwei Zeilen in den Tabellen `$ziel` und
# `$appid`, dann `docker compose up -d --force-recreate einsetzer`.
# `$appid`, dann `docker compose up -d --force-recreate honeybar-proxy`.
#
# cp ../../.env.example .env && ausfüllen (HONEYOS_APPS_KEY setzen!)
# mkdir -p daten && sudo chown 1000:1000 daten
# docker compose up -d
#
# Danach in Pangolin: honeyos.… → honeyos:8080, jede App → einsetzer:80.
# Danach in Pangolin: honeyos.… → honeyos:8080, jede App → honeybar-proxy:80.
# Und in HoneyOS jede App eintragen — die `ID` dort muss dem `$appid` hier
# entsprechen, sonst weiß die HoneyBar nicht, in welcher App man gerade ist.
# ─────────────────────────────────────────────────────────────────────────────
@@ -45,21 +45,21 @@ services:
- HONEYOS_APPS_KEY=${HONEYOS_APPS_KEY:-}
networks: [honeybar]
einsetzer:
honeybar-proxy:
image: nginx:alpine
container_name: honeybar-einsetzer
container_name: honeybar-proxy
restart: unless-stopped
ports:
- "${LEISTE_PORT:-8185}:80"
- "${HONEYBAR_PROXY_PORT:-8185}:80"
configs:
- source: einsetzer
- source: honeybar
target: /etc/nginx/conf.d/default.conf
networks: [honeybar]
# Kein depends_on: Der Einsetzer reicht nur durch. Ist HoneyOS aus, fehlt
# Kein depends_on: Der HoneyBar-Proxy reicht nur durch. Ist HoneyOS aus, fehlt
# die HoneyBar — die Apps laufen weiter.
configs:
einsetzer:
honeybar:
# `$$` ist hier ein einfaches `$` für nginx. Ein einzelnes `$` setzt
# dagegen Compose ein — genau das ist bei ${HONEYOS_APPS_KEY} gewollt: der
# Schlüssel steht damit nur in der nginx-Konfiguration, nie in der Seite.
@@ -97,7 +97,7 @@ configs:
if ($$ziel = "") { return 404; }
# Uploads nicht hier begrenzen — nginx nimmt sonst bei 1 MB nichts
# mehr an, und jede App mit Dateiupload waere hinter dem Einsetzer
# mehr an, und jede App mit Dateiupload waere hinter dem HoneyBar-Proxy
# kaputt. Wieviel erlaubt ist, entscheidet die App dahinter.
client_max_body_size 0;
+7 -1
View File
@@ -224,7 +224,13 @@ func (s *Server) cors(next http.Handler) http.Handler {
func noCache(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Cache-Control", "no-cache")
// no-store, nicht no-cache: Die Oberflaeche und vor allem honeybar.js
// muessen bei jedem Aufruf frisch kommen. Sie werden ueber den eigenen
// Ursprung der fremden App ausgeliefert und geraten damit in deren
// Zwischenspeicher — und in den ihres Service Workers, falls sie einen
// hat. Eine alte HoneyBar dort ist von aussen nicht zu erkennen: Sie
// sieht aus wie ein Fehler in HoneyOS.
w.Header().Set("Cache-Control", "no-store, must-revalidate")
// Die HoneyBar wird von fremden Ursprüngen geladen — das ist ihr Zweck.
// Apps, die selbst COEP „require-corp" setzen (alles mit WASM oder
// SharedArrayBuffer, etwa BentoPDF), lehnen sonst jede fremde Datei ab,