diff --git a/README.md b/README.md
index 103b66b..bc2cf61 100644
--- a/README.md
+++ b/README.md
@@ -256,11 +256,14 @@ Adresse der App.
strenge CSP und COEP mitbringt: Leiste, 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 alle Dienste in einem Stapel.** Am Host erkennt nginx, welcher
+ Einsetzer 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 Leiste hebt die aktuelle
+ App hervor, sobald `$appid` der `id` in der App-Liste entspricht — genau wie
+ in Aether und InkNote. Am Host erkennt nginx, welcher
Dienst gemeint ist; eine neue App sind zwei Zeilen in den Tabellen oben in
`leiste.conf`. Das ist der Aufbau, den man haben will, sobald es mehr als ein
- Werkzeug ist — nicht ein Behälter je App, und nicht HoneyOS getrennt davon
- gepflegt.
+ Nicht ein Behälter je App, und nicht HoneyOS getrennt davon gepflegt.
Das Netz `honeybar` legt dieser Stapel selbst an, unter festem Namen. Die
fremden Dienste treten ihm bei (`networks: [default, honeybar]` und
diff --git a/beispiele/mehrere-apps/docker-compose.yml b/beispiele/mehrere-apps/docker-compose.yml
index 7505fef..eba4c31 100644
--- a/beispiele/mehrere-apps/docker-compose.yml
+++ b/beispiele/mehrere-apps/docker-compose.yml
@@ -1,29 +1,24 @@
# ─────────────────────────────────────────────────────────────────────────────
-# HoneyOS und der Einsetzer in einem Stapel.
+# HoneyOS und ein Einsetzer für beliebig viele fremde Dienste.
#
-# Pangolin → honeyos (der Schreibtisch selbst)
-# Pangolin → leiste → bentopdf, kuma, … (fremde Dienste mit Leiste)
+# außen ──► Pangolin ──► honeyos (der Schreibtisch)
+# Pangolin ──► leiste ──► bentopdf:8080 (App mit Leiste)
+# │ ──► uptime-kuma:3001
+# └──► honeyos:8080 (Leiste + zwei Abfragen)
#
-# Beides gehört zusammen: Die Leiste kommt von HoneyOS, der Einsetzer trägt sie
-# in Werkzeuge, die man nicht ändern kann. Getrennt zu pflegen hiesse, bei jeder
-# neuen App an zwei Stellen zu denken.
+# 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.
#
-# cp ../../.env.example .env && ausfüllen
+# Eine neue App hinzufügen heißt: zwei Zeilen in den Tabellen `$ziel` und
+# `$appid`, dann `docker compose up -d --force-recreate leiste`.
+#
+# cp ../../.env.example .env && ausfüllen (HONEYOS_APPS_KEY setzen!)
# mkdir -p daten && sudo chown 1000:1000 daten
# docker compose up -d
#
-# Das Netz `honeybar` legt dieser Stapel selbst an — die fremden Dienste treten
-# ihm bei. In deren Compose-Datei:
-#
-# services:
-# bentopdf:
-# networks: [default, honeybar] # ports: kann dann ganz weg
-# networks:
-# honeybar:
-# external: true
-#
-# Diesen Stapel deshalb zuerst starten; danach die anderen.
-# In Pangolin zeigt honeyos.… auf honeyos:8080 und jede App auf leiste:80.
+# Danach in Pangolin: honeyos.… → honeyos:8080, jede App → leiste:80.
+# Und in HoneyOS jede App eintragen — die `id` dort muss dem `$appid` hier
+# entsprechen, sonst weiß die Leiste nicht, in welcher App man gerade ist.
# ─────────────────────────────────────────────────────────────────────────────
services:
@@ -33,8 +28,7 @@ services:
restart: unless-stopped
user: "1000:1000"
ports:
- # Nur an localhost: davor steht Pangolin, nicht das offene Netz.
- - "127.0.0.1:${HONEYOS_PORT:-8088}:8080"
+ - "${HONEYOS_PORT:-8088}:8080"
volumes:
- ${HONEYOS_DATA_DIR:-./daten}:/data
environment:
@@ -55,73 +49,75 @@ services:
image: nginx:alpine
container_name: honeybar-leiste
restart: unless-stopped
- # Die beiden nginx-Dateien stehen als `configs` unten **in dieser Datei**.
- #
- # Mit Bind-Mounts (`./leiste.conf:/etc/nginx/…`) müssten sie auf dem Wirt
- # liegen — und fehlt eine, legt Docker dort wortlos ein *Verzeichnis* an
- # und scheitert beim nächsten Start mit „not a directory". Beim Einsetzen
- # über eine Oberfläche, wo man nur die Compose-Datei bearbeitet, ist das
- # eine Falle ohne Nutzen.
+ ports:
+ - "${LEISTE_PORT:-8185}:80"
configs:
- - source: upgrade
- target: /etc/nginx/conf.d/00-upgrade.conf
- source: leiste
target: /etc/nginx/conf.d/default.conf
- ports:
- - "127.0.0.1:${LEISTE_PORT:-8185}:80"
networks: [honeybar]
- # Der Einsetzer braucht HoneyOS nicht zum Starten — er reicht nur durch und
- # setzt eine Zeile ein. Ist HoneyOS aus, fehlt die Leiste, die App läuft.
+ # Kein depends_on: Der Einsetzer reicht nur durch. Ist HoneyOS aus, fehlt
+ # die Leiste — die Apps laufen weiter.
configs:
- # Achtung beim Ändern: `$$` ist hier ein einfaches `$` für nginx. Ein
- # einzelnes `$` würde Compose als eigene Variable lesen und leeren.
- upgrade:
+ leiste:
+ # `$$` 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.
content: |
- # Gehört nach /etc/nginx/conf.d/, aber ausserhalb eines server-Blocks:
- # „Connection: upgrade" nur dann setzen, wenn der Browser das auch will.
+ # ── Welcher Dienst steckt hinter welchem Namen ────────────────────────
+ # Links die Adresse, unter der du die App aufrufst; rechts Behältername
+ # und Port im Docker-Netz.
+ map $$host $$ziel {
+ default "";
+ pdf.honeyos.duckdns.org "bentopdf:8080";
+ status.honeyos.duckdns.org "uptime-kuma:3001";
+ }
+
+ # ── Und welche App das für HoneyOS ist ────────────────────────────────
+ # Muss der `id` in der App-Liste entsprechen. Daran erkennt die Leiste,
+ # wo man gerade ist, und hebt den Eintrag hervor — wie in Aether.
+ map $$host $$appid {
+ default "";
+ pdf.honeyos.duckdns.org "bentopdf";
+ status.honeyos.duckdns.org "status";
+ }
+
map $$http_upgrade $$connection_upgrade {
default upgrade;
'' close;
}
- leiste:
- content: |
- # ─────────────────────────────────────────────────────────────────────────────
- # Ein Einsetzer für alle Dienste, die die Leiste tragen sollen.
- #
- # Pangolin gibt den ursprünglichen Host weiter; daran erkennt nginx, welcher
- # Dienst gemeint ist. Eine neue App heisst: zwei Zeilen in den Tabellen unten,
- # neu laden, fertig — kein weiterer Behälter.
- # ─────────────────────────────────────────────────────────────────────────────
-
- # Wohin durchgereicht wird. Links der Name, unter dem du die App aufrufst,
- # rechts Behältername und Port im Docker-Netz.
- map $$host $$ziel {
- default "";
- pdf.honeyos.duckdns.org "bentopdf:8080";
- status.honeyos.duckdns.org "uptime-kuma:3001";
- }
-
- # Welche App das für HoneyOS ist. Muss der id in der App-Liste entsprechen —
- # daran erkennt die Leiste, wo man gerade ist, und hebt sie hervor.
- map $$host $$appid {
- default "";
- pdf.honeyos.duckdns.org "bentopdf";
- status.honeyos.duckdns.org "status";
- }
server {
listen 80;
server_name _;
-
- # Für ein proxy_pass mit Variable braucht nginx einen Namensauflöser —
- # im Docker-Netz ist das der eingebaute unter 127.0.0.11.
resolver 127.0.0.11 valid=30s ipv6=off;
- # Unbekannter Host: nicht raten, sondern ablehnen. Sonst wird aus einem
- # Tippfehler in Pangolin eine stille Weiterleitung irgendwohin.
+ # Unbekannter Name: nicht raten. Sonst wird aus einem Tippfehler in
+ # Pangolin eine stille Weiterleitung irgendwohin.
if ($$ziel = "") { return 404; }
+ # ── Die Leiste, durchgereicht über DIESE Adresse ──────────────────
+ # Dadurch ist sie für den Browser eigener Ursprung: Die CSP der App
+ # bleibt unangetastet, CORS und COEP entfallen.
+ location /honeybar/ {
+ proxy_pass http://honeyos:8080/honeybar/;
+ }
+
+ # Ihre zwei Abfragen — einzeln benannt und nur lesend. Ein pauschales
+ # /api/ hinge die ganze HoneyOS-Schnittstelle unter die Adresse der
+ # App. Den Ausweis setzt der Server ein.
+ location = /honeyos-api/apps {
+ limit_except GET { deny all; }
+ proxy_pass http://honeyos:8080/api/apps;
+ proxy_set_header X-HoneyOS-Key "${HONEYOS_APPS_KEY}";
+ }
+ location = /honeyos-api/weather {
+ limit_except GET { deny all; }
+ proxy_pass http://honeyos:8080/api/weather;
+ proxy_set_header X-HoneyOS-Key "${HONEYOS_APPS_KEY}";
+ }
+
+ # ── Die App selbst ───────────────────────────────────────────────
location / {
proxy_pass http://$$ziel;
proxy_set_header Host $$host;
@@ -129,22 +125,18 @@ configs:
proxy_set_header X-Forwarded-Proto $$scheme;
proxy_set_header X-Real-IP $$remote_addr;
- # WebSockets durchlassen — viele Werkzeuge (Uptime Kuma, Dashboards,
- # alles mit Live-Anzeige) brechen sonst ab.
+ # WebSockets durchlassen — Live-Anzeigen brechen sonst ab.
proxy_http_version 1.1;
proxy_set_header Upgrade $$http_upgrade;
proxy_set_header Connection $$connection_upgrade;
- # Unkomprimiert anfordern, sonst ist im Strom nichts zu ersetzen.
+ # Unkomprimiert anfordern, sonst ist nichts zu ersetzen.
proxy_set_header Accept-Encoding "";
- # Nur HTML anfassen; alles andere geht unberührt durch.
- sub_filter_types text/html;
sub_filter_once on;
sub_filter ''
- '';
+ '';
- # Lange Antworten nicht künstlich aufhalten (Downloads, Fortschritt).
proxy_buffering off;
proxy_read_timeout 300s;
}
@@ -152,6 +144,5 @@ configs:
networks:
honeybar:
- # Fester Name, damit andere Compose-Dateien ihn als `external` finden.
- # Ohne den hiesse das Netz nach dem Ordner, in dem diese Datei liegt.
+ # Fester Name, damit die App-Stapel ihn als `external` finden.
name: honeybar
diff --git a/beispiele/mehrere-apps/leiste.conf b/beispiele/mehrere-apps/leiste.conf
deleted file mode 100644
index 5fc96c6..0000000
--- a/beispiele/mehrere-apps/leiste.conf
+++ /dev/null
@@ -1,73 +0,0 @@
-# ─────────────────────────────────────────────────────────────────────────────
-# HINWEIS: Diese Datei ist die lesbare Fassung zum Nachschlagen. Verwendet wird
-# derselbe Inhalt aus `docker-compose.yml` (Abschnitt `configs:`) — dort steht
-# er noch einmal, mit `$$` statt `$`. Wer hier etwas ändert, ändert es dort.
-#
-# Der Grund für den Umweg: Bind-Mounts einzelner Dateien scheitern, sobald die
-# Datei auf dem Wirt fehlt — Docker legt dann ein Verzeichnis an und bricht mit
-# „not a directory" ab. Beim Einsetzen über eine Oberfläche will man ausserdem
-# nur eine Datei bearbeiten, nicht drei.
-# ─────────────────────────────────────────────────────────────────────────────
-
-# ─────────────────────────────────────────────────────────────────────────────
-# Ein Einsetzer für alle Dienste, die die Leiste tragen sollen.
-#
-# Pangolin gibt den ursprünglichen Host weiter; daran erkennt nginx, welcher
-# Dienst gemeint ist. Eine neue App heisst: zwei Zeilen in den Tabellen unten,
-# neu laden, fertig — kein weiterer Behälter.
-# ─────────────────────────────────────────────────────────────────────────────
-
-# Wohin durchgereicht wird. Links der Name, unter dem du die App aufrufst,
-# rechts Behältername und Port im Docker-Netz.
-map $host $ziel {
- default "";
- pdf.honeyos.duckdns.org "bentopdf:8080";
- status.honeyos.duckdns.org "uptime-kuma:3001";
-}
-
-# Welche App das für HoneyOS ist. Muss der id in der App-Liste entsprechen —
-# daran erkennt die Leiste, wo man gerade ist, und hebt sie hervor.
-map $host $appid {
- default "";
- pdf.honeyos.duckdns.org "bentopdf";
- status.honeyos.duckdns.org "status";
-}
-
-server {
- listen 80;
- server_name _;
-
- # Für ein proxy_pass mit Variable braucht nginx einen Namensauflöser —
- # im Docker-Netz ist das der eingebaute unter 127.0.0.11.
- resolver 127.0.0.11 valid=30s ipv6=off;
-
- # Unbekannter Host: nicht raten, sondern ablehnen. Sonst wird aus einem
- # Tippfehler in Pangolin eine stille Weiterleitung irgendwohin.
- if ($ziel = "") { return 404; }
-
- location / {
- proxy_pass http://$ziel;
- proxy_set_header Host $host;
- proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
- proxy_set_header X-Forwarded-Proto $scheme;
- proxy_set_header X-Real-IP $remote_addr;
-
- # WebSockets durchlassen — viele Werkzeuge (Uptime Kuma, Dashboards,
- # alles mit Live-Anzeige) brechen sonst ab.
- proxy_http_version 1.1;
- proxy_set_header Upgrade $http_upgrade;
- proxy_set_header Connection $connection_upgrade;
-
- # Unkomprimiert anfordern, sonst ist im Strom nichts zu ersetzen.
- proxy_set_header Accept-Encoding "";
-
- # Nur HTML anfassen; alles andere geht unberührt durch.
- sub_filter_once on;
- sub_filter ''
- '';
-
- # Lange Antworten nicht künstlich aufhalten (Downloads, Fortschritt).
- proxy_buffering off;
- proxy_read_timeout 300s;
- }
-}
diff --git a/beispiele/mehrere-apps/upgrade.conf b/beispiele/mehrere-apps/upgrade.conf
deleted file mode 100644
index f48caf2..0000000
--- a/beispiele/mehrere-apps/upgrade.conf
+++ /dev/null
@@ -1,6 +0,0 @@
-# Gehört nach /etc/nginx/conf.d/, aber ausserhalb eines server-Blocks:
-# „Connection: upgrade" nur dann setzen, wenn der Browser das auch will.
-map $http_upgrade $connection_upgrade {
- default upgrade;
- '' close;
-}