Service naming migration plan¶
Review document for a piecewise, low-blast rename toward:
{scope}--{service}--{function}
No renames in this change set — only the plan. See also Architecture overview.
Invariant: Compose service key = container_name = Docker DNS name = target string. Never shorten (no nextcloud--app; always nextcloud--nextcloud--app).
Related risk: soda_scs_manager.settings, PHP defaults, .env host values, and scripts hardcode several Docker DNS names. Changing Compose without aliases or config cutover will break Manager, WissKI SPARQL, mounts, and pre-install scripts.
1. Goals and non-goals¶
| Do | Don't (yet) |
|---|---|
| Three-part names: scope (Compose env) · service (software) · function (role) | Big-bang rename of all stacks in one PR |
| Alias window so old DNS keeps resolving | Rename Traefik public hostnames / domains |
| Inventory every consumer before each wave | Rename WissKI instance containers first |
| Cut over Manager settings / Env after aliases work | Rename COMPOSE_FILE directory paths in the same waves |
| Verify with ripgrep + smoke tests | Rely on “we updated compose only” |
Stay explicit (nextcloud--nextcloud--app) |
Collapse when service ≡ scope |
Out of scope for early waves: public domains (drive.*, auth.*), OIDC client IDs based on URLs, Let's Encrypt cert names, Jupyter notebook prefix jupyter- (DockerSpawner), git/submodule folder names.
2. Naming model¶
Canonical definitions (scopes, service tokens, functions, delimiter rules): Service naming vocabulary.
Summary: {scope}--{service}--{function} — Compose env · software · role. Always explicit (nextcloud--nextcloud--app). Compose service key = container_name = DNS.
Compose service key and container_name must equal the target. During each wave, keep the Today value as a Docker network alias until cutover.
3. Complete Ist → Soll¶
During each wave: introduce Target as service key + container_name, keep Today as network alias until Env, scripts, Manager settings, and code fallbacks no longer reference Today.
3.1 Containers / Compose services¶
| Wave | Scope | Today (DNS / container_name) |
Target {scope}--{service}--{function} |
Alias until cutover | Hot consumers (non-exhaustive) |
|---|---|---|---|---|---|
| A | core |
scs--echo |
core--echo--app |
scs--echo |
compose, docs |
| A | health |
scs--health |
health--health--app |
scs--health |
compose, Traefik labels, Health docs |
| B | core |
nextcloud-mounter |
core--rclone--sidecar |
nextcloud-mounter |
NEXTCLOUD_MOUNTER_RC_URL, Manager override depends_on, NextcloudMounterClient.php fallback |
| C | core |
scs--database |
core--mariadb--db |
scs--database |
.env *_DB_HOST, JDBC KC_DB_URL, MYSQL_HOST, DB_HOST, start.sh, all pre-install/backup docker exec, soda_scs_manager.settings dbHost, PHP fallbacks |
| D | core |
scs--reverse-proxy |
core--traefik--edge |
scs--reverse-proxy |
many depends_on, logs/runbooks; Traefik router label IDs may lag |
| E | core |
scs--portainer |
core--portainer--app |
scs--portainer |
Portainer volume; Manager Portainer host often public HTTPS — still verify internal DNS |
| E | dbms |
scs--phpmyadmin |
dbms--phpmyadmin--app |
scs--phpmyadmin |
phpMyAdmin override |
| E | dbms |
scs--forward-auth |
dbms--forwardauth--proxy |
scs--forward-auth |
pair with phpMyAdmin |
| F | opengdb |
scs--rdf4j |
opengdb--rdf4j--db |
scs--rdf4j |
Compose key today rdf4j; RDF4J_HOSTNAME |
| F | opengdb |
scs--authproxy |
opengdb--authproxy--proxy |
scs--authproxy |
Manager triplestore.generalSettings.internalHost, form default, WissKI TS_*, apply-performance-tuning.bash, DJANGO_ALLOWED_HOSTS |
| F | opengdb |
scs--outproxy |
opengdb--outproxy--proxy |
scs--outproxy |
JVM -Dhttp.proxyHost=… |
| F | opengdb |
scs--opengdb-proxy |
opengdb--nginx--edge |
scs--opengdb-proxy |
Compose key today nginx |
| G | core |
scs--access-proxy |
core--accessproxy--proxy or remove |
scs--access-proxy |
accessProxy.generalSettings.containerName; not in current root compose — confirm dead |
| H | keycloak |
keycloak--keycloak |
keycloak--keycloak--app |
keycloak--keycloak |
Compose key keycloak; DB already via core--mariadb--db |
| H | manager |
scs-manager--drupal |
manager--drupal--app |
scs-manager--drupal |
Traefik, scs-drush habits, overrides |
| H | manager |
scs-manager--redis |
manager--redis--cache |
scs-manager--redis |
|
| H | manager |
scs-manager--database |
(no-op — stay disabled) | — | Uses shared DB; do not revive |
| H | manager |
scs-manager--varnish |
manager--varnish--edge |
scs-manager--varnish |
Often disabled; rename only if re-enabled |
| H | nextcloud |
nextcloud--nextcloud |
nextcloud--nextcloud--app |
nextcloud--nextcloud |
OnlyOffice internal URLs, occ |
| H | nextcloud |
nextcloud--redis |
nextcloud--redis--cache |
nextcloud--redis |
NEXTCLOUD_REDIS_HOST |
| H | nextcloud |
nextcloud--nextcloud-reverse-proxy |
nextcloud--nginx--edge |
nextcloud--nextcloud-reverse-proxy |
Traefik → nginx → FPM |
| H | nextcloud |
nextcloud--onlyoffice-document-server |
nextcloud--ods--app |
nextcloud--onlyoffice-document-server |
Document Server |
| H | nextcloud |
nextcloud--onlyoffice-reverse-proxy |
nextcloud--ods--edge |
nextcloud--onlyoffice-reverse-proxy |
nginx in front of ODS; service=ods, function=edge |
| H | jupyterhub |
jupyterhub--jupyterhub or ${JUPYTERHUB_SERVICE_NAME} |
jupyterhub--jupyterhub--app |
old value | Set JUPYTERHUB_SERVICE_NAME to target or stop using env for container_name; do not conflate with public Host slug |
| H | jupyterhub |
jupyterhub--image-builder |
jupyterhub--spawner--builder |
jupyterhub--image-builder |
Build-only |
| H | webprotege |
webprotege |
webprotege--webprotege--app |
webprotege |
Manager webprotege.generalSettings.apiBaseUrl (http://webprotege:8080) |
| H | webprotege |
webprotege-mongodb |
webprotege--mongodb--db |
webprotege-mongodb |
Compose key often wpmongo |
| H | website |
scs-project-website--drupal |
website--drupal--app |
old name | Optional stack |
| H | website |
scs-project-website--varnish |
website--varnish--edge |
old name | |
| H | website |
scs-project-website--redis |
website--redis--cache |
old name | |
| H | website |
scs-project-website--database |
website--mariadb--db or drop |
old name | Prefer shared core--mariadb--db |
| Z | (deferred) | {SERVICE_NAME}--varnish |
TBD — see Wave Z | old pattern | Not in this migration cycle |
| Z | (deferred) | {SERVICE_NAME}--drupal |
TBD | old pattern | Needs wisski-base-stack release |
| Z | (deferred) | {SERVICE_NAME}--redis |
TBD | old pattern | + Manager Portainer env + existing stacks |
| — | — | jupyter-{username} |
unchanged | — | DockerSpawner; not platform scope |
Platform rename count (excl. WissKI / notebooks): 28 targets + 1 optional dead (access-proxy) + 1 no-op (scs-manager--database). WissKI is a separate epic (Wave Z), not counted here.
3.2 Networks¶
| Wave | Today | Target | Notes |
|---|---|---|---|
| B | nextcloud-mounter-net |
core--rclone--net |
Or keep old name: long; Manager + sidecar must share |
| D | reverse-proxy |
core--traefik--net |
Highest operational blast. Prefer keep Docker network name: reverse-proxy forever and only document it as edge net; rename optional/late |
| H | webprotege (named net) |
webprotege--webprotege--net |
If still isolated |
| Z | {SERVICE_NAME}_internal |
TBD (wisski--{id}--net or keep) |
Deferred with Wave Z |
3.3 Named volumes (optional)¶
Prefer keep external name: on the existing volume (no data copy). Logical Compose keys may follow the new scheme later.
| Wave | Today (volume name) | Logical target key | Recommendation |
|---|---|---|---|
| C | scs--database-data |
core--mariadb--db-data |
Keep old name: |
| D | scs--reverse-proxy-certificates |
core--traefik--edge-certs |
Keep old name: (ACME) |
| E | scs--portainer-data |
core--portainer--app-data |
Keep old name: |
| B | nextcloud-mounter-cache |
core--rclone--sidecar-cache |
Keep old name: |
| H | scs-manager--redis-data etc. |
manager--redis--cache-data … |
Keep old name: |
| H | Nextcloud / ODS volumes | nextcloud--…--data |
Keep old name: |
| H | webprotege-data |
webprotege--webprotege--app-data |
Keep old name: |
| F | rdf4j-data, authproxy-data |
opengdb--…--data |
Keep old name: |
| — | scs--shared-data |
core--shared--data |
Keep old name: |
3.4 Explicitly not renamed¶
| Item | Reason |
|---|---|
Public domains / Traefik Host(...) |
Certs, OIDC redirects, bookmarks |
COMPOSE_FILE paths |
e.g. scs-nextcloud-stack/…, 00_custom_configs/scs-nextcloud-stack/… — directory layout; separate refactor, never same PR as container DNS |
Env key names (KC_DB_HOST, …) |
Values change to new DNS; renaming keys is optional later |
KC_SERVICE_NAME=auth, public Portainer slugs |
URL fragments, not container DNS |
Notebooks jupyter-* |
Spawner convention |
| Submodule / stack folder names | Out of band |
4. Fallstrick-Klassen (immer alle prüfen)¶
Before each wave, search Today and planned Target; tick every class.
4.1 Environment (.env / example-env)¶
Central DNS knobs: SCS_CONTAINER_* (see Naming vocabulary — Environment variables). Scripts source 01_scripts/global/scs-container-names.bash.
| Kind | Examples | Action |
|---|---|---|
| Docker DNS values | SCS_CONTAINER_DATABASE, KC_DB_HOST=${SCS_CONTAINER_DATABASE}, … |
Flip once Target exists (+ alias) |
| JDBC / composed URLs | Keycloak KC_DB_URL uses ${SCS_CONTAINER_DATABASE} |
Covered if container var flips |
| Mounter | NEXTCLOUD_MOUNTER_RC_URL / SCS_CONTAINER_NEXTCLOUD_MOUNTER |
PHP via SodaScsDockerDns |
JUPYTERHUB_SERVICE_NAME |
Used as container_name today |
Decouple from public Host |
| Public slug env | KC_SERVICE_NAME, SCS_PORTAINER_SERVICE_NAME |
Do not treat as container rename |
COMPOSE_FILE= |
File paths under stack dirs | Do not change when renaming containers |
4.2 Compose¶
- Service keys,
container_name,depends_on,networks, volume keys extra_hosts,DJANGO_ALLOWED_HOSTS, JVM-Dhttp.proxyHost=scs--outproxy- Traefik router/service label IDs (can lag; cosmetic/scripts)
00_custom_configs/**and already copied overrides in stack dirs (start.shmay skip overwrite)
4.3 soda_scs_manager config¶
| Key | Typical Today | Target after flip |
|---|---|---|
dbHost |
scs--database |
core--mariadb--db |
triplestore.generalSettings.internalHost |
http://scs--authproxy:8000 |
http://opengdb--authproxy--proxy:8000 |
webprotege.generalSettings.apiBaseUrl |
http://webprotege:8080 |
http://webprotege--webprotege--app:8080 |
accessProxy.generalSettings.containerName |
scs--access-proxy |
core--accessproxy--proxy or remove |
Also update on-disk copies:
scs-manager-stack/custom_configs/soda_scs_manager.settings.ymlscs-manager-stack/volumes/drupal-root/custom_configs/…- live config in MariaDB (export before / import or
config:seton cutover)
Portainer / Jupyter / Nextcloud public baseUrls in settings usually stay on HTTPS domains — still verify nothing points at old Docker DNS.
4.4 Code hardcodes (soda_scs_manager + scripts)¶
Prefer env/settings; remaining defaults live in SodaScsDockerDns and scs-container-names.bash.
| Location | Mechanism |
|---|---|
SodaScsDockerDns |
SCS_CONTAINER_*, INTERNAL_TS_BASE, NEXTCLOUD_MOUNTER_RC_URL |
SodaScsServiceHelpers / SodaScsSqlComponentActions |
settings dbHost → env → default |
NextcloudMounterClient |
env / Settings.php → SodaScsDockerDns::nextcloudMounterRcUrl() |
SodaScsSettingsForm |
form defaults from SodaScsDockerDns |
start.sh, 01_scripts/** |
source scs-container-names.bash, use "${SCS_CONTAINER_DATABASE}" etc. |
| OpenGDB / Keycloak / Nextcloud overrides | ${SCS_CONTAINER_*} in connection env |
4.5 Ops / external¶
- Cron, systemd (
scs-nextcloud-mounts.service— mostly paths, not DNS) - Health dashboard container listing
- Portainer-deployed WissKI env (frozen
TS_*) - Operator muscle memory (
docker compose logs scs--reverse-proxy)
5. Mandatory procedure per wave¶
1. Freeze + backup (DB + export soda_scs_manager.settings)
2. Ripgrep inventory for Today (and Target collisions)
3. Compose: add Target service + container_name; alias Today on shared network(s)
4. Recreate only affected containers
5. Smoke DNS: getent/curl Today AND Target from each consumer
6. Flip consumers: .env values, overrides, scripts → Target
7. Flip soda_scs_manager.settings + PHP defaults + custom YAML copies
8. Smoke Manager (DB provision, mounts, Portainer, SPARQL, WebProtégé API)
9. Soak; ripgrep Today == 0 in runtime paths; then remove alias
10. Docs + changelogs
Alias pattern¶
services:
core--mariadb--db:
container_name: core--mariadb--db
networks:
reverse-proxy:
aliases:
- scs--database # Today — keep until cutover done
Verification¶
OLD='scs--database'
NEW='core--mariadb--db'
rg -n -g '!**/node_modules/**' -g '!**/.git/**' -g '!**/vendor/**' "$OLD" .
docker compose exec manager--drupal--app getent hosts "$OLD" # after manager rename; use Today name during early waves
docker compose exec scs-manager--drupal getent hosts "$NEW"
scs-drush config:get soda_scs_manager.settings dbHost
scs-drush config:get soda_scs_manager.settings triplestore.generalSettings.internalHost
scs-drush config:get soda_scs_manager.settings webprotege.generalSettings.apiBaseUrl
scs-drush config:get soda_scs_manager.settings accessProxy.generalSettings.containerName
scs-drush config:get soda_scs_manager.settings --format=yaml | rg -n 'scs--|webprotege:|authproxy|mounter|nextcloud--'
6. Wave plan (piecewise)¶
Wave 0 — Prep¶
- [x] Env layer
SCS_CONTAINER_*+ scripts +SodaScsDockerDns(dev, 2026-09-08) - [ ] Export
soda_scs_manager.settings(prime) - [x] Confirm: no
COMPOSE_FILEpath renames in container waves
Wave A — core--echo--app, health--health--app¶
- [x] Introduced with aliases
scs--echo/scs--health(2026-09-08) - [ ] Soak, then drop aliases
Low coupling; prove alias + recreate pattern.
Wave B — core--rclone--sidecar¶
- [x] Alias
nextcloud-mounter(both nets) - [ ] Flip
NEXTCLOUD_MOUNTER_RC_URL/SCS_CONTAINER_NEXTCLOUD_MOUNTERafter soak - [x] Network: keep
nextcloud-mounter-netname initially - [x] Smoke: rc-API old+new DNS;
scs:nextcloud-statusreachable; reconcile mounted=5
Wave C — core--mariadb--db ⚠¶
- [x] Alias
scs--database(long soak); compose key +container_name=core--mariadb--db; volume stillscs--database-data(dev, 2026-09-08) - [x]
SCS_CONTAINER_DATABASE/ scripts /start.shuse the new name (docker execis not aliased) - [ ] Flip remaining
*_DB_HOST, JDBC,MYSQL_HOST, DrupalDB_HOST,dbHost, PHP fallbacks after soak - [ ] Smoke Keycloak, Manager, Nextcloud, phpMyAdmin, project DB CRUD
Wave D — core--traefik--edge¶
- [x] Alias
scs--reverse-proxy; compose key +container_name=core--traefik--edge(dev, 2026-09-08) - [x] Docker network
name: reverse-proxyunchanged; cert volume stillscs--reverse-proxy-certificates - [x] Traefik router label IDs still
scs--reverse-proxy(intentional lag) - [ ] Soak, then drop alias; optionally rename router labels later
Wave E — core--portainer--app, dbms--*¶
- [x] Aliases
scs--portainer/scs--phpmyadmin/scs--forward-auth(dev, 2026-09-08) - [x] Portainer volume still
scs--portainer-data; Traefik router label IDs lag - [x] Traefik
dbms-ssostill callshttp://scs--forward-auth:4181(alias; no Traefik recreate) - [ ] Soak, then flip middleware URL + drop aliases
Wave F — opengdb--* ⚠ Manager + WissKI¶
- [x] Aliases
scs--rdf4j/scs--authproxy/scs--outproxy/scs--opengdb-proxy(dev, 2026-09-08) - [x] Submodule compose keys parked on profile
opengdb-legacy-keys; new keys live in the override - [x]
INTERNAL_TS_BASE/ ManagerinternalHost/ WissKITS_*stillhttp://scs--authproxy:8000 - [x]
DJANGO_ALLOWED_HOSTSincludes both Today and Target - [ ] Flip
internalHost+ WissKITS_*+ drop aliases after soak
Wave G — access-proxy¶
- [x] Confirmed dead: no Compose service, no running container (dev, 2026-09-08)
- [x] Removed
SCS_CONTAINER_ACCESS_PROXYfrom env helper,example-env, Manager overrides - [ ] Optional: delete leftover
accessProxy.*fromsoda_scs_manager.settingsif the module still stores it
Wave H — one Compose env per cycle¶
Suggested order:
- [x]
keycloak--keycloak--app(aliaskeycloak--keycloak; Traefik router labels lag; publicKC_DOMAINunchanged) - [x]
manager--drupal--app/manager--redis--cache(aliasesscs-manager--drupal/scs-manager--redis; Traefik router IDs lag;scs-drushhost alias updated) - [x]
nextcloud--*all five (aliases keep nginx upstreams,REDIS_HOST, OnlyOfficeDocumentServerInternalUrl; Traefik router IDs lag;NEXTCLOUD_REDIS_HOSTstillnextcloud--redis) - [x]
jupyterhub--jupyterhub--app/jupyterhub--spawner--builder(JUPYTERHUB_SERVICE_NAME= Target for hub_connect_ip; notebooksjupyter-{user}unchanged; Traefik router IDs lag) - [x]
webprotege--webprotege--app/webprotege--mongodb--db(aliases keepapiBaseUrl+webprotege.mongodb.host=wpmongo; Traefik label IDs lag) - [ ]
website--*if enabled — skipped on this host (stack not in liveCOMPOSE_FILE; prepare files later or leave until website is enabled)
Each: introduce+alias → flip env/scripts (docker exec / compose keys) → smoke → drop alias after soak.
Wave H3 — Nextcloud (dev, 2026-09-08)¶
- [x] Compose keys +
container_namefor all five; aliases keep Today DNS - [x]
SCS_CONTAINER_NEXTCLOUD/_REDIS/_EDGE/_ODS/_ODS_EDGEflipped - [x]
NEXTCLOUD_REDIS_HOSTstillnextcloud--redis; nginxupstream/ OnlyOfficeDocumentServerInternalUrlstill Today names - [x] Traefik router label IDs lag (
nextcloud--nextcloud-reverse-proxy,nextcloud--onlyoffice-reverse-proxy) - [x] Volumes keep
name:(nextcloud-data,onlyoffice-data,onlyoffice-log) - [ ] Drop aliases + flip
REDIS_HOST/ nginx.conf / occ OnlyOffice internals after soak
Wave H4 — JupyterHub (dev, 2026-09-08)¶
- [x] Compose keys +
container_name:jupyterhub--jupyterhub--app,jupyterhub--spawner--builder - [x] Alias
jupyterhub--jupyterhubonreverse-proxy; builder is build-only (replicas: 0) - [x]
JUPYTERHUB_SERVICE_NAME+SCS_CONTAINER_JUPYTERHUB/_BUILDERflipped to Target - [x] Traefik router label IDs lag (
jupyterhub--jupyterhub) - [x] Notebook containers
jupyter-{user}unchanged - [ ] Drop hub alias after soak
Wave H5 — WebProtégé (dev, 2026-09-08)¶
- [x] Compose keys +
container_name:webprotege--webprotege--app,webprotege--mongodb--db - [x] Aliases
webprotege(app),wpmongo+webprotege-mongodb(mongo) - [x]
SCS_CONTAINER_WEBPROTEGE/_MONGODBflipped; ManagerapiBaseUrlstillhttp://webprotege:8080 - [x]
webprotege.mongodb.host=wpmongounchanged (alias) - [x] Volumes keep
name:(webprotege-data,mongodb-data); networkname: webprotege - [x] Traefik router/service label IDs lag (
webprotege,webprotege-nocache, …) - [ ] Flip
apiBaseUrl+mongodb.host+ drop aliases after soak
Wave Z — WissKI instances — TODO / deferred¶
Not part of the current platform rename. Leave running stacks as {SERVICE_NAME}--{drupal|varnish|redis} (e.g. wisski-mit-nextcloud-mount--drupal).
Why it is harder than Waves A–H:
- External Compose, not root
COMPOSE_FILE: wisski-base-stackdocker-compose.yml(local checkoutrepos/wisski-base-stack). Container names are${SERVICE_NAME}--drupal/--varnish/--redis; VarnishVARNISH_BACKEND_HOST=${SERVICE_NAME}--drupal. - Needs its own release of
wisski-base-stack(and likely Manager Portainer template / env wiring) before any live cutover. - Many living stacks via Portainer — rename is rolling redeploy, not one
docker compose up. - Scope token still open — early draft used
proj-{id}--drupal--app. Prefer something closer to Today’sSERVICE_NAME, e.g.wisski--{id}--drupal--app/wisski--{id}--varnish--edge/wisski--{id}--redis--cache(three segments, function vocabulary). Exact{id}mapping (slug vs Drupal project id vs currentSERVICE_NAME) is undecided.
Checklist when we pick this up:
- [ ] Decide scope/id scheme (
wisski--{id}--*vsproj-{id}--*vs keep{SERVICE_NAME}--*+ only add function) - [ ] Patch
wisski-base-stackcompose (container_name,VARNISH_BACKEND_HOST, Traefik label IDs, volumename:policy) - [ ] Tag/release
wisski-base-stack; point Manager/Portainer at the new tag - [ ] Migration path for existing stacks (alias soak vs recreate-only for new projects)
- [ ] Scripts (
01_scripts/wisski/*), docs, architecture inventory - [ ] Do not conflate with public Hosts (
*.wisski.…) or Nextcloud Team Folder labels
Until then: platform migration is done for shared stacks; WissKI stays on Today names.
7. PR slicing¶
| PR | Content |
|---|---|
| 0 | Docs: this convention + tables |
| A… | Per wave: introduce Target + Today alias |
| *2 | Flip Env / scripts / Manager / PHP to Target |
| *3 | Remove Today alias after soak |
Never combine alias removal with unrelated features. Never mix container DNS renames with COMPOSE_FILE directory moves.
8. Rollback¶
- Backup Compose +
.env+ settings export. - While alias exists: revert flip commits only.
- After alias removed: restore alias first, then debug.
- Manager: restore
soda_scs_manager.settings. - WissKI: restore
TS_*/ SALZ or re-run tuning with oldINTERNAL_TS_BASE.
9. Open decisions¶
- Scope token for OpenGDB:
opengdb(above) vsts— prefer Compose-honestopengdb. - Health:
health--health--app(explicit) vs shorter — keep explicit. - Docker network
reverse-proxy: rename late / never? - Alias soak duration (staging / prime)?
- Prime settings cutover: Drush update hook vs manual
config:set? - ~~Is
scs--access-proxydead?~~ Yes — removed from compose/env (Wave G). - Confirm website keeps private MariaDB or moves to
core--mariadb--dbonly. - WissKI / Wave Z (deferred): Prefer
wisski--{id}--{drupal|varnish|redis}-style names overproj-{id}--*. Exact{id}(currentSERVICE_NAMEslug vs numeric project id) and whether the third segment is software (drupal) or function (app/edge/cache) — decide in thewisski-base-stackrelease, not in this deployment cycle.
See also¶
- Naming vocabulary
- Architecture overview
- Glossary
- Nextcloud mount sidecar
- WissKI stack —
internalHost - Pre-start steps —
start.sh/ DB bootstrap