This article shows you how to create a basic Docker image for Magnolia using a local database. It’s intended for developers who want a lightweight Docker-based Magnolia instance for experimentation or testing deployments to the cloud or other infrastructure environments.

It is not a production-grade configuration, but it can serve as a solid starting point for further extensions.

As a bonus, you’ll also get a ZSH shell script that optionally builds an image for a cloud environment. In this example, we use Azure Container Registry (ACR).

Note: if you’re on macOS with an Apple Silicon chip (M1/M2), you cannot directly deploy locally built images to Azure because of architecture incompatibility.

πŸ’‘ All the files used in this article are available on GitHub.


Project Structure

Assuming a typical Maven multi-module layout:

your-project-root/
β”œβ”€β”€ pom.xml                          # Root POM (multi-module project)
β”œβ”€β”€ .dockerignore                    # Docker ignore rules
β”œβ”€β”€ build.zsh                        # ZSH build script
β”œβ”€β”€ your-project-webapp/             # Webapp module (WAR project)
β”‚   β”œβ”€β”€ pom.xml                      # Module POM
β”‚   β”œβ”€β”€ Dockerfile                   # Dockerfile for building the container
β”‚   β”œβ”€β”€ build-support/
β”‚   β”‚   └── setenv.sh                # Tomcat/Magnolia startup configuration
β”‚   β”œβ”€β”€ src/
β”‚   └── target/
β”‚       └── magnolia-webapp.war     # Built WAR (after Maven build),
                                    # matches finalName in root pom.xml
  1. Set the finalName in the root pom.xml

  2. In the section of your root or module pom.xml, set:

 <build>
    <finalName>magnolia-webapp</finalName>
    <plugins>
    ...
    </plugins>
</build>

This ensures that your WAR file always has a predictable name, regardless of version changes. Adjust this if needed, but keep the name consistent in scripts and the Dockerfile.

  1. Create a build-support directory

Inside your your-project-webapp module, create a folder called build-support/ for additional files that should be copied into the Docker image. Here you place setenv.sh, which customizes the Tomcat configuration.

  1. Add the Dockerfile

Also within your-project-webapp/, create the following Dockerfile:

FROM tomcat:9.0-jdk17

# Preparation
RUN apt-get update && \
    mkdir -p /opt/magnolia && \
    chmod 775 /opt/magnolia

COPY your-project-webapp/build-support/setenv.sh $CATALINA_HOME/bin/

# Copy WAR from local path
COPY your-project-webapp/target/magnolia-webapp.war $CATALINA_HOME/webapps/ROOT.war

# Environment Settings
ENV JVM_XMS=1g
ENV JVM_XMX=4g
ENV MGNL_REPOSITORIES_HOME=/opt/magnolia/repositories
ENV MGNL_RESOURCES_DIR=/opt/magnolia/resources
ENV MGNL_BOOTSTRAP_DIR=/opt/magnolia/bootstrap/common
ENV MGNL_REPOSITORIES_JACKRABBIT_CONFIG=WEB-INF/config/repo-conf/jackrabbit-bundle-h2-search.xml
ENV MGNL_DB=h2
ENV MGNL_BOOTSTRAP_AUTHOR_INSTANCE=false
ENV MGNL_UPDATE_AUTO=true
ENV MGNL_DEVELOP=true
ENV MGNL_PERISCOPE_RESULT_RANKING=false
ENV MGNL_UI_STICKER_ENVIRONMENT=PUBLIC
ENV MGNL_UI_STICKER_COLOR=#9A3332
ENV MGNL_UI_STICKER_COLOR_BACKGROUND=#FFFFFF
ENV MGNL_WEBAPP="Public"
ENV MGNL_INJECT_CONFIG=NA

CMD ["/usr/local/tomcat/bin/catalina.sh", "run"]

Make sure the path to the WAR and the setenv.sh file matches your project structure.

  1. Compile the Magnolia project

This is a prerequisite for building the Docker image. From the project root, run:

mvn clean package

This must succeed and produce the file:

your-project-webapp/target/magnolia-webapp.war

The Build Script

The build.zsh script is run from your project root. It builds the WAR, ensures Docker is available, and then builds a Docker image. Optionally, it can create a cross-platform image for ACR.

#!/bin/zsh

set -e  # Stop on errors

# === Docker Desktop Check & Auto-Start ===
echo "πŸ§ͺ Checking Docker Desktop..."

if ! command -v docker &>/dev/null; then
  echo "❌ Docker CLI not found. Is Docker Desktop installed?"
  exit 1
fi

if ! docker info &>/dev/null; then
  echo "πŸš€ Docker is not running. Starting Docker Desktop..."
  open -a Docker

  # Wait for Docker to become available
  echo -n "⏳ Waiting for Docker to start"
  while ! docker info &>/dev/null; do
    echo -n "."
    sleep 1
  done
  echo ""
  echo "βœ… Docker is now running"
else
  echo "βœ… Docker is running"
fi

# === Configuration ===
MODULE_NAME="your-project-webapp"
FINAL_NAME="magnolia-webapp"
WAR_FILE="$MODULE_NAME/target/$FINAL_NAME.war"
DOCKERFILE="$MODULE_NAME/Dockerfile"
LOCAL_IMAGE_NAME="magnolia-webapp"
ACR_IMAGE_NAME="yourname.azurecr.io/magnolia-webapp:latest"

# === Determine mode (default: local build) ===
if [[ "$1" == "acr" ]]; then
  echo "☁️  Azure ACR-compatible build (linux/amd64)"
  IMAGE_NAME=$ACR_IMAGE_NAME
  BUILD_COMMAND="docker buildx build \
    --platform linux/amd64 \
    -f $DOCKERFILE \
    -t $IMAGE_NAME \
    --load \
    ."
else
  echo "πŸ› οΈ  Local build"
  IMAGE_NAME=$LOCAL_IMAGE_NAME
  BUILD_COMMAND="docker build \
    -f $DOCKERFILE \
    -t $IMAGE_NAME \
    ."
fi

# === Build WAR ===
echo "πŸ”¨ Building WAR..."
mvn clean package -DskipTests -pl $MODULE_NAME

if [[ ! -f "$WAR_FILE" ]]; then
  echo "❌ Could not find WAR file: $WAR_FILE"
  exit 1
fi

# === Build Docker Image ===
echo "🐳 Building Docker image: $IMAGE_NAME"
eval $BUILD_COMMAND

echo "βœ… Build complete: $IMAGE_NAME"

Update yourname.azurecr.io and other names as needed to reflect your project.


Run the Build Script

Make the script executable:

chmod +x *.zsh

Then run:

./build.zsh         # local image
./build.zsh acr     # ACR-compatible image

Troubleshooting

If something fails, share the exact error with a Mechanical Turk of your choice (ChatGPT, Claude, etc.), and improve the script accordingly.


πŸ’‘ All the files used in this article are available on GitHub.