Skip to content

Release of GeoNetwork 4.4.10 and 4.2.15#21331

Open
juanluisrp wants to merge 2 commits intodocker-library:masterfrom
juanluisrp:gn-4-4-10-and-4.2.15
Open

Release of GeoNetwork 4.4.10 and 4.2.15#21331
juanluisrp wants to merge 2 commits intodocker-library:masterfrom
juanluisrp:gn-4-4-10-and-4.2.15

Conversation

@juanluisrp
Copy link
Copy Markdown
Contributor

No description provided.

@juanluisrp juanluisrp requested a review from a team as a code owner April 27, 2026 16:44
@github-actions

This comment has been minimized.

tianon
tianon previously approved these changes Apr 28, 2026
Copy link
Copy Markdown
Member

@tianon tianon left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+ENV GN_DOWNLOAD_MD5=79cd931ac7fc0be044ec1f2dd44f3f96

As a heads-up: MD5 is cryptographically broken for integrity verification purposes -- SHA256 (and/or better on top, PGP signature verification if GeoNetwork provides it) would be a significant improvement. This isn't something you introduced in this PR, and I'm not going to block a version bump over it, but I'd love to see it addressed in a follow-up. 🙇

@tianon
Copy link
Copy Markdown
Member

tianon commented Apr 28, 2026

Oh, we've got some unsupported base images: 😅

  • geonetwork:4.2.15 (FROM jetty:9-jre8) -- completely unsupported base!
  • geonetwork:4.4.10 (FROM jetty:9-jre11) -- completely unsupported base!

#20765 (comment)

@tianon tianon dismissed their stale review April 28, 2026 00:13

unsupported base images need to be resolved

@github-actions
Copy link
Copy Markdown

Diff for ab05691:
diff --git a/_bashbrew-arches b/_bashbrew-arches
index 40e9122..044c900 100644
--- a/_bashbrew-arches
+++ b/_bashbrew-arches
@@ -2,3 +2,4 @@ amd64
 arm32v7
 arm64v8
 ppc64le
+s390x
diff --git a/_bashbrew-cat b/_bashbrew-cat
index 882874a..a6a9bd8 100644
--- a/_bashbrew-cat
+++ b/_bashbrew-cat
@@ -12,12 +12,12 @@ Architectures: amd64, arm32v7, arm64v8, ppc64le
 GitCommit: 17278beab34080c90454c0b7059bd6b49701f979
 Directory: 3.12.12/postgres
 
-Tags: 4.2.14, 4.2
-Architectures: amd64, arm64v8
-GitCommit: 6848a28591a23af0e326b56cd9dde0bf34bc1fe9
-Directory: 4.2.14
+Tags: 4.2.15, 4.2
+Architectures: amd64, arm32v7, arm64v8, ppc64le
+GitCommit: bd633f8817d0f9ac56662e668f1f38d746ed36e5
+Directory: 4.2.15
 
-Tags: 4.4.9, 4.4, 4, latest
-Architectures: amd64, arm64v8
-GitCommit: 8ad0acd56ed97a67ae07f8099b7ee255465946e4
-Directory: 4.4.9
+Tags: 4.4.10, 4.4, 4, latest
+Architectures: amd64, arm32v7, arm64v8, ppc64le, s390x
+GitCommit: bd633f8817d0f9ac56662e668f1f38d746ed36e5
+Directory: 4.4.10
diff --git a/_bashbrew-list b/_bashbrew-list
index 4ada7be..53fc90a 100644
--- a/_bashbrew-list
+++ b/_bashbrew-list
@@ -6,7 +6,7 @@ geonetwork:3.12.12
 geonetwork:3.12.12-postgres
 geonetwork:4
 geonetwork:4.2
-geonetwork:4.2.14
+geonetwork:4.2.15
 geonetwork:4.4
-geonetwork:4.4.9
+geonetwork:4.4.10
 geonetwork:latest
diff --git a/geonetwork_4.2/Dockerfile b/geonetwork_4.2/Dockerfile
index afb8405..0a7395a 100644
--- a/geonetwork_4.2/Dockerfile
+++ b/geonetwork_4.2/Dockerfile
@@ -1,40 +1,36 @@
-FROM jetty:9-jre8
+FROM tomcat:9-jre8
 
 ENV DATA_DIR=/catalogue-data
-ENV JAVA_OPTS="-Dorg.eclipse.jetty.annotations.AnnotationParser.LEVEL=OFF \
-        -Djava.security.egd=file:/dev/./urandom \
+ENV JAVA_OPTS="-Djava.security.egd=file:/dev/./urandom \
         -Djava.awt.headless=true \
         -Xms512M -Xss512M -Xmx2G -XX:+UseConcMarkSweepGC \
         -Dgeonetwork.resources.dir=${DATA_DIR}/resources \
         -Dgeonetwork.data.dir=${DATA_DIR} \
-        -Dgeonetwork.codeList.dir=/var/lib/jetty/webapps/geonetwork/WEB-INF/data/config/codelist \
-        -Dgeonetwork.schema.dir=/var/lib/jetty/webapps/geonetwork/WEB-INF/data/config/schema_plugins"
+        -Dgeonetwork.codeList.dir=/usr/local/tomcat/webapps/geonetwork/WEB-INF/data/config/codelist \
+        -Dgeonetwork.schema.dir=/usr/local/tomcat/webapps/geonetwork/WEB-INF/data/config/schema_plugins"
 
-USER root
 RUN apt-get -y update && \
     apt-get -y install --no-install-recommends \
         curl \
         unzip && \
     rm -rf /var/lib/apt/lists/* && \
     mkdir -p ${DATA_DIR} && \
-    chown -R jetty:jetty ${DATA_DIR} && \
-    mkdir -p /var/lib/jetty/webapps/geonetwork && \
-    chown -R jetty:jetty /var/lib/jetty/webapps/geonetwork
+    mkdir -p /usr/local/tomcat/webapps/geonetwork
 
-USER jetty
 ENV GN_FILE=geonetwork.war
-ENV GN_VERSION=4.2.14
-ENV GN_DOWNLOAD_MD5=1e53b8d5f98c28b1c08657c24f7f9581
+ENV GN_VERSION=4.2.15
+ENV GN_DOWNLOAD_MD5=79cd931ac7fc0be044ec1f2dd44f3f96
 
-RUN cd /var/lib/jetty/webapps/geonetwork/ && \
+RUN cd /usr/local/tomcat/webapps/geonetwork/ && \
      curl -fSL -o geonetwork.war \
      https://sourceforge.net/projects/geonetwork/files/GeoNetwork_opensource/v${GN_VERSION}/${GN_FILE}/download && \
      echo "${GN_DOWNLOAD_MD5} *geonetwork.war" | md5sum -c && \
      unzip -q geonetwork.war && \
      rm geonetwork.war
 
+COPY tomcat/server.xml /usr/local/tomcat/conf/server.xml
 COPY ./docker-entrypoint.sh /geonetwork-entrypoint.sh
 ENTRYPOINT ["/geonetwork-entrypoint.sh"]
-CMD ["java","-jar","/usr/local/jetty/start.jar"]
+CMD ["catalina.sh","run"]
 
 VOLUME [ "${DATA_DIR}" ]
diff --git a/geonetwork_4.2/docker-entrypoint.sh b/geonetwork_4.2/docker-entrypoint.sh
index 446a28a..afd263e 100755
--- a/geonetwork_4.2/docker-entrypoint.sh
+++ b/geonetwork_4.2/docker-entrypoint.sh
@@ -1,17 +1,17 @@
 #!/bin/bash
 set -e
 
-export JAVA_OPTIONS=${JAVA_OPTS}
+export CATALINA_OPTS="${JAVA_OPTIONS}"
 
-if ! command -v -- "$1" >/dev/null 2>&1 ; then
-	set -- java -jar "$JETTY_HOME/start.jar" "$@"
-fi
-
-if [[ "$1" = jetty.sh ]] || [[ $(expr "$*" : 'java .*/start\.jar.*$') != 0 ]]; then
-    # this is a command to run jetty
+if [[ "$1" = "catalina.sh" ]]; then
+    if [[ -n "${REMOTE_IP_INTERNAL_PROXIES}" ]]; then
+        sed -i "s@REMOTE_IP_INTERNAL_PROXIES_VALUE@${REMOTE_IP_INTERNAL_PROXIES//\\/\\\\}@" "${CATALINA_HOME}/conf/server.xml"
+    else
+        sed -i 's/ internalProxies="REMOTE_IP_INTERNAL_PROXIES_VALUE"//' "${CATALINA_HOME}/conf/server.xml"
+    fi
 
     # Sanity check: ES_HOST variable is mandatory
-    if [ -z "${ES_HOST}" ]; then
+    if [[ -z "${ES_HOST}" ]]; then
         cat >&2 <<- EOWARN
 			********************************************************************
 			WARNING: Environment variable ES_HOST is mandatory
@@ -27,39 +27,31 @@ if [[ "$1" = jetty.sh ]] || [[ $(expr "$*" : 'java .*/start\.jar.*$') != 0 ]]; t
         exit 2
     fi;
 
-    # Set Elasticsearch properties
-    if [ "${ES_HOST}" != "localhost" ]; then
-        sed -i "s#http://localhost:9200#${ES_PROTOCOL:="http"}://${ES_HOST}:${ES_PORT:="9200"}#g" "${JETTY_BASE}/webapps/geonetwork/WEB-INF/web.xml" ;
-        sed -i "s#es.host=localhost#es.host=${ES_HOST}#" "${JETTY_BASE}/webapps/geonetwork/WEB-INF/config.properties" ;
-    fi; 
-
-    if [ -n "${ES_PROTOCOL}" ] && [ "${ES_PROTOCOL}" != "http" ] ; then
-        sed -i "s#es.protocol=http#es.protocol=${ES_PROTOCOL}#" "${JETTY_BASE}/webapps/geonetwork/WEB-INF/config.properties" ;
-    fi
+    GN_WEBAPPS_DIR=/usr/local/tomcat/webapps/geonetwork
 
-    if [ -n "${ES_PORT}" ] && [ "$ES_PORT" != "9200" ] ; then
-        sed -i "s#es.port=9200#es.port=${ES_PORT}#" "${JETTY_BASE}/webapps/geonetwork/WEB-INF/config.properties" ;
-    fi
+    # config.properties resolves ES/Kibana settings via Spring SpEL systemEnvironment[...]
+    # lookups, so translate the legacy ES_*/KB_URL contract into the GEONETWORK_* names.
+    [[ -n "${ES_HOST}" ]]     && export GEONETWORK_ES_HOST="${ES_HOST}"
+    [[ -n "${ES_PORT}" ]]     && export GEONETWORK_ES_PORT="${ES_PORT}"
+    [[ -n "${ES_PROTOCOL}" ]] && export GEONETWORK_ES_PROTOCOL="${ES_PROTOCOL}"
+    [[ -n "${ES_USERNAME}" ]] && export GEONETWORK_ES_USERNAME="${ES_USERNAME}"
+    [[ -n "${ES_PASSWORD}" ]] && export GEONETWORK_ES_PASSWORD="${ES_PASSWORD}"
+    [[ -n "${KB_URL}" ]]      && export GEONETWORK_KIBANA_URL="${KB_URL}"
 
-    if [ -n "${ES_INDEX_RECORDS}" ] && [ "$ES_INDEX_RECORDS" != "gn-records" ] ; then
-        sed -i "s#es.index.records=gn-records#es.index.records=${ES_INDEX_RECORDS}#" "${JETTY_BASE}/webapps/geonetwork/WEB-INF/config.properties" ;
+    # web.xml proxy servlets still hard-code localhost targets — rewrite them.
+    if [[ "${ES_HOST}" != "localhost" ]]; then
+        sed -i "s#http://localhost:9200#${ES_PROTOCOL:=http}://${ES_HOST}:${ES_PORT:=9200}#g" "${GN_WEBAPPS_DIR}/WEB-INF/web.xml"
     fi
 
-    if [ "${ES_USERNAME}" != "" ] ; then
-        sed -i "s/es.username=.*/es.username=${ES_USERNAME}/" "${JETTY_BASE}/webapps/geonetwork/WEB-INF/config.properties" ;
+    if [[ -n "${KB_URL}" ]] && [[ "${KB_URL}" != "http://localhost:5601" ]]; then
+        sed -i "s#http://localhost:5601#${KB_URL}#g" "${GN_WEBAPPS_DIR}/WEB-INF/web.xml"
     fi
 
-    if [ "${ES_PASSWORD}" != "" ] ; then
-        sed -i "s/es.password=.*/es.password=${ES_PASSWORD}/" "${JETTY_BASE}/webapps/geonetwork/WEB-INF/config.properties" ;
+    if [[ -n "${ES_INDEX_RECORDS}" ]] && [[ "${ES_INDEX_RECORDS}" != "gn-records" ]]; then
+        sed -i "s#es.index.records=gn-records#es.index.records=${ES_INDEX_RECORDS}#" "${GN_WEBAPPS_DIR}/WEB-INF/config.properties"
     fi
 
-    if [ -n "${KB_URL}" ] && [ "$KB_URL" != "http://localhost:5601" ]; then
-        sed -i "s#kb.url=http://localhost:5601#kb.url=${KB_URL}#" "${JETTY_BASE}/webapps/geonetwork/WEB-INF/config.properties" ;
-        sed -i "s#http://localhost:5601#${KB_URL}#g" "${JETTY_BASE}/webapps/geonetwork/WEB-INF/web.xml" ;
-    fi
-
-    # Delegate on base image entrypoint to start jetty
-    exec /docker-entrypoint.sh "$@"
+    exec "$@"
 else
     exec "$@"
 fi
diff --git a/geonetwork_4.2/tomcat/server.xml b/geonetwork_4.2/tomcat/server.xml
new file mode 100644
index 0000000..ccdc9f4
--- /dev/null
+++ b/geonetwork_4.2/tomcat/server.xml
@@ -0,0 +1,67 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<Server port="8005" shutdown="SHUTDOWN">
+  <Listener className="org.apache.catalina.startup.VersionLoggerListener" />
+  <!-- APR connector and OpenSSL support using Tomcat Native -->
+  <Listener className="org.apache.catalina.core.AprLifecycleListener" SSLEngine="on" />
+  <!-- Prevent memory leaks due to use of particular java/javax APIs-->
+  <Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener" />
+  <Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" />
+  <Listener className="org.apache.catalina.core.ThreadLocalLeakPreventionListener" />
+
+  <GlobalNamingResources>
+    <Resource name="UserDatabase" auth="Container"
+              type="org.apache.catalina.UserDatabase"
+              description="User database that can be updated and saved"
+              factory="org.apache.catalina.users.MemoryUserDatabaseFactory"
+              pathname="conf/tomcat-users.xml" />
+  </GlobalNamingResources>
+
+  <Service name="Catalina">
+
+    <Connector port="8080" protocol="HTTP/1.1"
+               connectionTimeout="20000"
+               redirectPort="8443"
+               maxHttpHeaderSize="32768"
+               maxPostSize="500000"
+               maxParameterCount="4000" />
+
+    <Engine name="Catalina" defaultHost="localhost">
+
+      <Realm className="org.apache.catalina.realm.LockOutRealm">
+        <Realm className="org.apache.catalina.realm.UserDatabaseRealm"
+               resourceName="UserDatabase"/>
+      </Realm>
+
+      <Host name="localhost" appBase="webapps"
+            unpackWARs="true" autoDeploy="true">
+
+        <Valve className="org.apache.catalina.valves.RemoteIpValve"
+               remoteIpHeader="x-forwarded-for"
+               protocolHeader="x-forwarded-proto"
+               internalProxies="REMOTE_IP_INTERNAL_PROXIES_VALUE" />
+
+        <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
+               prefix="localhost_access_log" suffix=".txt"
+               pattern="%h %l %u %t &quot;%r&quot; %s %b"
+               requestAttributesEnabled="true" />
+
+      </Host>
+    </Engine>
+  </Service>
+</Server>
diff --git a/geonetwork_latest/Dockerfile b/geonetwork_latest/Dockerfile
index ddcfbb5..5e4a28a 100644
--- a/geonetwork_latest/Dockerfile
+++ b/geonetwork_latest/Dockerfile
@@ -1,4 +1,4 @@
-FROM jetty:9-jre11
+FROM tomcat:9-jre11
 
 ENV DATA_DIR=/catalogue-data
 ENV WEBAPP_CONTEXT_PATH=/geonetwork
@@ -11,21 +11,18 @@ ENV GN_CONFIG_PROPERTIES="-Dgeonetwork.dir=${DATA_DIR} \
 ENV JAVA_OPTS="-Djava.security.egd=file:/dev/./urandom -Djava.awt.headless=true \
         -Xms512M -Xss512M -Xmx2G -XX:+UseConcMarkSweepGC"
 
-USER root
 RUN apt-get -y update && \
     apt-get -y install --no-install-recommends \
         curl \
         unzip && \
     rm -rf /var/lib/apt/lists/* && \
     mkdir -p ${DATA_DIR} && \
-    chown -R jetty:jetty ${DATA_DIR} && \
     mkdir -p /opt/geonetwork && \
-    chown -R jetty:jetty /opt/geonetwork
+    mkdir -p /usr/local/tomcat/conf/Catalina/localhost
 
-USER jetty
 ENV GN_FILE=geonetwork.war
-ENV GN_VERSION=4.4.9
-ENV GN_DOWNLOAD_MD5=03104df014c7a96dccf96e421267fd9f
+ENV GN_VERSION=4.4.10
+ENV GN_DOWNLOAD_MD5=920136a8a502e52fd1bfa1417df83a05
 
 RUN cd /opt/geonetwork/ && \
      curl -fSL -o geonetwork.war \
@@ -34,12 +31,11 @@ RUN cd /opt/geonetwork/ && \
      unzip -q geonetwork.war && \
      rm geonetwork.war
 
-COPY jetty/geonetwork_context_template.xml /usr/local/share/geonetwork/geonetwork_context_template.xml
+COPY tomcat/geonetwork_context_template.xml /usr/local/share/geonetwork/geonetwork_context_template.xml
+COPY tomcat/server.xml /usr/local/tomcat/conf/server.xml
 COPY ./docker-entrypoint.sh /geonetwork-entrypoint.sh
 
-RUN java -jar /usr/local/jetty/start.jar --create-startd --add-module=http-forwarded
-
 ENTRYPOINT ["/geonetwork-entrypoint.sh"]
-CMD ["java","-jar","/usr/local/jetty/start.jar"]
+CMD ["catalina.sh","run"]
 
 VOLUME [ "${DATA_DIR}" ]
diff --git a/geonetwork_latest/docker-entrypoint.sh b/geonetwork_latest/docker-entrypoint.sh
index 57a9118..dee603e 100755
--- a/geonetwork_latest/docker-entrypoint.sh
+++ b/geonetwork_latest/docker-entrypoint.sh
@@ -1,24 +1,28 @@
 #!/bin/bash
 set -e
 
-export JAVA_OPTIONS="${JAVA_OPTS} ${GN_CONFIG_PROPERTIES}"
+export CATALINA_OPTS="${GN_CONFIG_PROPERTIES}"
 
 GN_BASE_DIR=/opt/geonetwork
 
-if ! command -v -- "$1" >/dev/null 2>&1 ; then
-	set -- java -jar "$JETTY_HOME/start.jar" "$@"
-fi
+if [[ "$1" = "catalina.sh" ]]; then
+    if [[ -n "${REMOTE_IP_INTERNAL_PROXIES}" ]]; then
+        sed -i "s@REMOTE_IP_INTERNAL_PROXIES_VALUE@${REMOTE_IP_INTERNAL_PROXIES//\\/\\\\}@" "${CATALINA_HOME}/conf/server.xml"
+    else
+        sed -i 's/ internalProxies="REMOTE_IP_INTERNAL_PROXIES_VALUE"//' "${CATALINA_HOME}/conf/server.xml"
+    fi
 
-if [[ "$1" = jetty.sh ]] || [[ $(expr "$*" : 'java .*/start\.jar.*$') != 0 ]]; then
-    # Customize context path
-    if [ ! -f "{$JETTY_BASE}/webapps/geonetwork.xml" ]; then
-        echo "Using $WEBAPP_CONTEXT_PATH for deploying the application"
-        cp /usr/local/share/geonetwork/geonetwork_context_template.xml "${JETTY_BASE}/webapps/geonetwork.xml"
-        sed -i "s#GEONETWORK_CONTEXT_PATH#${WEBAPP_CONTEXT_PATH}#" "${JETTY_BASE}/webapps/geonetwork.xml"
+    # Customize context path (Tomcat-style: file name = context path)
+    CONTEXT_NAME="${WEBAPP_CONTEXT_PATH#/}"
+    CONTEXT_FILE="${CATALINA_HOME}/conf/Catalina/localhost/${CONTEXT_NAME}.xml"
+    if [[ ! -f "${CONTEXT_FILE}" ]]; then
+        echo "Using ${WEBAPP_CONTEXT_PATH} for deploying the application"
+        mkdir -p "${CATALINA_HOME}/conf/Catalina/localhost"
+        cp /usr/local/share/geonetwork/geonetwork_context_template.xml "${CONTEXT_FILE}"
+        sed -i "s#GEONETWORK_CONTEXT_PATH#${WEBAPP_CONTEXT_PATH}#" "${CONTEXT_FILE}"
     fi
 
-    # Delegate on base image entrypoint to start jetty
-    exec /docker-entrypoint.sh "$@"
+    exec "$@"
 else
     exec "$@"
 fi
diff --git a/geonetwork_latest/jetty/geonetwork_context_template.xml b/geonetwork_latest/jetty/geonetwork_context_template.xml
deleted file mode 100644
index d667206..0000000
diff --git a/geonetwork_latest/tomcat/geonetwork_context_template.xml b/geonetwork_latest/tomcat/geonetwork_context_template.xml
new file mode 100644
index 0000000..59e0f7f
--- /dev/null
+++ b/geonetwork_latest/tomcat/geonetwork_context_template.xml
@@ -0,0 +1,3 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Context docBase="/opt/geonetwork" path="GEONETWORK_CONTEXT_PATH">
+</Context>
diff --git a/geonetwork_latest/tomcat/server.xml b/geonetwork_latest/tomcat/server.xml
new file mode 100644
index 0000000..a12607f
--- /dev/null
+++ b/geonetwork_latest/tomcat/server.xml
@@ -0,0 +1,189 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one or more
+  contributor license agreements.  See the NOTICE file distributed with
+  this work for additional information regarding copyright ownership.
+  The ASF licenses this file to You under the Apache License, Version 2.0
+  (the "License"); you may not use this file except in compliance with
+  the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+-->
+<!-- Note:  A "Server" is not itself a "Container", so you may not
+     define subcomponents such as "Valves" at this level.
+     Documentation at /docs/config/server.html
+ -->
+<Server port="8005" shutdown="SHUTDOWN">
+  <Listener className="org.apache.catalina.startup.VersionLoggerListener" />
+  <!-- Security listener. Documentation at /docs/config/listeners.html
+  <Listener className="org.apache.catalina.security.SecurityListener" />
+  -->
+  <!-- APR connector and OpenSSL support using Tomcat Native -->
+  <Listener className="org.apache.catalina.core.AprLifecycleListener" SSLEngine="on" />
+  <!-- OpenSSL support using FFM API from Java 22 -->
+  <!-- <Listener className="org.apache.catalina.core.OpenSSLLifecycleListener" /> -->
+  <!-- Prevent memory leaks due to use of particular java/javax APIs-->
+  <Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener" />
+  <Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" />
+  <Listener className="org.apache.catalina.core.ThreadLocalLeakPreventionListener" />
+
+  <!-- Global JNDI resources
+       Documentation at /docs/jndi-resources-howto.html
+  -->
+  <GlobalNamingResources>
+    <!-- Editable user database that can also be used by
+         UserDatabaseRealm to authenticate users
+    -->
+    <Resource name="UserDatabase" auth="Container"
+              type="org.apache.catalina.UserDatabase"
+              description="User database that can be updated and saved"
+              factory="org.apache.catalina.users.MemoryUserDatabaseFactory"
+              pathname="conf/tomcat-users.xml" />
+  </GlobalNamingResources>
+
+  <!-- A "Service" is a collection of one or more "Connectors" that share
+       a single "Container" Note:  A "Service" is not itself a "Container",
+       so you may not define subcomponents such as "Valves" at this level.
+       Documentation at /docs/config/service.html
+   -->
+  <Service name="Catalina">
+
+    <!--The connectors can use a shared executor, you can define one or more named thread pools-->
+    <!--
+    <Executor name="tomcatThreadPool" namePrefix="catalina-exec-"
+        maxThreads="150" minSpareThreads="4"/>
+    -->
+
+
+    <!-- A "Connector" represents an endpoint by which requests are received
+         and responses are returned. Documentation at :
+         Java HTTP Connector: /docs/config/http.html
+         Java AJP  Connector: /docs/config/ajp.html
+         APR (HTTP/AJP) Connector: /docs/apr.html
+         Define a non-SSL/TLS HTTP/1.1 Connector on port 8080
+    -->
+    <Connector port="8080" protocol="HTTP/1.1"
+               connectionTimeout="20000"
+               redirectPort="8443"
+               maxHttpHeaderSize="32768"
+               maxPostSize="500000"
+               maxParameterCount="4000" />
+    <!-- A "Connector" using the shared thread pool-->
+    <!--
+    <Connector executor="tomcatThreadPool"
+               port="8080" protocol="HTTP/1.1"
+               connectionTimeout="20000"
+               redirectPort="8443"
+               maxParameterCount="1000"
+               />
+    -->
+    <!-- Define an SSL/TLS HTTP/1.1 Connector on port 8443
+         This connector uses the NIO implementation. The default
+         SSLImplementation will depend on the presence of the APR/native
+         library and the useOpenSSL attribute of the AprLifecycleListener.
+         Either JSSE or OpenSSL style configuration may be used regardless of
+         the SSLImplementation selected. JSSE style configuration is used below.
+    -->
+    <!--
+    <Connector port="8443" protocol="org.apache.coyote.http11.Http11NioProtocol"
+               maxThreads="150" SSLEnabled="true"
+               maxParameterCount="1000"
+               >
+        <SSLHostConfig>
+            <Certificate certificateKeystoreFile="conf/localhost-rsa.jks"
+                         certificateKeystorePassword="changeit" type="RSA" />
+        </SSLHostConfig>
+    </Connector>
+    -->
+    <!-- Define an SSL/TLS HTTP/1.1 Connector on port 8443 with HTTP/2
+         This connector uses the APR/native implementation which always uses
+         OpenSSL for TLS.
+         Either JSSE or OpenSSL style configuration may be used. OpenSSL style
+         configuration is used below.
+    -->
+    <!--
+    <Connector port="8443" protocol="org.apache.coyote.http11.Http11AprProtocol"
+               maxThreads="150" SSLEnabled="true"
+               maxParameterCount="1000"
+               >
+        <UpgradeProtocol className="org.apache.coyote.http2.Http2Protocol" />
+        <SSLHostConfig>
+            <Certificate certificateKeyFile="conf/localhost-rsa-key.pem"
+                         certificateFile="conf/localhost-rsa-cert.pem"
+                         certificateChainFile="conf/localhost-rsa-chain.pem"
+                         type="RSA" />
+        </SSLHostConfig>
+    </Connector>
+    -->
+
+    <!-- Define an AJP 1.3 Connector on port 8009 -->
+    <!--
+    <Connector protocol="AJP/1.3"
+               address="::1"
+               port="8009"
+               redirectPort="8443"
+               maxParameterCount="1000"
+               />
+    -->
+
+    <!-- An Engine represents the entry point (within Catalina) that processes
+         every request.  The Engine implementation for Tomcat stand alone
+         analyzes the HTTP headers included with the request, and passes them
+         on to the appropriate Host (virtual host).
+         Documentation at /docs/config/engine.html -->
+
+    <!-- You should set jvmRoute to support load-balancing via AJP ie :
+    <Engine name="Catalina" defaultHost="localhost" jvmRoute="jvm1">
+    -->
+    <Engine name="Catalina" defaultHost="localhost">
+      
+      <!--For clustering, please take a look at documentation at:
+          /docs/cluster-howto.html  (simple how to)
+          /docs/config/cluster.html (reference documentation) -->
+      <!--
+      <Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster"/>
+      -->
+
+      <!-- Use the LockOutRealm to prevent attempts to guess user passwords
+           via a brute-force attack -->
+      <Realm className="org.apache.catalina.realm.LockOutRealm">
+        <!-- This Realm uses the UserDatabase configured in the global JNDI
+             resources under the key "UserDatabase".  Any edits
+             that are performed against this UserDatabase are immediately
+             available for use by the Realm.  -->
+        <Realm className="org.apache.catalina.realm.UserDatabaseRealm"
+               resourceName="UserDatabase"/>
+      </Realm>
+
+      <Host name="localhost" appBase="webapps"
+            unpackWARs="true" autoDeploy="true">
+
+        <Valve className="org.apache.catalina.valves.RemoteIpValve"
+               remoteIpHeader="x-forwarded-for"
+               protocolHeader="x-forwarded-proto"
+               internalProxies="REMOTE_IP_INTERNAL_PROXIES_VALUE" />
+        
+        <!-- SingleSignOn valve, share authentication between web applications
+             Documentation at: /docs/config/valve.html -->
+        <!--
+        <Valve className="org.apache.catalina.authenticator.SingleSignOn" />
+        -->
+
+        <!-- Access log processes all example.
+             Documentation at: /docs/config/valve.html
+             Note: The pattern used is equivalent to using pattern="common" -->
+        <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
+               prefix="localhost_access_log" suffix=".txt"
+               pattern="%h %l %u %t &quot;%r&quot; %s %b"
+               requestAttributesEnabled="true" />
+
+      </Host>
+    </Engine>
+  </Service>
+</Server>
\ No newline at end of file

Relevant Maintainers:

@juanluisrp
Copy link
Copy Markdown
Contributor Author

@tianon we have replaced the unsupported Jetty images by Tomcat 9 ones.

@tianon
Copy link
Copy Markdown
Member

tianon commented Apr 30, 2026

Thanks! Since we're the ones who pushed the Jetty -> Tomcat migration, a couple of things worth confirming before this lands so users aren't caught off guard:

Running as root. The previous images ran as the jetty user; the new images have no USER instruction and the base tomcat image runs as root. That's a concrete breaking change: existing persistent volumes with jetty-owned files will hit permission errors on upgrade, and anyone building FROM geonetwork:4.x expecting a non-root user will be surprised. Is this intentional? Just want to make sure you're aware so you know what to tell users when they run into it.

Jetty -> Tomcat path and env changes. A few things downstream users may have relied on are now gone:

  • $JETTY_HOME / $JETTY_BASE env vars
  • /var/lib/jetty/webapps/geonetwork/ (4.2) -- now /usr/local/tomcat/webapps/geonetwork/
  • CMD ["java", "-jar", "/usr/local/jetty/start.jar"]

Anyone COPY-ing to those paths in a FROM geonetwork:4.x image, or referencing those env vars in scripts, silently breaks. Probably unavoidable given the base swap, but worth confirming you've considered it and plan to document it.


Both Dockerfiles would benefit from set -eux at the top of the non-trivial RUN blocks -- it propagates failures from curl, the md5sum check, and unzip properly instead of relying on && chaining:

-RUN apt-get -y update && \
-    apt-get -y install --no-install-recommends \
-        curl \
-        unzip && \
-    rm -rf /var/lib/apt/lists/* && \
-    mkdir -p ${DATA_DIR} && \
-    mkdir -p /usr/local/tomcat/webapps/geonetwork
+RUN set -eux; \
+    apt-get update; \
+    apt-get install -y --no-install-recommends \
+        curl \
+        unzip \
+    ; \
+    rm -rf /var/lib/apt/lists/*; \
+    mkdir -p "${DATA_DIR}"; \
+    mkdir -p /usr/local/tomcat/webapps/geonetwork

In geonetwork_4.2/docker-entrypoint.sh:

+export CATALINA_OPTS="${JAVA_OPTIONS}"

JAVA_OPTIONS isn't defined -- looks like a leftover from the Jetty entrypoint that translated JAVA_OPTS into what Jetty expected. With Tomcat, catalina.sh reads JAVA_OPTS from the environment directly, so this line can just be removed.


One question about tomcat/server.xml in both variants: the HTTP connector sets maxPostSize="500000" (~488 KiB), which is about a quarter of Tomcat's default (2 MiB). For a GIS application handling KML, GeoJSON, or shapefile uploads, that seems like it could be tight -- is that intentional, and does it cover all the upload paths in GeoNetwork's UI?


FYI: tomcat:9-jre8 and tomcat:9-jre11 carry over the same "no OS version pinned" pattern your Jetty tags were using, so no new concern there -- just noting the pattern continues.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants