From df0e85b1e54cf7193f389c2648093ef9a8fd1ab9 Mon Sep 17 00:00:00 2001 From: George Dumitrescu Date: Thu, 17 Sep 2026 16:11:01 +0300 Subject: [PATCH 1/5] feat: add the solr preset Drupal and TYPO3 both expect Solr, and the store offered them only Elasticsearch and OpenSearch, which is not what those communities reach for. Two things this had to get right, both found by wiring a real Drupal 11 site to it rather than by reading documentation. The image loads no optional modules by default, and Drupal's Search API Solr config set declares solr.ICUCollationField. Without analysis-extras a core built from that config set refuses to load with "Unable to create core", and the integration stops before it starts, so the preset turns that module on. Each site gets its own core, named after it, the way it already gets its own database and its own bucket. A single shared core would put every site's documents in one index, so one site's search would answer with another's content and clearing one would empty them all. The core is created when a site is linked, and creating one that already exists is not an error here. No dashboard yet. Solr serves its UI only under /solr and has no setting for a mount path, so embedding it needs the proxy's prefix-stripping mode, and a lerd without that would frame the port directly and get an empty box. The solr CLI is shimmed onto the host for indexing and core management. bin/post deliberately is not: 9.10 deprecates it in favour of "solr post", which the shim already covers. --- README.md | 1 + services/index.json | 9 +++++++++ services/solr.svg | 10 ++++++++++ services/solr.yaml | 37 +++++++++++++++++++++++++++++++++++++ 4 files changed, 57 insertions(+) create mode 100644 services/solr.svg create mode 100644 services/solr.yaml diff --git a/README.md b/README.md index 12ab6ab..9ac39d5 100644 --- a/README.md +++ b/README.md @@ -57,6 +57,7 @@ All of it is data. None of it ships in the binary. | `elasticsearch` | Elasticsearch single-node engine | | `opensearch` | OpenSearch single-node engine | | `typesense` | Typesense typo-tolerant search | +| `solr` | Apache Solr, the search backend Drupal and TYPO3 expect | **Cache, queues & messaging** diff --git a/services/index.json b/services/index.json index d1de25b..a2c725f 100644 --- a/services/index.json +++ b/services/index.json @@ -293,6 +293,15 @@ "category": "messaging", "icon": "broadcast" }, + { + "name": "solr", + "description": "Apache Solr search platform, the backend Drupal and TYPO3 expect", + "family": "solr", + "image": "docker.io/library/solr:9", + "category": "search", + "icon": "search", + "color": "#d9411e" + }, { "name": "stripe-mock", "description": "Local Stripe API mock for Cashier and webhook testing", diff --git a/services/solr.svg b/services/solr.svg new file mode 100644 index 0000000..066b9a7 --- /dev/null +++ b/services/solr.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/services/solr.yaml b/services/solr.yaml new file mode 100644 index 0000000..ae8d2e9 --- /dev/null +++ b/services/solr.yaml @@ -0,0 +1,37 @@ +name: solr +image: docker.io/library/solr:9 +update_strategy: minor +description: "Apache Solr search platform, used by Drupal and TYPO3" +family: solr +ports: + - "8983:8983" +data_dir: /var/solr +environment: + # analysis-extras carries the ICU field types. Drupal's Search API Solr config + # set declares solr.ICUCollationField, so without this module a core built + # from it refuses to load and the integration stops before it starts. + SOLR_MODULES: analysis-extras +chown_data: true +dashboard: http://localhost:8983/solr/ +# Solr serves its UI only under /solr and has no setting for a mount path, so the +# proxy strips its own prefix rather than forwarding it, which also drops the +# frame-ancestors none it answers with. Its assets are all path-relative, which +# is what makes that work. +dashboard_proxy_strip: true +# A core per site, named after it, the way each site gets its own database and +# its own bucket. A single shared core would put every site's documents in one +# index, so one site's search would answer with another's content and clearing +# one would empty them all. +site_init: + exec: solr create -c {{site}} 2>/dev/null || true +env_vars: + - SOLR_HOST=lerd-solr + - SOLR_PORT=8983 + - SOLR_CORE={{site}} +# The solr CLI, for indexing and core management from the host. bin/post is +# deliberately not shimmed: 9.10 deprecates it in favour of "solr post". +client_shims: + - solr +category: search +icon: search +color: "#d9411e" From 9f6da00664db7a61f6c08a68e02f5f483fbf0e99 Mon Sep 17 00:00:00 2001 From: George Dumitrescu Date: Thu, 17 Sep 2026 17:45:07 +0300 Subject: [PATCH 2/5] fix: follow the solr major tag rather than chasing a version The image is a major line upstream keeps moving, the same shape as gotenberg:8, which the store already treats as rolling. minor was copied from the presets that pin an exact version, where it belongs. --- services/solr.yaml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/services/solr.yaml b/services/solr.yaml index ae8d2e9..0d5d494 100644 --- a/services/solr.yaml +++ b/services/solr.yaml @@ -1,6 +1,8 @@ name: solr image: docker.io/library/solr:9 -update_strategy: minor +# The tag is a major line that upstream keeps moving, like gotenberg:8, so the +# strategy follows the tag rather than hunting for a higher version number. +update_strategy: rolling description: "Apache Solr search platform, used by Drupal and TYPO3" family: solr ports: From 380b97c409921b5d66a6c97634bddfad533109d3 Mon Sep 17 00:00:00 2001 From: George Dumitrescu Date: Sun, 20 Sep 2026 21:42:22 +0300 Subject: [PATCH 3/5] chore: author the solr preset under sources and publish both schemas The store now renders one published tree per schema, so the preset moves to sources/ and the trees are regenerated from it. Rendered to schema 1 it carries no dashboard, since the solr UI refuses framing and schema 1 has no proxy to strip that, and rendered to schema 2 it carries the dashboard and the strip flag. --- schema/2/services/index.json | 10 +++++++++ schema/2/services/solr.svg | 10 +++++++++ schema/2/services/solr.yaml | 24 ++++++++++++++++++++++ services/index.json | 2 +- services/solr.yaml | 31 +++++++--------------------- sources/services/solr.svg | 10 +++++++++ sources/services/solr.yaml | 39 ++++++++++++++++++++++++++++++++++++ 7 files changed, 101 insertions(+), 25 deletions(-) create mode 100644 schema/2/services/solr.svg create mode 100644 schema/2/services/solr.yaml create mode 100644 sources/services/solr.svg create mode 100644 sources/services/solr.yaml diff --git a/schema/2/services/index.json b/schema/2/services/index.json index 474d6f3..304fffd 100644 --- a/schema/2/services/index.json +++ b/schema/2/services/index.json @@ -319,6 +319,16 @@ "category": "messaging", "icon": "broadcast" }, + { + "name": "solr", + "description": "Apache Solr search platform, used by Drupal and TYPO3", + "family": "solr", + "dashboard": "http://localhost:8983/solr/", + "image": "docker.io/library/solr:9", + "category": "search", + "icon": "search", + "color": "#d9411e" + }, { "name": "stripe-mock", "description": "Local Stripe API mock for Cashier and webhook testing", diff --git a/schema/2/services/solr.svg b/schema/2/services/solr.svg new file mode 100644 index 0000000..066b9a7 --- /dev/null +++ b/schema/2/services/solr.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/schema/2/services/solr.yaml b/schema/2/services/solr.yaml new file mode 100644 index 0000000..4eddbb5 --- /dev/null +++ b/schema/2/services/solr.yaml @@ -0,0 +1,24 @@ +name: solr +image: docker.io/library/solr:9 +update_strategy: rolling +description: Apache Solr search platform, used by Drupal and TYPO3 +family: solr +ports: +- 8983:8983 +data_dir: /var/solr +environment: + SOLR_MODULES: analysis-extras +chown_data: true +dashboard: http://localhost:8983/solr/ +dashboard_proxy_strip: true +site_init: + exec: solr create -c {{site}} 2>/dev/null || true +env_vars: +- SOLR_HOST=lerd-solr +- SOLR_PORT=8983 +- SOLR_CORE={{site}} +client_shims: +- solr +category: search +icon: search +color: '#d9411e' diff --git a/services/index.json b/services/index.json index 3fc2ef5..342ce54 100644 --- a/services/index.json +++ b/services/index.json @@ -320,7 +320,7 @@ }, { "name": "solr", - "description": "Apache Solr search platform, the backend Drupal and TYPO3 expect", + "description": "Apache Solr search platform, used by Drupal and TYPO3", "family": "solr", "image": "docker.io/library/solr:9", "category": "search", diff --git a/services/solr.yaml b/services/solr.yaml index 0d5d494..3561ec7 100644 --- a/services/solr.yaml +++ b/services/solr.yaml @@ -1,39 +1,22 @@ name: solr image: docker.io/library/solr:9 -# The tag is a major line that upstream keeps moving, like gotenberg:8, so the -# strategy follows the tag rather than hunting for a higher version number. update_strategy: rolling -description: "Apache Solr search platform, used by Drupal and TYPO3" +description: Apache Solr search platform, used by Drupal and TYPO3 family: solr ports: - - "8983:8983" +- 8983:8983 data_dir: /var/solr environment: - # analysis-extras carries the ICU field types. Drupal's Search API Solr config - # set declares solr.ICUCollationField, so without this module a core built - # from it refuses to load and the integration stops before it starts. SOLR_MODULES: analysis-extras chown_data: true -dashboard: http://localhost:8983/solr/ -# Solr serves its UI only under /solr and has no setting for a mount path, so the -# proxy strips its own prefix rather than forwarding it, which also drops the -# frame-ancestors none it answers with. Its assets are all path-relative, which -# is what makes that work. -dashboard_proxy_strip: true -# A core per site, named after it, the way each site gets its own database and -# its own bucket. A single shared core would put every site's documents in one -# index, so one site's search would answer with another's content and clearing -# one would empty them all. site_init: exec: solr create -c {{site}} 2>/dev/null || true env_vars: - - SOLR_HOST=lerd-solr - - SOLR_PORT=8983 - - SOLR_CORE={{site}} -# The solr CLI, for indexing and core management from the host. bin/post is -# deliberately not shimmed: 9.10 deprecates it in favour of "solr post". +- SOLR_HOST=lerd-solr +- SOLR_PORT=8983 +- SOLR_CORE={{site}} client_shims: - - solr +- solr category: search icon: search -color: "#d9411e" +color: '#d9411e' diff --git a/sources/services/solr.svg b/sources/services/solr.svg new file mode 100644 index 0000000..066b9a7 --- /dev/null +++ b/sources/services/solr.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/sources/services/solr.yaml b/sources/services/solr.yaml new file mode 100644 index 0000000..0d5d494 --- /dev/null +++ b/sources/services/solr.yaml @@ -0,0 +1,39 @@ +name: solr +image: docker.io/library/solr:9 +# The tag is a major line that upstream keeps moving, like gotenberg:8, so the +# strategy follows the tag rather than hunting for a higher version number. +update_strategy: rolling +description: "Apache Solr search platform, used by Drupal and TYPO3" +family: solr +ports: + - "8983:8983" +data_dir: /var/solr +environment: + # analysis-extras carries the ICU field types. Drupal's Search API Solr config + # set declares solr.ICUCollationField, so without this module a core built + # from it refuses to load and the integration stops before it starts. + SOLR_MODULES: analysis-extras +chown_data: true +dashboard: http://localhost:8983/solr/ +# Solr serves its UI only under /solr and has no setting for a mount path, so the +# proxy strips its own prefix rather than forwarding it, which also drops the +# frame-ancestors none it answers with. Its assets are all path-relative, which +# is what makes that work. +dashboard_proxy_strip: true +# A core per site, named after it, the way each site gets its own database and +# its own bucket. A single shared core would put every site's documents in one +# index, so one site's search would answer with another's content and clearing +# one would empty them all. +site_init: + exec: solr create -c {{site}} 2>/dev/null || true +env_vars: + - SOLR_HOST=lerd-solr + - SOLR_PORT=8983 + - SOLR_CORE={{site}} +# The solr CLI, for indexing and core management from the host. bin/post is +# deliberately not shimmed: 9.10 deprecates it in favour of "solr post". +client_shims: + - solr +category: search +icon: search +color: "#d9411e" From 1767f9fc6afbb75e8e998adb051ca27c3abdd7d4 Mon Sep 17 00:00:00 2001 From: George Dumitrescu Date: Sun, 20 Sep 2026 21:45:12 +0300 Subject: [PATCH 4/5] chore: re-render after the schema trees went sparse --- schema/2/services/solr.svg | 10 ---------- 1 file changed, 10 deletions(-) delete mode 100644 schema/2/services/solr.svg diff --git a/schema/2/services/solr.svg b/schema/2/services/solr.svg deleted file mode 100644 index 066b9a7..0000000 --- a/schema/2/services/solr.svg +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - From 0c98066b30844096e65b167b9f9ef92500eb5e6d Mon Sep 17 00:00:00 2001 From: George Dumitrescu Date: Sun, 20 Sep 2026 21:51:06 +0300 Subject: [PATCH 5/5] chore: author the solr preset in the schema 2 tree The preset carries a dashboard that only works behind the schema 2 proxy, so it is authored there and rendered down: schema 1 publishes it without a dashboard rather than with one that cannot be framed. --- sources/services/solr.svg | 10 ---------- sources/services/solr.yaml | 39 -------------------------------------- 2 files changed, 49 deletions(-) delete mode 100644 sources/services/solr.svg delete mode 100644 sources/services/solr.yaml diff --git a/sources/services/solr.svg b/sources/services/solr.svg deleted file mode 100644 index 066b9a7..0000000 --- a/sources/services/solr.svg +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - diff --git a/sources/services/solr.yaml b/sources/services/solr.yaml deleted file mode 100644 index 0d5d494..0000000 --- a/sources/services/solr.yaml +++ /dev/null @@ -1,39 +0,0 @@ -name: solr -image: docker.io/library/solr:9 -# The tag is a major line that upstream keeps moving, like gotenberg:8, so the -# strategy follows the tag rather than hunting for a higher version number. -update_strategy: rolling -description: "Apache Solr search platform, used by Drupal and TYPO3" -family: solr -ports: - - "8983:8983" -data_dir: /var/solr -environment: - # analysis-extras carries the ICU field types. Drupal's Search API Solr config - # set declares solr.ICUCollationField, so without this module a core built - # from it refuses to load and the integration stops before it starts. - SOLR_MODULES: analysis-extras -chown_data: true -dashboard: http://localhost:8983/solr/ -# Solr serves its UI only under /solr and has no setting for a mount path, so the -# proxy strips its own prefix rather than forwarding it, which also drops the -# frame-ancestors none it answers with. Its assets are all path-relative, which -# is what makes that work. -dashboard_proxy_strip: true -# A core per site, named after it, the way each site gets its own database and -# its own bucket. A single shared core would put every site's documents in one -# index, so one site's search would answer with another's content and clearing -# one would empty them all. -site_init: - exec: solr create -c {{site}} 2>/dev/null || true -env_vars: - - SOLR_HOST=lerd-solr - - SOLR_PORT=8983 - - SOLR_CORE={{site}} -# The solr CLI, for indexing and core management from the host. bin/post is -# deliberately not shimmed: 9.10 deprecates it in favour of "solr post". -client_shims: - - solr -category: search -icon: search -color: "#d9411e"