diff --git a/components/site/momentumHomePageContent.tsx b/components/site/momentumHomePageContent.tsx
index c6ac82358..5e72eb276 100644
--- a/components/site/momentumHomePageContent.tsx
+++ b/components/site/momentumHomePageContent.tsx
@@ -28,6 +28,7 @@ const content = [
url: '/momentum/4/p-reference',
level: 3,
},
+ { label: 'Running in a Container', url: '/momentum/4/p-container', level: 3 },
],
[
{ label: 'Momentum 3.x Documentation', level: 1 },
diff --git a/content/momentum/4/4-container-building.md b/content/momentum/4/4-container-building.md
new file mode 100644
index 000000000..1c70197cb
--- /dev/null
+++ b/content/momentum/4/4-container-building.md
@@ -0,0 +1,85 @@
+---
+lastUpdated: "07/01/2025"
+title: "Building an Image"
+description: "Instructions for building a Docker container image for Momentum."
+---
+
+## Building the Momentum container
+
+Use a *Dockerfile* to build a Momentum container image.
+
+> **NOTE:** Momentum requires a valid license and working configuration to run. You can either include them into your container image or attach them later to the container at runtime (like in the example below, where they will be found in the mounted `/opt/msys/ecelerity/etc/` tree).
+
+**Example:**
+```dockerfile
+FROM rockylinux:9
+
+# Install dependencies and utilities
+RUN dnf update -y && \
+ dnf install -y bzip2 epel-release iproute iputils net-tools openssl perl procps-ng sudo unbound && \
+ dnf clean all && rm -rf /var/cache/dnf
+
+# Copy and unpack the bundle into the container
+ARG version=5.0.0.xxxxx
+ADD momentum-mta-bundle-${version}.rhel9.x86_64.tar.gz /var/tmp/
+
+# Install as per the Momentum Installation Guide
+RUN cd /var/tmp/momentum-mta-${version} && \
+ ./setrepodir && \
+ dnf install -y --config momentum.repo --enablerepo=momentum msys-role-mta msys-ecelerity-mobility msys-ecelerity-engagement-proxy && \
+ dnf clean all && rm -rf /var/cache/dnf && \
+ rm -rf /var/tmp/momentum-mta-bundle-${version}.rhel9.x86_64.tar.gz momentum-mta-${version}
+
+# Setup initial configuration as per the same Momentum Installation Guide
+RUN sudo -u ecuser mkdir -p /opt/msys/ecelerity/etc/conf/default && \
+ cd /opt/msys/ecelerity/etc/sample-configs/default && \
+ sudo -u ecuser cp ecelerity.conf ecelerity-cluster.conf common.conf /opt/msys/ecelerity/etc/conf/default
+
+# Environment variables for the gimli (heartbeat) monitor
+ENV GIMLI_QUIET=1 \
+ GIMLI_DETACH=0 \
+ GIMLI_PID_FILE=/var/run/ecelerity.monitor.pid \
+ GIMLI_TRACE_DIR=/var/log/ecelerity/traces
+
+# Paths that could be (bind-)mounted
+VOLUME ["/opt/msys/ecelerity/etc/conf/default", "/var/log/ecelerity", "/var/spool/ecelerity"]
+
+# Ports that could be exposed
+EXPOSE 25 2025
+
+# Start the MTA service in the foreground inside the container
+CMD ["/opt/msys/gimli/bin/monitor", "/opt/msys/ecelerity/sbin/run.ecelerity"]
+````
+
+To build the Docker image from the above Dockerfile:
+1. Copy the Momentum MTA bundle to the same directory as the Dockerfile.
+2. Run the following command in that directory:
+```bash
+docker build --tag momentum-mta:$VERSION --build-arg version=$VERSION .
+```
+where `$VERSION` is the version of the Momentum MTA bundle you are using (e.g., `5.0.0.12345`).
+
+## Persistence of data
+
+By default, all files in a container do **NOT** persist when the container exits. On the other hand, Momentum stores state data (e.g. spooled messages) in the filesystem, and a restart of the service would take it back from the saved state. Momentum also generates some files for post-processing, such as logs and traces.
+
+To ensure that these files persist across container restarts, you should use [bind mounts](https://docs.docker.com/engine/storage/bind-mounts/) to persist the following (but not limited to) directories in the container:
+- `/var/spool/ecelerity`: directory that keeps the spool files for emails not yet delivered.
+- `/var/log/ecelerity`: directory that stores the logs and traces generated by Momentum.
+
+Optionally, you can also mount the configuration directory:
+- `/opt/msys/ecelerity/etc/conf/default`: directory that contains the configuration files for Momentum, such as `ecelerity.conf`.
+
+## Exposing listeners
+
+Momentum listens on several ports for different purposes. When running in a container, you can expose these ports to the host system using Docker's port mapping feature. For a more comprehensive explanation of that, see Docker's [documentation](https://docs.docker.com/engine/network/).
+
+### Bridge mode
+
+By default, Docker runs containers in "bridge" mode, which means that the container has its own network namespace and can communicate with the host through a virtual bridge. The host addresses aren't visible inside the container, and you *must* use port mapping to expose the necessary ports for traffic sent to the host to reach Momentum.
+
+To expose the ports, you use the `-p` option when running the container.
+
+### Host mode
+
+Alternatively, you can run the container in "host" mode, which makes the host interfaces transparent to the container, i.e., allows the container to share the host's network stack. In this case, you do not need to map ports, as the container will listen on the same ports as the host.
diff --git a/content/momentum/4/4-container-compose.md b/content/momentum/4/4-container-compose.md
new file mode 100644
index 000000000..694b50d3b
--- /dev/null
+++ b/content/momentum/4/4-container-compose.md
@@ -0,0 +1,79 @@
+---
+lastUpdated: "07/01/2025"
+title: "Using Docker Compose"
+description: "Instructions for using Docker Compose to run the Momentum container."
+---
+
+
+While the `docker run` command is useful for launching single containers manually, **Docker Compose** offers a more structured, maintainable, and scalable way to define and manage containers. This is especially valuable for services like Momentum which may involve multiple volumes, environment variables, port mappings, and resource configurations.
+
+## Benefits of using Docker Compose
+
+- **Centralized configuration (YAML file)**: all settings — environment variables, volumes, port bindings, restart policies, resource limits — are defined in a single `docker-compose.yml` file. This makes configurations clear, reproducible, and version-controlled.
+- **Easier management**: if the container requires several mounts, ports, or links to other services (e.g., metrics, monitoring agents), Docker Compose handles that in one command, without long and error-prone `docker run` lines.
+- **Improved readability and maintainability**: instead of complicated CLI commands, configuration is written in a clean, readable YAML format, simplifying troubleshooting.
+- **Environment-specific overrides**: Docker Compose supports separate override files (e.g., `docker-compose.override.yml` or `.env`) for environment-specific settings (development, staging, production).
+- **Container lifecycle management**: with Docker Compose, you can start, stop, restart, or destroy entire service stacks with simple commands (up, down, restart, etc.).
+- **Restart policies and fault tolerance**: easily define behavior on crash or reboot (`restart: unless-stopped`, `always`, etc.) directly in the `docker-compose.yml` file.
+
+## Running the Momentum container
+
+To create a Momentum container using Docker Compose, put a `docker-compose.yml` file in your project directory.
+
+**Example:**
+```yaml
+services:
+ mta:
+ cap_add:
+ - NET_BIND_SERVICE
+ - SYS_PTRACE
+ command: "/opt/msys/gimli/bin/monitor /opt/msys/ecelerity/sbin/run.ecelerity"
+ container_name: mta
+ cpus: 4
+ environment:
+ - GIMLI_QUIET=1
+ - GIMLI_DETACH=0
+ - GIMLI_PID_FILE=/var/run/ecelerity.monitor.pid
+ - GIMLI_TRACE_DIR=/var/log/ecelerity/traces
+ hostname: mta.test
+ image: momentum-mta:${VERSION}
+ mem_limit: 8g
+ network_mode: host
+ #ports: # Uncomment if mode changes to "bridge"
+ # - "25:25"
+ # - "2025:2025"
+ restart: unless-stopped
+ volumes:
+ - type: bind
+ read_only: true
+ source: /path/to/your/config
+ target: /opt/msys/ecelerity/etc/conf/default
+ - type: bind
+ source: /path/to/your/logs
+ target: /var/log/ecelerity
+ - type: bind
+ source: /path/to/your/spool
+ target: /var/spool/ecelerity
+```
+
+To run the container using Docker Compose with the `docker-compose.yml` contents of the example above, execute the following command in the same directory as the YAML file:
+
+```
+VERSION=5.0.0.xxxxx docker compose up -d
+```
+
+### Setting resource limits
+
+Notice it is possible to set resource limits (CPU and memory) directly in the `docker-compose.yml` file, which is not possible with the `docker run` command. The limits set in the example above are:
+- `cpus: 4`: limits the container to use 4 CPU cores.
+- `mem_limit: 8g`: limits the container to use a maximum of 8 GB of memory.
+
+and they can be checked with the following command:
+```
+docker inspect mta | grep -Eiw 'NanoCpus|Memory'
+```
+which should return something like:
+```
+ "NanoCpus": 4000000000,
+ "Memory": 8589934592,
+```
diff --git a/content/momentum/4/4-container-running.md b/content/momentum/4/4-container-running.md
new file mode 100644
index 000000000..a5b070787
--- /dev/null
+++ b/content/momentum/4/4-container-running.md
@@ -0,0 +1,85 @@
+---
+lastUpdated: "07/01/2025"
+title: "Running and Accessing the Container"
+description: "Instructions for running the Docker container built with Momentum."
+---
+
+
+## Running the Momentum container
+
+For a manual run for test of the Momentum container from the image built as per [here](/momentum/4/4-container-building), you can use the following command:
+
+```bash
+docker run -d --name mta --hostname mta.test \
+ -v /path/to/your/config:/opt/msys/ecelerity/etc/conf/default:ro \
+ -v /path/to/your/logs:/var/log/ecelerity \
+ -v /path/to/your/spool:/var/spool/ecelerity \
+ -p 25:25 -p 2025:2025 \
+ --cap-add=NET_BIND_SERVICE --cap-add=SYS_PTRACE \
+ momentum-mta:$VERSION
+```
+
+where `$VERSION` is the version of Momentum used to build and tag the image (e.g., `5.0.0.12345`).
+
+> **NOTE:** To run Momentum in your production environment, you will likely want to customize mounting of volumes and mapping of ports to suit your deployment needs.
+
+In the command above, notice the following:
+- The `:ro` suffix on the volume mount for `/opt/msys/ecelerity/etc/conf/default` indicates that the configuration is mounted in read-only mode.
+- Since the "bridge" network mode (the default) is being used, the `-p` options map the container's ports to the host's ports.
+- The `--cap-add=NET_BIND_SERVICE` capability allows the container to bind to low-numbered ports (like 25).
+- The `--cap-add=SYS_PTRACE` capability allows the container to use the `ptrace` system call, which is required by **gimli** for monitoring.
+
+You can check the container is running with the following command:
+```
+docker ps
+```
+and see the `mta` container listed with its status as "Up":
+```
+CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
+319be9d4affd momentum-mta:5.0.0.12345 "/opt/msys/gimli/bin…" 4 seconds ago Up 3 seconds 0.0.0.0:25->25/tcp, [::]:25->25/tcp, 0.0.0.0:2025->2025/tcp, [::]:2025->2025/tcp mta
+```
+You can also see in the logs of the container:
+```bash
+docker logs mta
+```
+that Momentum license was validated:
+```
+[Wed 11 Jun 2025 18:27:48] <0x7f5926da1200> Validating software license.
+(...)
+[Wed 11 Jun 2025 18:27:48] <0x7f5926da1200> Valid license.
+```
+
+## Accessing the container
+
+Use the `docker exec` command to access the `mta` container via a terminal session. For example, to inspect the running processes inside the container, you can run:
+```
+docker exec mta ps -efH
+```
+obtaining output similar to:
+```
+UID PID PPID C STIME TTY TIME CMD
+root 239 0 0 18:39 ? 00:00:00 ps -efH
+root 1 0 0 18:27 ? 00:00:00 /opt/msys/ecelerity/sbin/run.ecelerity: monitoring child 7
+ecuser 7 1 0 18:27 ? 00:00:02 /opt/msys/ecelerity/sbin/ecelerity
+```
+
+You can also run a shell inside the container:
+```
+docker exec -it mta /bin/bash
+```
+This will give you a shell prompt inside the container, allowing you to run commands from there, including the `ec_console`:
+```
+me@host:~$ docker exec -it mta /bin/bash
+[root@mta /]# hostname
+mta.test
+[root@mta /]# echo "sysinfo" | sudo -u ecuser /opt/msys/ecelerity/bin/ec_console
+Ecelerity Version: 5.0.0.74264 r(msys-ecelerity:tags/5.0.0-ga^0) (64-bit)
+build date: Feb 20 2025 (RELEASE)
+product name: Ecelerity Momentum
+Rocky Linux release 9.5 (Blue Onyx)
+Linux mta.test 5.14.0-503.22.1.el9_5.x86_64 #1 SMP PREEMPT_DYNAMIC Wed Jan 15 08:02:15 EST 2025 x86_64
+
+[root@mta /]# exit
+exit
+me@host:~$
+```
diff --git a/content/momentum/4/4-container.md b/content/momentum/4/4-container.md
new file mode 100644
index 000000000..b6fc52857
--- /dev/null
+++ b/content/momentum/4/4-container.md
@@ -0,0 +1,36 @@
+---
+lastUpdated: "07/01/2025"
+title: "Running Momentum in a Container"
+description: "Rationale for running Momentum in a containerized environment, and instructions for doing so."
+---
+
+
+Running Momentum in a container is a strategic move toward simplifying deployment, increasing portability, and standardizing runtime environments through development, staging and production. It allows the MTA to operate as a self-contained, version-controlled unit that can be easily replicated and scaled.
+
+Guidance is provided here to run Momentum inside a Linux-based container.
+
+**NOTES:**
+
+- This feature is *experimental*. We are actively seeking feedback to make Momentum more container-friendly.
+- Docker engine and Docker Compose must be installed on the host system where Momentum container will be built and/or run.
+- This document assumes familiarity with Docker and containerization concepts. For more information on it, see Docker's [documentation](https://docs.docker.com/).
+
+## Rationale
+
+Running Momentum in a container provides several benefits:
+- **Portability across environments**: Containers abstract away OS-level differences.
+- **Simplified deployment**: Packaging Momentum and its dependencies makes deployments predictable and repeatable.
+- **Isolation and stability**: Momentum runs in a sandboxed environment, isolated from the host and other services, minimizing the risk of conflicts with host-level libraries or services.
+- **Scalability**: Containers can be easily scaled up or down based on load, allowing for efficient resource utilization.
+- **Easier upgrades**: Versioning container images makes it straightforward to deploy a new version of Momentum in parallel with minimum downtime.
+- **Better resource management**: Containers can be configured with explicit CPU and memory limits, preventing from consuming unexpected system resources.
+- **Fault tolerance and persistence**: By combining containers with persistent volumes, configuration, policies, spooled messages, and logs can be retained across container restarts, ensuring that critical data is not lost.
+- **DevOps and automation friendly**: Containers integrate well with CI/CD pipelines, Docker Compose, and orchestration tools (like Kubernetes and Swarm), enabling fast testing, staging, and deployment cycles.
+
+## Planning for Containerization
+
+Before deploying Momentum in a container, consider the following:
+- **Container image**: When building your own image, select a RHEL-compatible base OS and set the proper environment variables.
+- **Configuration management**: Plan how to manage configuration and other module files, such as `ecelerity.conf`, Lua scripts, etc. You can use bind mounts or Docker volumes to provide such files to the container.
+- **Data persistence**: Likewise, determine how to persist data across container restarts. Use Docker volumes or bind mounts to store spooled messages and logs outside the container. It might be required to handle volume ownership and permissions to ensure Momentum can read/write to these volumes.
+- **Networking**: Decide how to expose ports and configure networking. You can use Docker's port mapping to expose the necessary ports for the different Momentum listeners.
diff --git a/content/momentum/4/p-container.md b/content/momentum/4/p-container.md
new file mode 100644
index 000000000..a50734f8b
--- /dev/null
+++ b/content/momentum/4/p-container.md
@@ -0,0 +1,7 @@
+---
+lastUpdated: "07/01/2025"
+title: "Running in a Container"
+description: "Instructions for running Momentum as a standalone MTA in a containerized environment based on Docker."
+---
+
+Momentum can be run as a standalone MTA in a Docker container.
diff --git a/content/momentum/navigation.yml b/content/momentum/navigation.yml
index dba66c3fb..549c401ea 100644
--- a/content/momentum/navigation.yml
+++ b/content/momentum/navigation.yml
@@ -583,6 +583,18 @@
title: Connection Context Variables
- link: /momentum/4/4-policy-context-mess
title: Message Context Variables
+ - link: /momentum/4/p-container
+ title: Running in a Container
+ items:
+ - link: '/momentum/4/4-container'
+ title: Running Momentum in a Container
+ items:
+ - link: /momentum/4/4-container-building
+ title: Building an Image
+ - link: /momentum/4/4-container-running
+ title: Running and Accessing the Container
+ - link: /momentum/4/4-container-compose
+ title: Using Docker Compose
- link: /momentum/4/p-reference
title: Reference
items: