diff --git a/CHANGELOG.md b/CHANGELOG.md index 2ecab38..5eca7db 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,46 @@ +# v0.7.00-beta β Apps koppelen, eenvoudiger instellen, geavanceerde opties verborgen + +## π Apps kunnen elkaar nu bereiken + +Elke stack draaide als eigen compose-project en kreeg daarmee zijn eigen +netwerk. Twee stacks konden elkaar dus niet op naam vinden: Zigbee2MQTT zag de +Mosquitto-broker uit een andere stack simpelweg niet. + +Bij het installeren staat nu **"Verbinden met andere apps"** aan. De stack komt +dan op een gedeeld bridge-netwerk (`serverup`), waar containers elkaar op naam +oplossen. Het netwerk wordt aangemaakt zodra de eerste stack het nodig heeft. + +## π― Kiezen in plaats van typen + +Een veld dat naar een andere app verwijst, toont voortaan een **keuzelijst met +wat je al hebt draaien** in plaats van een leeg tekstveld. Installeer je +Zigbee2MQTT en heb je Mosquitto al staan, dan staat `mqtt://mosquitto:1883` er +meteen ingevuld. Hetzelfde voor Open WebUI dat je Ollama vindt. + +Staat de app er nog niet, dan zegt het veld dat β met de mogelijkheid om alsnog +handmatig een adres in te vullen. + +## π¬ Uitleg per instelling + +Achter elk veld met toelichting staat een **info-icoon**. Klikken opent een blok +met de volledige uitleg en de standaardwaarde. Voor de instellingen die de +meeste vragen oproepen is die uitleg uitgeschreven β waarom je downloadmap op +hetzelfde bestandssysteem moet staan als je mediamap, wat `shm_size` bij Frigate +doet, waarom Caddy poort 80 nodig heeft ook als je alles via HTTPS aanbiedt. + +## ποΈ Geavanceerde opties uit het zicht + +Velden die je meestal met rust laat β database-wachtwoorden, PUID/PGID, +USB-paden, bewaartermijnen β zitten nu achter een uitklapblok **"Geavanceerde +opties"** met een teller erbij. Het installatieformulier begint daardoor met +alleen de vragen die er echt toe doen. + +Templates kunnen `advanced: true` op een veld of op een hele groep zetten. Een +test bewaakt dat er per app altijd zichtbare velden overblijven, zodat niemand +per ongeluk een volledig leeg formulier maakt. + +--- + # v0.6.20-beta β 31 apps erbij na een rondgang langs de verzamelsites Van 65 naar 96 apps. Selectie op basis van awesome-selfhosted, selfh.st, diff --git a/VERSION b/VERSION index 08ce70d..771f51a 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.6.20-beta +0.7.00-beta diff --git a/apps/arr-stack/template.json b/apps/arr-stack/template.json index 4c7045a..cee79ca 100644 --- a/apps/arr-stack/template.json +++ b/apps/arr-stack/template.json @@ -51,7 +51,8 @@ "title": "Downloadmap", "default": "/mnt/downloads", "required": true, - "description": "Zet deze op hetzelfde bestandssysteem als de mediamap, anders kopieert elke download in plaats van te verplaatsen" + "description": "Zet deze op hetzelfde bestandssysteem als de mediamap, anders kopieert elke download in plaats van te verplaatsen", + "help": "Zet deze map op hetzelfde bestandssysteem als je mediamap. Staan ze op verschillende schijven of volumes, dan kopieert elke voltooide download in plaats van te verplaatsen: traag, en je hebt alles tijdelijk dubbel." }, { "name": "timezone", @@ -66,7 +67,8 @@ "title": "Gebruikers-ID (PUID)", "default": 1000, "required": true, - "description": "`id -u` op je host; bepaalt de eigenaar van bestanden" + "description": "`id -u` op je host; bepaalt de eigenaar van bestanden", + "help": "Het gebruikersnummer waaronder de containers draaien. Klopt dit niet met de eigenaar van je mediamap, dan kunnen de apps er niet in schrijven. Vind het met `id -u` op je server." }, { "name": "pgid", diff --git a/apps/authelia/template.json b/apps/authelia/template.json index 0ce99a3..92a1779 100644 --- a/apps/authelia/template.json +++ b/apps/authelia/template.json @@ -57,7 +57,8 @@ "description": "Gebruik de dobbelsteenknop voor een willekeurige waarde", "config": { "placeholder": "sterk-wachtwoord" - } + }, + "advanced": true }, { "name": "session_secret", @@ -68,7 +69,8 @@ "description": "Gebruik de dobbelsteenknop voor een willekeurige waarde", "config": { "placeholder": "sterk-wachtwoord" - } + }, + "advanced": true }, { "name": "storage_key", @@ -79,7 +81,8 @@ "description": "Gebruik de dobbelsteenknop voor een willekeurige waarde", "config": { "placeholder": "sterk-wachtwoord" - } + }, + "advanced": true } ] } diff --git a/apps/baby-buddy/template.json b/apps/baby-buddy/template.json index 25c41d2..86aaba3 100644 --- a/apps/baby-buddy/template.json +++ b/apps/baby-buddy/template.json @@ -54,14 +54,16 @@ "title": "Gebruikers-ID (PUID)", "default": 1000, "required": true, - "description": "Bepaalt de eigenaar van de bestanden; `id -u` op je host" + "description": "Bepaalt de eigenaar van de bestanden; `id -u` op je host", + "advanced": true }, { "name": "pgid", "type": "int", "title": "Groeps-ID (PGID)", "default": 1000, - "required": true + "required": true, + "advanced": true }, { "name": "secret_key", @@ -80,7 +82,8 @@ "title": "Toegestane hostnamen", "default": "*", "required": true, - "description": "Bijvoorbeeld babybuddy.thuis.nl; * staat alles toe" + "description": "Bijvoorbeeld babybuddy.thuis.nl; * staat alles toe", + "advanced": true } ] } diff --git a/apps/bambuddy/template.json b/apps/bambuddy/template.json index 16f13de..cbf0290 100644 --- a/apps/bambuddy/template.json +++ b/apps/bambuddy/template.json @@ -54,14 +54,16 @@ "title": "Gebruikers-ID (PUID)", "default": 1000, "required": true, - "description": "Bepaalt de eigenaar van de bestanden; `id -u` op je host" + "description": "Bepaalt de eigenaar van de bestanden; `id -u` op je host", + "advanced": true }, { "name": "pgid", "type": "int", "title": "Groeps-ID (PGID)", "default": 1000, - "required": true + "required": true, + "advanced": true } ] } diff --git a/apps/bookstack/template.json b/apps/bookstack/template.json index 4eaab7d..890094a 100644 --- a/apps/bookstack/template.json +++ b/apps/bookstack/template.json @@ -54,14 +54,16 @@ "title": "Gebruikers-ID (PUID)", "default": 1000, "required": true, - "description": "Bepaalt de eigenaar van de bestanden; `id -u` op je host" + "description": "Bepaalt de eigenaar van de bestanden; `id -u` op je host", + "advanced": true }, { "name": "pgid", "type": "int", "title": "Groeps-ID (PGID)", "default": 1000, - "required": true + "required": true, + "advanced": true }, { "name": "db_password", @@ -72,7 +74,8 @@ "description": "Gebruik de dobbelsteenknop voor een willekeurige waarde", "config": { "placeholder": "sterk-wachtwoord" - } + }, + "advanced": true }, { "name": "app_url", diff --git a/apps/caddy/template.json b/apps/caddy/template.json index c5efe58..477bc98 100644 --- a/apps/caddy/template.json +++ b/apps/caddy/template.json @@ -32,7 +32,8 @@ "type": "int", "title": "HTTP poort", "default": 80, - "required": true + "required": true, + "help": "Caddy vraagt zelf certificaten aan bij Let's Encrypt en heeft daarvoor poort 80 nodig, ook als je alles via HTTPS aanbiedt." }, { "name": "data_dir", diff --git a/apps/calibre-web/template.json b/apps/calibre-web/template.json index cbb0a36..ac7c364 100644 --- a/apps/calibre-web/template.json +++ b/apps/calibre-web/template.json @@ -54,14 +54,16 @@ "title": "Gebruikers-ID (PUID)", "default": 1000, "required": true, - "description": "Bepaalt de eigenaar van de bestanden; `id -u` op je host" + "description": "Bepaalt de eigenaar van de bestanden; `id -u` op je host", + "advanced": true }, { "name": "pgid", "type": "int", "title": "Groeps-ID (PGID)", "default": 1000, - "required": true + "required": true, + "advanced": true }, { "name": "books_dir", diff --git a/apps/duplicati/template.json b/apps/duplicati/template.json index af55536..76fb8fa 100644 --- a/apps/duplicati/template.json +++ b/apps/duplicati/template.json @@ -54,14 +54,16 @@ "title": "Gebruikers-ID (PUID)", "default": 1000, "required": true, - "description": "Bepaalt de eigenaar van de bestanden; `id -u` op je host" + "description": "Bepaalt de eigenaar van de bestanden; `id -u` op je host", + "advanced": true }, { "name": "pgid", "type": "int", "title": "Groeps-ID (PGID)", "default": 1000, - "required": true + "required": true, + "advanced": true }, { "name": "source_dir", diff --git a/apps/firefly-iii/template.json b/apps/firefly-iii/template.json index f0dab55..12010d2 100644 --- a/apps/firefly-iii/template.json +++ b/apps/firefly-iii/template.json @@ -57,7 +57,8 @@ "description": "Gebruik de dobbelsteenknop voor een willekeurige waarde", "config": { "placeholder": "sterk-wachtwoord" - } + }, + "advanced": true }, { "name": "app_key", @@ -68,7 +69,8 @@ "description": "Exact 32 tekens; gebruik de dobbelsteenknop en kort zo nodig in", "config": { "placeholder": "32-tekens-lange-sleutel" - } + }, + "advanced": true } ] } diff --git a/apps/frigate/template.json b/apps/frigate/template.json index 00ca1b4..07fd0e8 100644 --- a/apps/frigate/template.json +++ b/apps/frigate/template.json @@ -53,7 +53,8 @@ "type": "int", "title": "RTSP poort", "default": 8554, - "required": true + "required": true, + "advanced": true }, { "name": "shm_size", @@ -61,7 +62,9 @@ "title": "Gedeeld geheugen", "default": "128mb", "required": true, - "description": "Verhoog dit bij meer dan twee camera's (ongeveer 64mb per camera)" + "description": "Verhoog dit bij meer dan twee camera's (ongeveer 64mb per camera)", + "advanced": true, + "help": "Frigate houdt camerabeelden in gedeeld geheugen. Reken op ongeveer 64 MB per camera bovenop de standaard; te weinig leidt tot vastlopers zonder duidelijke foutmelding." } ] } diff --git a/apps/grocy/template.json b/apps/grocy/template.json index 9b5ee2c..0eb601e 100644 --- a/apps/grocy/template.json +++ b/apps/grocy/template.json @@ -54,14 +54,16 @@ "title": "Gebruikers-ID (PUID)", "default": 1000, "required": true, - "description": "Bepaalt de eigenaar van de bestanden; `id -u` op je host" + "description": "Bepaalt de eigenaar van de bestanden; `id -u` op je host", + "advanced": true }, { "name": "pgid", "type": "int", "title": "Groeps-ID (PGID)", "default": 1000, - "required": true + "required": true, + "advanced": true } ] } diff --git a/apps/hedgedoc/template.json b/apps/hedgedoc/template.json index 85acf9f..14434b7 100644 --- a/apps/hedgedoc/template.json +++ b/apps/hedgedoc/template.json @@ -57,7 +57,8 @@ "description": "Gebruik de dobbelsteenknop voor een willekeurige waarde", "config": { "placeholder": "sterk-wachtwoord" - } + }, + "advanced": true }, { "name": "app_url", diff --git a/apps/immich/template.json b/apps/immich/template.json index a744b81..892e659 100644 --- a/apps/immich/template.json +++ b/apps/immich/template.json @@ -3,9 +3,18 @@ "metadata": { "name": "Immich", "description": "Zelfgehoste foto- en videobeheer met automatische back-up. Google Photos alternatief.", - "tags": ["fotos", "media", "backup"], - "icon": {"provider": "selfhst", "id": "immich"}, - "version": {"name": "release"} + "tags": [ + "fotos", + "media", + "backup" + ], + "icon": { + "provider": "selfhst", + "id": "immich" + }, + "version": { + "name": "release" + } }, "variables": [ { @@ -31,7 +40,8 @@ "title": "Upload directory", "default": "/opt/serverup/appdata", "required": true, - "description": "Basismap voor foto-uploads en database" + "description": "Basismap voor foto-uploads en database", + "help": "Hier komen je originele foto's en video's te staan. Reken op net zoveel ruimte als je telefoon en camera bij elkaar produceren, plus wat marge voor de miniaturen." }, { "name": "timezone", @@ -52,7 +62,10 @@ "default": "immich_db_pass", "required": true, "description": "Wachtwoord voor de interne PostgreSQL database", - "config": {"placeholder": "sterk-wachtwoord"} + "config": { + "placeholder": "sterk-wachtwoord" + }, + "advanced": true } ] } diff --git a/apps/influxdb/template.json b/apps/influxdb/template.json index 9ba0cdf..41500db 100644 --- a/apps/influxdb/template.json +++ b/apps/influxdb/template.json @@ -53,14 +53,16 @@ "type": "str", "title": "Organisatie", "default": "thuis", - "required": true + "required": true, + "advanced": true }, { "name": "bucket", "type": "str", "title": "Bucket", "default": "metingen", - "required": true + "required": true, + "advanced": true }, { "name": "admin_user", diff --git a/apps/karakeep/template.json b/apps/karakeep/template.json index 7eed13e..a61649b 100644 --- a/apps/karakeep/template.json +++ b/apps/karakeep/template.json @@ -57,7 +57,8 @@ "description": "Willekeurige waarde voor sessies", "config": { "placeholder": "sterk-wachtwoord" - } + }, + "advanced": true }, { "name": "openai_key", @@ -65,7 +66,8 @@ "title": "OpenAI-sleutel (optioneel)", "default": "", "required": false, - "description": "Alleen nodig als je automatisch labels wilt laten toekennen" + "description": "Alleen nodig als je automatisch labels wilt laten toekennen", + "advanced": true } ] } diff --git a/apps/kavita/template.json b/apps/kavita/template.json index 43d180b..901b30e 100644 --- a/apps/kavita/template.json +++ b/apps/kavita/template.json @@ -54,14 +54,16 @@ "title": "Gebruikers-ID (PUID)", "default": 1000, "required": true, - "description": "Bepaalt de eigenaar van de bestanden; `id -u` op je host" + "description": "Bepaalt de eigenaar van de bestanden; `id -u` op je host", + "advanced": true }, { "name": "pgid", "type": "int", "title": "Groeps-ID (PGID)", "default": 1000, - "required": true + "required": true, + "advanced": true }, { "name": "library_dir", diff --git a/apps/keycloak/template.json b/apps/keycloak/template.json index 53b3ea5..2ad4b96 100644 --- a/apps/keycloak/template.json +++ b/apps/keycloak/template.json @@ -75,7 +75,8 @@ "description": "Gebruik de dobbelsteenknop voor een willekeurige waarde", "config": { "placeholder": "sterk-wachtwoord" - } + }, + "advanced": true } ] } diff --git a/apps/kimai/template.json b/apps/kimai/template.json index 810b4fa..eb029f6 100644 --- a/apps/kimai/template.json +++ b/apps/kimai/template.json @@ -57,7 +57,8 @@ "description": "Gebruik de dobbelsteenknop voor een willekeurige waarde", "config": { "placeholder": "sterk-wachtwoord" - } + }, + "advanced": true }, { "name": "admin_email", diff --git a/apps/komga/template.json b/apps/komga/template.json index c7e98f3..c3425aa 100644 --- a/apps/komga/template.json +++ b/apps/komga/template.json @@ -54,14 +54,16 @@ "title": "Gebruikers-ID (PUID)", "default": 1000, "required": true, - "description": "Bepaalt de eigenaar van de bestanden; `id -u` op je host" + "description": "Bepaalt de eigenaar van de bestanden; `id -u` op je host", + "advanced": true }, { "name": "pgid", "type": "int", "title": "Groeps-ID (PGID)", "default": 1000, - "required": true + "required": true, + "advanced": true }, { "name": "library_dir", diff --git a/apps/languagetool/template.json b/apps/languagetool/template.json index bb3a3e8..52ea543 100644 --- a/apps/languagetool/template.json +++ b/apps/languagetool/template.json @@ -46,7 +46,8 @@ "type": "bool", "title": "N-gram data gebruiken", "default": false, - "description": "Betere suggesties, maar vraagt enkele gigabytes aan schijfruimte" + "description": "Betere suggesties, maar vraagt enkele gigabytes aan schijfruimte", + "advanced": true } ] } diff --git a/apps/metube/template.json b/apps/metube/template.json index b71eaf9..3d68955 100644 --- a/apps/metube/template.json +++ b/apps/metube/template.json @@ -54,14 +54,16 @@ "title": "Gebruikers-ID (PUID)", "default": 1000, "required": true, - "description": "Bepaalt de eigenaar van de bestanden; `id -u` op je host" + "description": "Bepaalt de eigenaar van de bestanden; `id -u` op je host", + "advanced": true }, { "name": "pgid", "type": "int", "title": "Groeps-ID (PGID)", "default": 1000, - "required": true + "required": true, + "advanced": true }, { "name": "downloads_dir", diff --git a/apps/ollama/template.json b/apps/ollama/template.json index ac72758..d9682c7 100644 --- a/apps/ollama/template.json +++ b/apps/ollama/template.json @@ -53,7 +53,9 @@ "type": "bool", "title": "NVIDIA-GPU gebruiken", "default": false, - "description": "Vereist de NVIDIA Container Toolkit op de host" + "description": "Vereist de NVIDIA Container Toolkit op de host", + "advanced": true, + "help": "Met een NVIDIA-kaart draaien modellen tientallen keren sneller. Vereist wel dat de NVIDIA Container Toolkit op de host geΓ―nstalleerd is; zonder die toolkit start de container niet." } ] } diff --git a/apps/open-webui/template.json b/apps/open-webui/template.json index ab1d747..f075d52 100644 --- a/apps/open-webui/template.json +++ b/apps/open-webui/template.json @@ -54,7 +54,13 @@ "title": "Ollama-adres", "default": "http://ollama:11434", "required": true, - "description": "Wijs naar je Ollama-container of een adres in je netwerk" + "description": "Wijs naar je Ollama-container of een adres in je netwerk", + "connect": { + "app": "ollama", + "scheme": "http", + "port": 11434 + }, + "help": "Het adres waar de taalmodellen draaien. Heb je de Ollama-app geΓ―nstalleerd, kies die dan hier; je kunt ook naar een Ollama op een andere machine wijzen." }, { "name": "secret_key", diff --git a/apps/photoprism/template.json b/apps/photoprism/template.json index 304bf09..0d38924 100644 --- a/apps/photoprism/template.json +++ b/apps/photoprism/template.json @@ -75,7 +75,8 @@ "description": "Gebruik de dobbelsteenknop voor een willekeurige waarde", "config": { "placeholder": "sterk-wachtwoord" - } + }, + "advanced": true } ] } diff --git a/apps/planka/template.json b/apps/planka/template.json index 807a137..9c4ca43 100644 --- a/apps/planka/template.json +++ b/apps/planka/template.json @@ -57,7 +57,8 @@ "description": "Gebruik de dobbelsteenknop voor een willekeurige waarde", "config": { "placeholder": "sterk-wachtwoord" - } + }, + "advanced": true }, { "name": "secret_key", @@ -68,7 +69,8 @@ "description": "Gebruik de dobbelsteenknop voor een willekeurige waarde", "config": { "placeholder": "sterk-wachtwoord" - } + }, + "advanced": true }, { "name": "base_url", diff --git a/apps/prometheus/template.json b/apps/prometheus/template.json index df0986f..0ff159c 100644 --- a/apps/prometheus/template.json +++ b/apps/prometheus/template.json @@ -54,7 +54,8 @@ "title": "Bewaartermijn", "default": "30d", "required": true, - "description": "Hoe lang meetwaarden bewaard blijven, bv. 30d of 1y" + "description": "Hoe lang meetwaarden bewaard blijven, bv. 30d of 1y", + "advanced": true } ] } diff --git a/apps/tandoor/template.json b/apps/tandoor/template.json index 30bcde4..9c906a1 100644 --- a/apps/tandoor/template.json +++ b/apps/tandoor/template.json @@ -57,7 +57,8 @@ "description": "Gebruik de dobbelsteenknop voor een willekeurige waarde", "config": { "placeholder": "sterk-wachtwoord" - } + }, + "advanced": true }, { "name": "secret_key", @@ -68,7 +69,8 @@ "description": "Willekeurige waarde voor sessieversleuteling", "config": { "placeholder": "willekeurige-lange-string" - } + }, + "advanced": true } ] } diff --git a/apps/teslamate/template.json b/apps/teslamate/template.json index f6cd413..4d83a2b 100644 --- a/apps/teslamate/template.json +++ b/apps/teslamate/template.json @@ -57,7 +57,8 @@ "description": "Gebruik de dobbelsteenknop voor een willekeurige waarde", "config": { "placeholder": "sterk-wachtwoord" - } + }, + "advanced": true }, { "name": "encryption_key", @@ -68,14 +69,17 @@ "description": "Beschermt je Tesla-token", "config": { "placeholder": "sterk-wachtwoord" - } + }, + "advanced": true }, { "name": "grafana_port", "type": "int", "title": "Grafana poort", "default": 3014, - "required": true + "required": true, + "help": "TeslaMate levert kant-en-klare dashboards mee in een eigen Grafana. Dit is de poort waarop je die bekijkt, los van je eventuele andere Grafana.", + "advanced": true } ] } diff --git a/apps/wallabag/template.json b/apps/wallabag/template.json index df040e6..79ab782 100644 --- a/apps/wallabag/template.json +++ b/apps/wallabag/template.json @@ -57,7 +57,8 @@ "description": "Gebruik de dobbelsteenknop voor een willekeurige waarde", "config": { "placeholder": "sterk-wachtwoord" - } + }, + "advanced": true }, { "name": "app_url", diff --git a/apps/wg-easy/template.json b/apps/wg-easy/template.json index 62105aa..50eaa1e 100644 --- a/apps/wg-easy/template.json +++ b/apps/wg-easy/template.json @@ -61,7 +61,8 @@ "title": "Publiek adres", "default": "vpn.example.com", "required": true, - "description": "Het adres of IP waarop je van buitenaf binnenkomt" + "description": "Het adres of IP waarop je van buitenaf binnenkomt", + "help": "Het adres waarop je van buitenaf binnenkomt: je vaste IP, of een naam via een dynamische-DNS-dienst. Klopt dit niet, dan werken de QR-codes wel maar kunnen je apparaten geen verbinding maken." }, { "name": "password_hash", diff --git a/apps/wikijs/template.json b/apps/wikijs/template.json index 9ab301f..05eedcf 100644 --- a/apps/wikijs/template.json +++ b/apps/wikijs/template.json @@ -57,7 +57,8 @@ "description": "Gebruik de dobbelsteenknop voor een willekeurige waarde", "config": { "placeholder": "sterk-wachtwoord" - } + }, + "advanced": true } ] } diff --git a/apps/zigbee2mqtt/template.json b/apps/zigbee2mqtt/template.json index e2953d3..a3817ed 100644 --- a/apps/zigbee2mqtt/template.json +++ b/apps/zigbee2mqtt/template.json @@ -54,7 +54,8 @@ "title": "USB-adapter", "default": "/dev/ttyACM0", "required": true, - "description": "Pad naar je Zigbee-stick; vind hem met `ls -l /dev/serial/by-id/`" + "description": "Pad naar je Zigbee-stick; vind hem met `ls -l /dev/serial/by-id/`", + "advanced": true }, { "name": "mqtt_server", @@ -62,7 +63,13 @@ "title": "MQTT-server", "default": "mqtt://mosquitto:1883", "required": true, - "description": "Adres van je MQTT-broker (zie de Mosquitto-app)" + "description": "Adres van je MQTT-broker (zie de Mosquitto-app)", + "connect": { + "app": "mosquitto", + "scheme": "mqtt", + "port": 1883 + }, + "help": "Zigbee2MQTT stuurt alles wat je apparaten melden naar een MQTT-broker; Home Assistant leest daar weer uit. Heb je de Mosquitto-app geΓ―nstalleerd, kies die dan hier. Een eigen broker elders vul je handmatig in." } ] } diff --git a/server-up/app.py b/server-up/app.py index 2b043cc..6f41dfd 100644 --- a/server-up/app.py +++ b/server-up/app.py @@ -1109,6 +1109,12 @@ def api_store_install(): bp_values = d.get("values", {}) # boilerplate variable values net_name = (d.get("network") or "").strip() # leeg = poorten op de host net_ip = (d.get("ip") or "").strip() + # Aan het gedeelde netwerk hangen, zodat deze stack andere apps op naam + # kan bereiken (en andersom). + verbinden = d.get("connect_apps") + if verbinden is None: + verbinden = bool(cfg.load().get("CONNECT_APPS_DEFAULT", True)) + gedeeld_net = (cfg.load().get("SHARED_NETWORK") or "serverup").strip() if not stack: return jsonify(ok=False, msg="stack vereist") @@ -1250,6 +1256,26 @@ def api_store_install(): jobs.log(qq, "dim", "Poortmappings verwijderd β de app draait op " "zijn eigen poort op dit adres.") + # Aan het gedeelde netwerk hangen. Zonder dit zit elke stack in + # zijn eigen compose-netwerk en vindt geen enkele app een andere. + if verbinden and gedeeld_net: + ok_net, fout_net = networks.ensure_shared(gedeeld_net) + if not ok_net: + jobs.log(qq, "warn", + f"Gedeeld netwerk '{gedeeld_net}' niet beschikbaar: " + f"{fout_net} β de stack start zonder koppeling.") + else: + cf = docker.find_compose(dest) + try: + cf.write_text(compose_transform.add_shared_network( + cf.read_text(encoding="utf-8"), gedeeld_net), + encoding="utf-8") + jobs.log(qq, "ok", + f"Gekoppeld aan netwerk '{gedeeld_net}' β andere " + "apps zijn bereikbaar op hun containernaam.") + except compose_transform.TransformError as e: + jobs.log(qq, "warn", f"Koppelen mislukt: {e}") + # Valideer het resultaat vΓ³Γ³r we proberen te starten, zodat een # fout in het template een duidelijke melding geeft. ok_cfg, err_cfg = docker.validate_compose(dest) @@ -1279,6 +1305,7 @@ def api_store_install(): # geen andere installatie hetzelfde IP voorgesteld. "network": net_name, "ip": net_ip if net else "", + "connected": bool(verbinden and gedeeld_net), }, ensure_ascii=False, indent=2), encoding="utf-8") except Exception: pass @@ -1475,6 +1502,43 @@ def api_networks(): drivers=list(networks.DRIVERS)) +@app.route("/api/apps/connectable") +def api_connectable(): + """Ge<0x00ef>nstalleerde apps waar een nieuwe app aan gekoppeld kan worden. + + Per stack de containernamen zoals ze binnen het gedeelde netwerk op te + lossen zijn, plus uit welke app-template hij komt. Daarmee kan de + installatiemodal een keuzelijst tonen in plaats van de gebruiker zelf een + adres te laten typen. + """ + lib = Path(cfg.load()["LIBRARY_DIR"]).resolve() + uit = [] + if lib.is_dir(): + for d in sorted(lib.iterdir()): + if not d.is_dir() or d.name.startswith(".") or not docker.has_compose(d): + continue + meta = {} + mf = d / ".serverup.json" + if mf.exists(): + try: + meta = json.loads(mf.read_text("utf-8")) + except Exception: + meta = {} + containers = [{"name": c["name"], "service": c.get("service", ""), + "ports": c.get("ports", "")} + for c in docker.compose_ps(d, name=d.name) if c.get("name")] + uit.append({ + "stack": d.name, + "source": meta.get("source", ""), # uit welke app-template + "name": meta.get("name") or d.name, + "ip": meta.get("ip", ""), + "containers": containers or [{"name": d.name, "service": "", "ports": ""}], + }) + c = cfg.load() + return jsonify(apps=uit, shared_network=c.get("SHARED_NETWORK", "serverup"), + connect_default=bool(c.get("CONNECT_APPS_DEFAULT", True))) + + @app.route("/api/networks/range", methods=["POST"]) def api_networks_range(): """Zet "van adres X tot adres Y" om in bruikbare CIDR-blokken.""" diff --git a/server-up/core/__init__.py b/server-up/core/__init__.py index 5937e69..43725ee 100644 --- a/server-up/core/__init__.py +++ b/server-up/core/__init__.py @@ -56,6 +56,11 @@ DEFAULTS = { "AUTO_SYNC_ON_BOOT": False, # Macvlan/ipvlan-netwerken waarmee stacks een eigen IP-adres krijgen. "NETWORKS": [], + # Gedeeld bridge-netwerk waarop stacks elkaar op containernaam vinden. + # Zonder dit zit elke stack in zijn eigen compose-netwerk en kan een app + # geen andere app bereiken. + "SHARED_NETWORK": "serverup", + "CONNECT_APPS_DEFAULT": True, # Backups. KEEP=0 of MAX_AGE=0 schakelt die regel uit; de nieuwste backup # van een stack wordt nooit opgeruimd. "BACKUP_KEEP": 5, diff --git a/server-up/core/boilerplates.py b/server-up/core/boilerplates.py index aed4d45..f849bcf 100644 --- a/server-up/core/boilerplates.py +++ b/server-up/core/boilerplates.py @@ -94,6 +94,7 @@ def fields(d: Path) -> list[dict]: "placeholder": "", "description": grp.get("description", ""), "is_group_toggle": True, }) + groep_geavanceerd = bool(grp.get("advanced")) for item in grp.get("items", []) or []: cfg = item.get("config") or {} out.append({ @@ -108,6 +109,17 @@ def fields(d: Path) -> list[dict]: "needs": item.get("needs") or [], "placeholder": cfg.get("placeholder", ""), "description": item.get("description", ""), + # Geavanceerde velden verdwijnen achter een uitklapblok, zodat + # het formulier bij het installeren kort blijft. + "advanced": bool(item.get("advanced")) or groep_geavanceerd, + # Uitgebreide toelichting voor het info-venster; valt terug op + # description als die er niet is. + "help": item.get("help", ""), + # Verwijst naar een andere app: de interface biedt dan een + # keuzelijst met wat er al ge?nstalleerd is in plaats van een + # leeg tekstveld. {"app": "mosquitto", "scheme": "mqtt", + # "port": 1883, "path": ""} + "connect": item.get("connect") or None, }) return out diff --git a/server-up/core/compose_transform.py b/server-up/core/compose_transform.py index c211cbc..b60b2e3 100644 --- a/server-up/core/compose_transform.py +++ b/server-up/core/compose_transform.py @@ -72,6 +72,48 @@ def to_dedicated_ip(compose_text: str, network: str, ip: str, allow_unicode=True, width=120) +def add_shared_network(compose_text: str, network: str) -> str: + """Hang elke service ook aan een gedeeld netwerk. + + Elke stack draait als eigen compose-project en krijgt daarmee zijn eigen + netwerk. Twee stacks kunnen elkaar dan niet op servicenaam bereiken β een + app als Zigbee2MQTT vindt de MQTT-broker uit een andere stack dus niet. + Door ze allemaal aan één gedeeld bridge-netwerk te hangen, lost de + container-naam wΓ©l op tussen stacks. + + Bestaande netwerken (zoals een macvlan met vast IP) blijven staan; dit komt + er naast. + """ + try: + doc = yaml.safe_load(compose_text) + except yaml.YAMLError as e: + raise TransformError(f"compose is geen geldige YAML: {e}") from e + if not isinstance(doc, dict) or not isinstance(doc.get("services"), dict): + raise TransformError("compose bevat geen services") + + for svc in doc["services"].values(): + if not isinstance(svc, dict): + continue + # `networks:` mag een lijst of een mapping zijn; allebei aanvullen. + huidig = svc.get("networks") + if huidig is None: + svc["networks"] = [network] + elif isinstance(huidig, list): + if network not in huidig: + huidig.append(network) + elif isinstance(huidig, dict): + huidig.setdefault(network, None) + + netwerken = doc.get("networks") + if not isinstance(netwerken, dict): + netwerken = {} + netwerken.setdefault(network, {"external": True}) + doc["networks"] = netwerken + + return yaml.safe_dump(doc, sort_keys=False, default_flow_style=False, + allow_unicode=True, width=120) + + def published_ports(compose_text: str) -> list[str]: """Alle host-poorten die dit compose-bestand publiceert (voor de UI).""" try: diff --git a/server-up/core/networks.py b/server-up/core/networks.py index 5d5f640..f432c3b 100644 --- a/server-up/core/networks.py +++ b/server-up/core/networks.py @@ -502,6 +502,29 @@ def create(net: dict) -> tuple[bool, str]: return True, "Netwerk aangemaakt." +def ensure_shared(name: str) -> tuple[bool, str]: + """Zorg dat het gedeelde bridge-netwerk bestaat waarop stacks elkaar vinden. + + Anders dan de macvlan-netwerken heeft dit er geen configuratie voor nodig: + een gewoon bridge-netwerk volstaat, want het gaat alleen om naamresolutie + tussen containers van verschillende compose-projecten. + """ + if not _NAME_RE.match(name or ""): + return False, "Ongeldige netwerknaam." + if exists(name): + return True, "" + r = docker._run([docker._bin(), "network", "create", "-d", "bridge", name], + timeout=30) + if r.returncode != 0: + melding = (r.stderr or r.stdout).strip() + # Bij gelijktijdige installaties kan een ander proces hem net hebben + # aangemaakt; dat is geen fout. + if "already exists" in melding.lower() or exists(name): + return True, "" + return False, melding[:300] + return True, "" + + def remove(name: str) -> tuple[bool, str]: if not _NAME_RE.match(name or ""): return False, "Ongeldige netwerknaam." diff --git a/server-up/templates/index.html b/server-up/templates/index.html index c2f90ab..0678d19 100644 --- a/server-up/templates/index.html +++ b/server-up/templates/index.html @@ -1119,6 +1119,37 @@ tailwind.config = {
Wijzig voor meerdere installaties
+ +