feat(beispiel): mehrere Apps ueber einen Einsetzer, je mit eigener Kennung
Am Host erkennt nginx, welcher Dienst gemeint ist und welche App das fuer HoneyOS ist; die Leiste hebt sie dann hervor wie in Aether. Dieselbe Bauart wie im BentoPDF-Beispiel: Leiste und ihre zwei Abfragen laufen ueber die Adresse der App, damit deren CSP unangetastet bleibt. Die beiden .conf-Dateien sind weg — sie standen ein zweites Mal in der Compose-Datei, und zwei Fassungen derselben Sache laufen auseinander. Heute schon zweimal passiert. Geprueft mit zwei Diensten: richtige Kennung je Host, richtige Hervorhebung in der Leiste, gemeinsame App-Liste, Wetter. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
1 parent
8f294e15db
commit
135625ebe7
4 files changed
+75
-160
No files matched your search
@@ -256,11 +256,14 @@ Adresse der App.
|
|||||||
strenge CSP und COEP mitbringt: Leiste, Apps und Wetter erscheinen, ohne dass
|
strenge CSP und COEP mitbringt: Leiste, 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 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
|
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
|
`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
|
Nicht ein Behälter je App, und nicht HoneyOS getrennt davon gepflegt.
|
||||||
gepflegt.
|
|
||||||
|
|
||||||
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
|
||||||
|
|||||||
@@ -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)
|
# außen ──► Pangolin ──► honeyos (der Schreibtisch)
|
||||||
# Pangolin → leiste → bentopdf, kuma, … (fremde Dienste mit Leiste)
|
# 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
|
# Die fremden Dienste brauchen kein `ports:` mehr — erreichbar sind sie über
|
||||||
# in Werkzeuge, die man nicht ändern kann. Getrennt zu pflegen hiesse, bei jeder
|
# ihren Namen im Netz `honeybar`, und nach außen führt nur der Einsetzer.
|
||||||
# neuen App an zwei Stellen zu denken.
|
|
||||||
#
|
#
|
||||||
# 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
|
# mkdir -p daten && sudo chown 1000:1000 daten
|
||||||
# docker compose up -d
|
# docker compose up -d
|
||||||
#
|
#
|
||||||
# Das Netz `honeybar` legt dieser Stapel selbst an — die fremden Dienste treten
|
# Danach in Pangolin: honeyos.… → honeyos:8080, jede App → leiste:80.
|
||||||
# ihm bei. In deren Compose-Datei:
|
# 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:
|
|
||||||
# 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.
|
|
||||||
# ─────────────────────────────────────────────────────────────────────────────
|
# ─────────────────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
services:
|
services:
|
||||||
@@ -33,8 +28,7 @@ services:
|
|||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
user: "1000:1000"
|
user: "1000:1000"
|
||||||
ports:
|
ports:
|
||||||
# Nur an localhost: davor steht Pangolin, nicht das offene Netz.
|
- "${HONEYOS_PORT:-8088}:8080"
|
||||||
- "127.0.0.1:${HONEYOS_PORT:-8088}:8080"
|
|
||||||
volumes:
|
volumes:
|
||||||
- ${HONEYOS_DATA_DIR:-./daten}:/data
|
- ${HONEYOS_DATA_DIR:-./daten}:/data
|
||||||
environment:
|
environment:
|
||||||
@@ -55,73 +49,75 @@ services:
|
|||||||
image: nginx:alpine
|
image: nginx:alpine
|
||||||
container_name: honeybar-leiste
|
container_name: honeybar-leiste
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
# Die beiden nginx-Dateien stehen als `configs` unten **in dieser Datei**.
|
ports:
|
||||||
#
|
- "${LEISTE_PORT:-8185}:80"
|
||||||
# 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.
|
|
||||||
configs:
|
configs:
|
||||||
- source: upgrade
|
|
||||||
target: /etc/nginx/conf.d/00-upgrade.conf
|
|
||||||
- source: leiste
|
- source: leiste
|
||||||
target: /etc/nginx/conf.d/default.conf
|
target: /etc/nginx/conf.d/default.conf
|
||||||
ports:
|
|
||||||
- "127.0.0.1:${LEISTE_PORT:-8185}:80"
|
|
||||||
networks: [honeybar]
|
networks: [honeybar]
|
||||||
# Der Einsetzer braucht HoneyOS nicht zum Starten — er reicht nur durch und
|
# Kein depends_on: Der Einsetzer reicht nur durch. Ist HoneyOS aus, fehlt
|
||||||
# setzt eine Zeile ein. Ist HoneyOS aus, fehlt die Leiste, die App läuft.
|
# die Leiste — die Apps laufen weiter.
|
||||||
|
|
||||||
configs:
|
configs:
|
||||||
# Achtung beim Ändern: `$$` ist hier ein einfaches `$` für nginx. Ein
|
leiste:
|
||||||
# einzelnes `$` würde Compose als eigene Variable lesen und leeren.
|
# `$$` ist hier ein einfaches `$` für nginx. Ein einzelnes `$` setzt
|
||||||
upgrade:
|
# 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: |
|
content: |
|
||||||
# Gehört nach /etc/nginx/conf.d/, aber ausserhalb eines server-Blocks:
|
# ── Welcher Dienst steckt hinter welchem Namen ────────────────────────
|
||||||
# „Connection: upgrade" nur dann setzen, wenn der Browser das auch will.
|
# 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 {
|
map $$http_upgrade $$connection_upgrade {
|
||||||
default upgrade;
|
default upgrade;
|
||||||
'' close;
|
'' 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 {
|
server {
|
||||||
listen 80;
|
listen 80;
|
||||||
server_name _;
|
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;
|
resolver 127.0.0.11 valid=30s ipv6=off;
|
||||||
|
|
||||||
# Unbekannter Host: nicht raten, sondern ablehnen. Sonst wird aus einem
|
# Unbekannter Name: nicht raten. Sonst wird aus einem Tippfehler in
|
||||||
# Tippfehler in Pangolin eine stille Weiterleitung irgendwohin.
|
# Pangolin eine stille Weiterleitung irgendwohin.
|
||||||
if ($$ziel = "") { return 404; }
|
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 / {
|
location / {
|
||||||
proxy_pass http://$$ziel;
|
proxy_pass http://$$ziel;
|
||||||
proxy_set_header Host $$host;
|
proxy_set_header Host $$host;
|
||||||
@@ -129,22 +125,18 @@ configs:
|
|||||||
proxy_set_header X-Forwarded-Proto $$scheme;
|
proxy_set_header X-Forwarded-Proto $$scheme;
|
||||||
proxy_set_header X-Real-IP $$remote_addr;
|
proxy_set_header X-Real-IP $$remote_addr;
|
||||||
|
|
||||||
# WebSockets durchlassen — viele Werkzeuge (Uptime Kuma, Dashboards,
|
# WebSockets durchlassen — Live-Anzeigen brechen sonst ab.
|
||||||
# alles mit Live-Anzeige) brechen sonst ab.
|
|
||||||
proxy_http_version 1.1;
|
proxy_http_version 1.1;
|
||||||
proxy_set_header Upgrade $$http_upgrade;
|
proxy_set_header Upgrade $$http_upgrade;
|
||||||
proxy_set_header Connection $$connection_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 "";
|
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_once on;
|
||||||
sub_filter '</head>'
|
sub_filter '</head>'
|
||||||
'<script defer src="https://honeyos.duckdns.org/honeybar/honeybar.js" data-app="$$appid"></script></head>';
|
'<script defer src="/honeybar/honeybar.js" data-app="$$appid" data-apps="/honeyos-api/apps" data-home="https://honeyos.duckdns.org/"></script></head>';
|
||||||
|
|
||||||
# Lange Antworten nicht künstlich aufhalten (Downloads, Fortschritt).
|
|
||||||
proxy_buffering off;
|
proxy_buffering off;
|
||||||
proxy_read_timeout 300s;
|
proxy_read_timeout 300s;
|
||||||
}
|
}
|
||||||
@@ -152,6 +144,5 @@ configs:
|
|||||||
|
|
||||||
networks:
|
networks:
|
||||||
honeybar:
|
honeybar:
|
||||||
# Fester Name, damit andere Compose-Dateien ihn als `external` finden.
|
# Fester Name, damit die App-Stapel ihn als `external` finden.
|
||||||
# Ohne den hiesse das Netz nach dem Ordner, in dem diese Datei liegt.
|
|
||||||
name: honeybar
|
name: honeybar
|
||||||
@@ -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 '</head>'
|
|
||||||
'<script defer src="https://honeyos.duckdns.org/honeybar/honeybar.js" data-app="$appid"></script></head>';
|
|
||||||
|
|
||||||
# Lange Antworten nicht künstlich aufhalten (Downloads, Fortschritt).
|
|
||||||
proxy_buffering off;
|
|
||||||
proxy_read_timeout 300s;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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;
|
|
||||||
}
|
|
||||||
Reference in new issue
Block a user