diff --git a/docker/etherpad/Dockerfile b/docker/etherpad/Dockerfile
index c48817553a..308e5db710 100644
--- a/docker/etherpad/Dockerfile
+++ b/docker/etherpad/Dockerfile
@@ -23,6 +23,7 @@
 # https://github.com/ether/etherpad-lite
 #
 # Author: muxator
+ARG BUILD_ENV=git
 
 # We set defaults here so that we can make use of them in different
 # stages of the multi stage build.
@@ -30,6 +31,8 @@ ARG EP_DIR=/opt/etherpad-lite
 ARG SETTINGS=./settings.json.docker
 ARG ETHERPAD_PLUGINS="ep_headings2"
 
+# Upstream is using nodejs 23 now which is not an LTS.
+# We stick to the latest LTS which is 22.
 FROM node:22-bookworm-slim AS adminBuild
 ARG EP_DIR
 WORKDIR "${EP_DIR}"
@@ -40,9 +43,9 @@ RUN export DEBIAN_FRONTEND=noninteractive; \
     apt-get -qq --no-install-recommends install ca-certificates git && \
     apt-get -qq clean && \
     rm -rf /var/lib/apt/lists/*
-RUN npm install -g pnpm@9.0.4
+RUN npm install -g pnpm@latest
 RUN git clone https://github.com/ether/etherpad-lite ${EP_DIR}
-RUN git checkout v2.2.7
+RUN git checkout v2.3.0
 RUN pnpm install
 RUN pnpm run build:ui
 
@@ -132,7 +135,7 @@ RUN mkdir -p "${EP_DIR}" && chown etherpad:etherpad "${EP_DIR}"
 # https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=863199
 RUN export DEBIAN_FRONTEND=noninteractive; \
     mkdir -p /usr/share/man/man1 && \
-    npm install pnpm@9.0.4 -g  && \
+    npm install pnpm@latest -g  && \
     apt-get -qq update && \
     apt-get -qq dist-upgrade && \
     apt-get -qq --no-install-recommends install \
@@ -140,7 +143,7 @@ RUN export DEBIAN_FRONTEND=noninteractive; \
         curl \
         git \
         ${INSTALL_ABIWORD:+abiword} \
-        ${INSTALL_SOFFICE:+libreoffice} \
+        ${INSTALL_SOFFICE:+libreoffice openjdk-11-jre} \
         && \
     apt-get -qq clean && \
     rm -rf /var/lib/apt/lists/*
@@ -149,26 +152,48 @@ USER etherpad
 
 RUN git clone https://github.com/ether/etherpad-lite ${EP_DIR}
 WORKDIR "${EP_DIR}"
-RUN git checkout v2.2.7
+RUN git checkout v2.3.0
+
+# Upstream differentiates between a build copy and a build git source
+# for building etherpad. We only do build_git.
+FROM build AS build_git
+
+FROM build AS build_copy
+
+
+
+
+FROM build_${BUILD_ENV} AS development
 
-FROM build AS development
 ARG ETHERPAD_PLUGINS
+ARG ETHERPAD_LOCAL_PLUGINS=
+ARG ETHERPAD_LOCAL_PLUGINS_ENV=
+ARG ETHERPAD_GITHUB_PLUGINS=
 
 # This copy is not necessary as we clone and checkout in the build image
 # COPY --chown=etherpad:etherpad ./src/ ./src/
 COPY --chown=etherpad:etherpad --from=adminbuild /opt/etherpad-lite/src/ templates/admin./src/templates/admin
 COPY --chown=etherpad:etherpad --from=adminbuild /opt/etherpad-lite/src/static/oidc ./src/static/oidc
 
+# This copy is not necessary we don't have any local plugins
+# COPY --chown=etherpad:etherpad ./local_plugin[s] ./local_plugins/
+
+RUN bash -c ./bin/installLocalPlugins.sh
+
 RUN bin/installDeps.sh && \
-    if [ ! -z "${ETHERPAD_PLUGINS}" ] || [ ! -z "${ETHERPAD_LOCAL_PLUGINS}" ] || [ ! -z "${ETHERPAD_GITHUB_PLUGINS}" ]; then \
-        pnpm run plugins i ${ETHERPAD_PLUGINS} ${ETHERPAD_LOCAL_PLUGINS:+--path ${ETHERPAD_LOCAL_PLUGINS}} ${ETHERPAD_GITHUB_PLUGINS:+--github ${ETHERPAD_GITHUB_PLUGINS}}; \
-    fi
+  if [ ! -z "${ETHERPAD_PLUGINS}" ] || [ ! -z "${ETHERPAD_GITHUB_PLUGINS}" ]; then \
+      pnpm run plugins i ${ETHERPAD_PLUGINS} ${ETHERPAD_GITHUB_PLUGINS:+--github ${ETHERPAD_GITHUB_PLUGINS}}; \
+  fi
 
 
-FROM build AS production
+FROM build_${BUILD_ENV} AS production
+
 ARG EP_DIR
 ARG SETTINGS
 ARG ETHERPAD_PLUGINS
+ARG ETHERPAD_LOCAL_PLUGINS=
+ARG ETHERPAD_LOCAL_PLUGINS_ENV=
+ARG ETHERPAD_GITHUB_PLUGINS=
 
 ENV NODE_ENV=production
 ENV ETHERPAD_PRODUCTION=true
@@ -178,10 +203,15 @@ ENV ETHERPAD_PRODUCTION=true
 COPY --chown=etherpad:etherpad --from=adminbuild /opt/etherpad-lite/src/templates/admin ./src/templates/admin
 COPY --chown=etherpad:etherpad --from=adminbuild /opt/etherpad-lite/src/static/oidc ./src/static/oidc
 
-RUN bin/installDeps.sh && rm -rf ~/.npm && rm -rf ~/.local && rm -rf ~/.cache && \
-    if [ ! -z "${ETHERPAD_PLUGINS}" ] || [ ! -z "${ETHERPAD_LOCAL_PLUGINS}" ] || [ ! -z "${ETHERPAD_GITHUB_PLUGINS}" ]; then \
-      pnpm run plugins i ${ETHERPAD_PLUGINS} ${ETHERPAD_LOCAL_PLUGINS:+--path ${ETHERPAD_LOCAL_PLUGINS}} ${ETHERPAD_GITHUB_PLUGINS:+--github ${ETHERPAD_GITHUB_PLUGINS}}; \
-    fi
+# This copy is not necessary we don't have any local plugins
+# COPY --chown=etherpad:etherpad ./local_plugin[s] ./local_plugins/
+
+RUN bash -c ./bin/installLocalPlugins.sh
+
+RUN bin/installDeps.sh && \
+  if [ ! -z "${ETHERPAD_PLUGINS}" ] || [ ! -z "${ETHERPAD_GITHUB_PLUGINS}" ]; then \
+      pnpm run plugins i ${ETHERPAD_PLUGINS} ${ETHERPAD_GITHUB_PLUGINS:+--github ${ETHERPAD_GITHUB_PLUGINS}}; \
+  fi
 
 # Copy the configuration file.
 COPY --chown=etherpad:etherpad ${SETTINGS} "${EP_DIR}"/settings.json
diff --git a/playbooks/test-etherpad.yaml b/playbooks/test-etherpad.yaml
new file mode 100644
index 0000000000..b104461f20
--- /dev/null
+++ b/playbooks/test-etherpad.yaml
@@ -0,0 +1,5 @@
+- hosts: "etherpad"
+  tasks:
+    - name: Run selenium container
+      include_role:
+        name: run-selenium
diff --git a/testinfra/test_etherpad.py b/testinfra/test_etherpad.py
index 3feb0b7d94..61820bd674 100644
--- a/testinfra/test_etherpad.py
+++ b/testinfra/test_etherpad.py
@@ -15,6 +15,8 @@
 import json
 import urllib.parse
 
+from util import take_screenshots
+
 testinfra_hosts = ['etherpad99.opendev.org']
 
 
@@ -156,3 +158,28 @@ def test_etherpad_restore_pad(host):
     assert '"message":"ok"' in cmd.stdout
     assert firststr in cmd.stdout
     assert secondstr not in cmd.stdout
+
+def test_etherpad_screenshots(host):
+    # Prepare our test pad for screenshotting
+    teststr = '🖖 Live long and prosper 🖖'
+    urlstr = urllib.parse.quote(teststr)
+
+    token = _get_bearer_token(host)
+
+    cmd = host.run('curl -H "Authorization: Bearer %s" '
+                   '"http://localhost:9001/api/1/createPad?'
+                   'padID=screenshot"' % token)
+    assert '"code":0' in cmd.stdout
+    assert '"message":"ok"' in cmd.stdout
+    cmd = host.run('curl -H "Authorization: Bearer %s" '
+                   '"http://localhost:9001/api/1/setText?'
+                   'padID=screenshot&text=%s"' % (token, urlstr))
+    assert '"code":0' in cmd.stdout
+    assert '"message":"ok"' in cmd.stdout
+    shots = (
+        ('http://localhost:9001', None, 'etherpad-main.png'),
+        ('http://localhost:9001/p/screenshot', None,
+         'etherpad-pad.png'),
+    )
+
+    take_screenshots(host, shots)
diff --git a/zuul.d/system-config-run.yaml b/zuul.d/system-config-run.yaml
index 97b78ccd3e..d36df475cc 100644
--- a/zuul.d/system-config-run.yaml
+++ b/zuul.d/system-config-run.yaml
@@ -636,6 +636,7 @@
       run_playbooks:
         - playbooks/letsencrypt.yaml
         - playbooks/service-etherpad.yaml
+      run_test_playbook: playbooks/test-etherpad.yaml
     files:
       - playbooks/bootstrap-bridge.yaml
       - playbooks/letsencrypt.yaml