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`. 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 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 `<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** | | `HONEYOS_APPS_KEY` | steht im Quelltext der Seite | **bleibt auf dem Server** |
| Aufwand | eine `sub_filter`-Zeile | drei `location`-Blöcke | | 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 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 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`) — **nur** `/api/apps` und `/api/weather`, und nur lesend (`limit_except GET`) —
@@ -328,29 +328,29 @@ services:
networks: networks:
honeybar: honeybar:
external: true # legt der Einsetzer-Stapel an external: true # legt der HoneyBar-Proxy-Stapel an
``` ```
Zwei Änderungen, mehr nicht: Zwei Änderungen, mehr nicht:
1. **`ports:` fällt weg.** Die App braucht kein Loch nach außen mehr — der 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 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 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 ruhig stehen bleiben — dann hast du zwei Wege: direkt ohne HoneyBar, über
Pangolin mit. 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. 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. Ressource von der App auf `honeybar:80` umstellen. Fertig.
#### Was es kostet #### Was es kostet
Nicht viel, aber nicht nichts: 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 nicht nur ihre HoneyBar. `restart: unless-stopped` ist deshalb Pflicht; ein
nginx, der nur durchreicht, fällt praktisch nie aus. nginx, der nur durchreicht, fällt praktisch nie aus.
- **Eine Stelle mehr zum Pflegen.** Je App zwei Zeilen, und beim Umbenennen - **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 strenge CSP und COEP mitbringt: HoneyBar, Apps und Wetter erscheinen, ohne dass
an dessen Kopfzeilen etwas geändert wird. an dessen Kopfzeilen etwas geändert wird.
- [`beispiele/mehrere-apps/`](beispiele/mehrere-apps/) — **HoneyOS und ein - [`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 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 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 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 Das Netz `honeybar` legt dieser Stapel selbst an, unter festem Namen. Die
fremden Dienste treten ihm bei (`networks: [default, honeybar]` und fremden Dienste treten ihm bei (`networks: [default, honeybar]` und
`honeybar: {external: true}`); ihre eigenen `ports:` können dann ganz weg, `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 geratenen Weiterleitung — sonst wird aus einem Tippfehler in Pangolin eine
stille Umleitung irgendwohin. WebSocket-Verbindungen (Uptime Kuma, Dashboards, stille Umleitung irgendwohin. WebSocket-Verbindungen (Uptime Kuma, Dashboards,
alles mit Live-Anzeige) gehen durch, dafür sorgt `upgrade.conf`. 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 erscheint nur, wenn HoneyOS selbst anmeldet; hinter einem Proxy oder im offenen
Betrieb fehlt er. 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 ## Wer angemeldet ist
Steht auf dem Schreibtisch, als eigenes Widget: Bild, Name und Begrüßung, aus 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. # BentoPDF mit HoneyBar — alles über den eigenen Ursprung.
# #
# Pangolin → einsetzer → bentopdf # Pangolin → honeybar-proxy → bentopdf
# ↘ honeyos (nur /honeybar/ und zwei Abfragen) # ↘ honeyos (nur /honeybar/ und zwei Abfragen)
# #
# Der Kniff: Die HoneyBar wird nicht von honeyos.… geladen, sondern über die # Der Kniff: Die HoneyBar wird nicht von honeyos.… geladen, sondern über die
@@ -16,7 +16,7 @@
# im Quelltext der Seite steht er nicht. # im Quelltext der Seite steht er nicht.
# #
# docker compose up -d # 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 # und in HoneyOS BentoPDF als App eintragen (ID: bentopdf, URL: die
# öffentliche Adresse, exakt so, wie du sie im Browser aufrufst). # öffentliche Adresse, exakt so, wie du sie im Browser aufrufst).
# ───────────────────────────────────────────────────────────────────────────── # ─────────────────────────────────────────────────────────────────────────────
@@ -25,13 +25,13 @@ services:
image: ghcr.io/alam00000/bentopdf-simple:latest image: ghcr.io/alam00000/bentopdf-simple:latest
container_name: bentopdf container_name: bentopdf
restart: unless-stopped 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.) # (Zum direkten Nachsehen ohne HoneyBar ruhig eins lassen.)
networks: [honeybar] networks: [honeybar]
einsetzer: honeybar-proxy:
image: nginx:alpine image: nginx:alpine
container_name: bentopdf-einsetzer container_name: bentopdf-honeybar
restart: unless-stopped restart: unless-stopped
depends_on: [bentopdf] depends_on: [bentopdf]
ports: ports:
@@ -39,15 +39,15 @@ services:
# Pangolin auf demselben Wirt im Host-Netz läuft — hängt es in einem # 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 # eigenen Behälter oder auf einer anderen Maschine, kommt es dort nicht
# hin. Am saubersten: kein ports:, und Pangolin (bzw. sein Newt) tritt # hin. Am saubersten: kein ports:, und Pangolin (bzw. sein Newt) tritt
# dem Netz `honeybar` bei und spricht `einsetzer:80` direkt an. # dem Netz `honeybar` bei und spricht `honeybar-proxy:80` direkt an.
- "${LEISTE_PORT:-8185}:80" - "${HONEYBAR_PROXY_PORT:-8185}:80"
configs: configs:
- source: einsetzer - source: honeybar
target: /etc/nginx/conf.d/default.conf target: /etc/nginx/conf.d/default.conf
networks: [honeybar] networks: [honeybar]
configs: configs:
einsetzer: honeybar:
# `$$` ist hier ein einfaches `$` für nginx. Ein einzelnes `$` setzt # `$$` ist hier ein einfaches `$` für nginx. Ein einzelnes `$` setzt
# dagegen Compose ein — genau das ist bei ${HONEYOS_APPS_KEY} gewollt: # dagegen Compose ein — genau das ist bei ${HONEYOS_APPS_KEY} gewollt:
# der Schlüssel kommt aus der .env und landet nur in der Konfiguration # 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; resolver 127.0.0.11 valid=30s ipv6=off;
# Uploads nicht hier begrenzen — nginx nimmt sonst bei 1 MB nichts # 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. # kaputt. Wieviel erlaubt ist, entscheidet die App dahinter.
client_max_body_size 0; 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) # außen ──► Pangolin ──► honeyos (der Schreibtisch)
# Pangolin ──► einsetzer ──► bentopdf:8080 (App mit HoneyBar) # Pangolin ──► honeybar-proxy ──► bentopdf:8080 (App mit HoneyBar)
# │ ──► uptime-kuma:3001 # │ ──► uptime-kuma:3001
# └──► honeyos:8080 (HoneyBar + zwei Abfragen) # └──► honeyos:8080 (HoneyBar + zwei Abfragen)
# #
# Die fremden Dienste brauchen kein `ports:` mehr — erreichbar sind sie über # 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 # 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!) # cp ../../.env.example .env && ausfüllen (HONEYOS_APPS_KEY setzen!)
# mkdir -p daten && sudo chown 1000:1000 daten # mkdir -p daten && sudo chown 1000:1000 daten
# docker compose up -d # 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 # 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. # entsprechen, sonst weiß die HoneyBar nicht, in welcher App man gerade ist.
# ───────────────────────────────────────────────────────────────────────────── # ─────────────────────────────────────────────────────────────────────────────
@@ -45,21 +45,21 @@ services:
- HONEYOS_APPS_KEY=${HONEYOS_APPS_KEY:-} - HONEYOS_APPS_KEY=${HONEYOS_APPS_KEY:-}
networks: [honeybar] networks: [honeybar]
einsetzer: honeybar-proxy:
image: nginx:alpine image: nginx:alpine
container_name: honeybar-einsetzer container_name: honeybar-proxy
restart: unless-stopped restart: unless-stopped
ports: ports:
- "${LEISTE_PORT:-8185}:80" - "${HONEYBAR_PROXY_PORT:-8185}:80"
configs: configs:
- source: einsetzer - source: honeybar
target: /etc/nginx/conf.d/default.conf target: /etc/nginx/conf.d/default.conf
networks: [honeybar] 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. # die HoneyBar — die Apps laufen weiter.
configs: configs:
einsetzer: honeybar:
# `$$` ist hier ein einfaches `$` für nginx. Ein einzelnes `$` setzt # `$$` ist hier ein einfaches `$` für nginx. Ein einzelnes `$` setzt
# dagegen Compose ein — genau das ist bei ${HONEYOS_APPS_KEY} gewollt: der # 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. # Schlüssel steht damit nur in der nginx-Konfiguration, nie in der Seite.
@@ -97,7 +97,7 @@ configs:
if ($$ziel = "") { return 404; } if ($$ziel = "") { return 404; }
# Uploads nicht hier begrenzen — nginx nimmt sonst bei 1 MB nichts # 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. # kaputt. Wieviel erlaubt ist, entscheidet die App dahinter.
client_max_body_size 0; 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 { func noCache(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 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. // Die HoneyBar wird von fremden Ursprüngen geladen — das ist ihr Zweck.
// Apps, die selbst COEP „require-corp" setzen (alles mit WASM oder // Apps, die selbst COEP „require-corp" setzen (alles mit WASM oder
// SharedArrayBuffer, etwa BentoPDF), lehnen sonst jede fremde Datei ab, // SharedArrayBuffer, etwa BentoPDF), lehnen sonst jede fremde Datei ab,