diff --git a/examples/.gitignore b/examples/.gitignore
index f103b36..9758648 100644
--- a/examples/.gitignore
+++ b/examples/.gitignore
@@ -1,5 +1,6 @@
 conf/*
 data/*
+gem-*/*
 logs/*
 locks/*
 projects/*
diff --git a/examples/docker-compose.build.yml b/examples/docker-compose.build.yml
index 57528e6..da5ba62 100644
--- a/examples/docker-compose.build.yml
+++ b/examples/docker-compose.build.yml
@@ -17,3 +17,20 @@ services:
       - ./logs/:/opt/gemstone/logs/
       - ./projects/:/opt/gemstone/projects/
       - ~/.ssh/:/home/gemstone/.ssh/:ro
+  gem:
+    init: true
+    network_mode: host
+    depends_on:
+      stone:
+        condition: service_started
+    build:
+      context: ../source
+      target: docker-gs64-gem
+      args:
+        GS_VERSION: 3.7.0
+    environment:
+      TZ: America/Argentina/Buenos_Aires
+    volumes:
+      - ./gem-conf/:/opt/gemstone/conf/
+      - ./gem-locks/:/opt/gemstone/locks/
+      - ./gem-logs/:/opt/gemstone/logs/
diff --git a/examples/docker-compose.yml b/examples/docker-compose.yml
index 28d382b..66a2f6f 100644
--- a/examples/docker-compose.yml
+++ b/examples/docker-compose.yml
@@ -13,3 +13,16 @@ services:
       - ./logs/:/opt/gemstone/logs/
       - ./projects/:/opt/gemstone/projects/
       - ~/.ssh/:/home/gemstone/.ssh/:ro
+  gem:
+    init: true
+    network_mode: host
+    depends_on:
+      stone:
+        condition: service_started
+    image: ghcr.io/ba-st/gs64-gem:v3.7.0
+    environment:
+      TZ: America/Argentina/Buenos_Aires
+    volumes:
+      - ./gem-conf/:/opt/gemstone/conf/
+      - ./gem-locks/:/opt/gemstone/locks/
+      - ./gem-logs/:/opt/gemstone/logs/
diff --git a/source/Dockerfile b/source/Dockerfile
index c24c1a7..51bf894 100644
--- a/source/Dockerfile
+++ b/source/Dockerfile
@@ -150,3 +150,86 @@ COPY --chown=${GS_USER}:users StdOutTestReporter.gs ${GEMSTONE_GLOBAL_DIR}/StdOu
 
 COPY --from=download --chown=${GS_USER}:users /tmp/extent0.rowan.dbf ${GEMSTONE_GLOBAL_DIR}/data/extent0.dbf
 CMD ["./entrypoint.sh"]
+
+FROM download as minimal-download
+
+# Remove non-essential files to keep the final image size small
+RUN rm -rf \
+  ${GEMSTONE}/bin/copydbf \
+  ${GEMSTONE}/bin/gemsetup.csh \
+  ${GEMSTONE}/bin/gemstone_data.conf \
+  ${GEMSTONE}/bin/pageaudit \
+  ${GEMSTONE}/bin/printlogs \
+  ${GEMSTONE}/bin/removedbf \
+  ${GEMSTONE}/bin/searchlogs \
+  ${GEMSTONE}/bin/secure_backup_extract \
+  ${GEMSTONE}/bin/slow \
+  ${GEMSTONE}/bin/starthostagent \
+  ${GEMSTONE}/bin/startlogreceiver \
+  ${GEMSTONE}/bin/startlogsender \
+  ${GEMSTONE}/bin/startstone \
+  ${GEMSTONE}/bin/stophostagent \
+  ${GEMSTONE}/bin/stoplogreceiver \
+  ${GEMSTONE}/bin/stoplogsender \
+  ${GEMSTONE}/bin/stopstone \
+  ${GEMSTONE}/bin/superdoit_baseimage_solo \
+  ${GEMSTONE}/bin/superdoit_solo \
+  ${GEMSTONE}/bin/superdoit_stone \
+  ${GEMSTONE}/bin/updatesecuredbf \
+  ${GEMSTONE}/bin/upgradeimage \
+  ${GEMSTONE}/bin/verify_backup_with_openssl \
+  ${GEMSTONE}/bin/waitstone \
+  ${GEMSTONE}/bin/x509 \
+  ${GEMSTONE}/data \
+  ${GEMSTONE}/doc/man1/copydbf* \
+  ${GEMSTONE}/doc/man1/pageaudit* \
+  ${GEMSTONE}/doc/man1/printlogs* \
+  ${GEMSTONE}/doc/man1/removedbf* \
+  ${GEMSTONE}/doc/man1/searchlogs* \
+  ${GEMSTONE}/doc/man1/secure_backup_extract* \
+  ${GEMSTONE}/doc/man1/starthostagent* \
+  ${GEMSTONE}/doc/man1/startlogreceiver* \
+  ${GEMSTONE}/doc/man1/startlogsender* \
+  ${GEMSTONE}/doc/man1/startstone* \
+  ${GEMSTONE}/doc/man1/stophostagent* \
+  ${GEMSTONE}/doc/man1/stoplogreceiver* \
+  ${GEMSTONE}/doc/man1/stoplogsender* \
+  ${GEMSTONE}/doc/man1/stopstone* \
+  ${GEMSTONE}/doc/man1/updatesecuredbf* \
+  ${GEMSTONE}/doc/man1/waitstone* \
+  ${GEMSTONE}/doc/man8/stoned* \
+  ${GEMSTONE}/sys/hostagenttopaz.ini \
+  ${GEMSTONE}/sys/midhostagenttopaz.ini \
+  ${GEMSTONE}/sys/runpageauditgem \
+  ${GEMSTONE}/sys/stoned \
+  ${GEMSTONE}/sys/topazSolo.ini \
+  ${GEMSTONE_GLOBAL_DIR}/start-gemstone.sh \
+  ${GEMSTONE_GLOBAL_DIR}/entrypoint.sh \
+  ;
+
+## Prepare gem image
+FROM base as docker-gs64-gem
+LABEL maintainer="Buenos Aires Smalltalk <github@fast.org.ar>"
+
+ENV GEMSTONE_GLOBAL_DIR=/opt/gemstone
+ENV GEMSTONE=${GEMSTONE_GLOBAL_DIR}/product
+ENV GEMSTONE_EXE_CONF=${GEMSTONE_GLOBAL_DIR}/conf
+ENV GEMSTONE_LOG_DIR=${GEMSTONE_GLOBAL_DIR}/logs
+
+ENV PATH=$GEMSTONE/bin:$PATH
+# Used to determine what shell to use for an exec, such as by System class>>performOnServer:.
+ENV SHELL=/usr/bin/bash
+
+ENV NETLDI_SERVICE_NAME=gs64ldi
+ENV NETLDI_PORT=50386
+
+# Copy startup scripts
+COPY start-gem.sh ${GEMSTONE_GLOBAL_DIR}/start-gem.sh
+COPY gem.sh ${GEMSTONE_GLOBAL_DIR}/gem.sh
+
+COPY --from=minimal-download --chown=${GS_USER}:users ${GEMSTONE_GLOBAL_DIR} ${GEMSTONE_GLOBAL_DIR}
+RUN ln -s ${GEMSTONE}/bin/gemsetup.sh /etc/profile.d/gemstone.sh
+
+
+WORKDIR ${GEMSTONE_GLOBAL_DIR}
+CMD ["./gem.sh"]
diff --git a/source/gem.sh b/source/gem.sh
new file mode 100755
index 0000000..6ca86e9
--- /dev/null
+++ b/source/gem.sh
@@ -0,0 +1,21 @@
+#!/usr/bin/env bash
+
+set -eu
+
+echo "${NETLDI_SERVICE_NAME} ${NETLDI_PORT}/tcp # GemStone - Netldi" >> /etc/services
+
+# Ensure write permissions
+NEED_WRITE_PERMISSION=(
+  "${GEMSTONE_GLOBAL_DIR}/locks/"
+  "${GEMSTONE_LOG_DIR}/"
+)
+
+for path in "${NEED_WRITE_PERMISSION[@]}"; do
+  if ! gosu "${GS_USER}" test -w "$path"; then
+    chown "${GS_UID}:${GS_GID}" "$path"
+    chmod ug+w "$path"
+  fi
+done
+
+# Run gemstone as GS_USER
+exec gosu "${GS_USER}" "${GEMSTONE_GLOBAL_DIR}/start-gem.sh"
diff --git a/source/start-gem.sh b/source/start-gem.sh
new file mode 100755
index 0000000..5ec8082
--- /dev/null
+++ b/source/start-gem.sh
@@ -0,0 +1,36 @@
+#!/usr/bin/env bash
+# based on https://medium.com/@gchudnov/trapping-signals-in-docker-containers-7a57fdda7d86
+# see also https://docs.docker.com/engine/reference/builder/#exec-form-entrypoint-example
+set -eu
+
+# SIGTERM-handler
+sigterm_handler() {
+  echo 'Got SIGTERM, stopping GemStone/S 64 gem'
+  stopnetldi
+  exit 143; # 128 + 15 -- SIGTERM
+}
+
+# setup handlers
+# on callback, kill the last background process,
+# which is `tail -f /dev/null` and execute the specified handler
+trap 'kill ${!}; sigterm_handler' SIGTERM
+
+# start GemStone services
+# shellcheck disable=SC2086
+startnetldi \
+  -g \
+  -a "${GS_USER}" \
+  -n \
+  -P "${NETLDI_PORT}" \
+  -l "${GEMSTONE_LOG_DIR}/${NETLDI_SERVICE_NAME}.log" \
+  ${NETLDI_ARGS:-} \
+  "${NETLDI_SERVICE_NAME}"
+
+# list GemStone services
+gslist -cvl
+
+# wait forever, (loop to handle multiple signals if needed)
+while true
+do
+  tail -f /dev/null & wait ${!}
+done