MockServer is available as a docker container that allows you to easily run MockServer as a separate container on any environment without having to install Java or any other libraries. The docker container fully encapsulates all requirements required to run MockServer (such as Java) and separates the running MockServer instance from all other parts of the system.

MockServer docker container can be found at MockServer Docker. The same images, with the same digests, are also on the GitHub Container Registry as ghcr.io/mock-server/mockserver and on AWS ECR Public as public.ecr.aws/t2x9c0i6/mockserver, which avoid Docker Hub's pull limit (see Pull MockServer Image).

Running MockServer Docker Container

The typical sequence for running the MockServer docker image is as follows:
  1. Install Docker
  2. Pull (or Update) Image
  3. Run Container
In addition it is possible to customise how the container is run.  

Install Docker

To install Docker see the installation instructions.

 

Pull MockServer Image

To pull the MockServer Docker image use the pull command, as follows:

docker pull mockserver/mockserver

This is not strictly necessary as the image will be automatically pulled if it does not exist when the run command is used. However, using the pull command will ensure the latest version of the image is downloaded.

Docker Hub limits how many images anonymous users can pull, which often hits CI builds that share an IP address. The same images are also published to two other registries, and pulls from them do not count against the Docker Hub limit:

  • GitHub Container Registry (GHCR), a good choice for CI and especially for GitHub Actions:
    docker pull ghcr.io/mock-server/mockserver:9.2.0
  • AWS ECR Public, which gives lower latency for AWS-based CI/CD:
    docker pull public.ecr.aws/t2x9c0i6/mockserver:9.2.0

GHCR and ECR Public carry the same tags as Docker Hub (for example latest, 9.2.0, mockserver-9.2.0, 9.2.0-graaljs and clustered-9.2.0) and each tag has the same image digest on every registry, so switching registry changes nothing but where the image comes from. The Kubernetes admission webhook image is at ghcr.io/mock-server/mockserver-webhook and public.ecr.aws/t2x9c0i6/mockserver-webhook. On GHCR:

  • releases from 7.1.0 onwards are available; earlier versions are not
  • the experimental -aot tags and the snapshot tags are not published to GHCR; pull them from Docker Hub or ECR Public
 

Verifying Image Signatures

Release images are signed with Sigstore cosign using the MockServer public key, published at https://www.mock-server.com/mockserver-cosign.pub (the same key signs the Helm chart). To verify an image before running it:

cosign verify --key https://www.mock-server.com/mockserver-cosign.pub mockserver/mockserver:9.2.0

A successful verification prints the signed payload and exits with status 0. The same key verifies the -graaljs, -http3 and clustered- image variants and the GHCR and ECR Public copies, for example cosign verify --key https://www.mock-server.com/mockserver-cosign.pub ghcr.io/mock-server/mockserver:9.2.0. Image versions before 9.2.0 predate signing.

 

Run MockServer Container

Then to run MockServer as a Docker container run the following command:

docker run -d --rm -P mockserver/mockserver

The -P switch in this command tells Docker to map all ports exported by the MockServer container to dynamically allocated ports on the host machine.

To view information about the MockServer container, including which dynamic ports have been used run the following command:

docker ps

No Interactive Shell

MockServer uses distroless as its based container for both size and security and so does not contain an interactive shell. This minimises the likelihood of vulnerabilities and to reduces the attack surface by ensuring only the JVM and MockServer code is inside the container.

   

Configure Port Mapping

This MockServer docker container exports the following port:

  • serverPort 1080

To specify which ports (on the host machine) should be mapped to the MockServer docker container use the -p <host port>:<container port> option, as follows:

docker run -d --rm -p <serverPort>:1080 mockserver/mockserver

For example:

docker run -d --rm -p 1080:1080 mockserver/mockserver
 

HTTP/3 (experimental)

The standard image serves HTTP/3: set MOCKSERVER_HTTP3_PORT and publish that port as UDP:

docker run -d --rm -p 1080:1080 -p 8443:8443/udp -e MOCKSERVER_HTTP3_PORT=8443 mockserver/mockserver:9.2.0

This also works with a read-only root filesystem (--read-only). The -graaljs, clustered- and -aot images also serve HTTP/3, but only if the container can write to /tmp. If MockServer cannot start HTTP/3 on that port — for example with --network host when another process already holds the UDP port — it exits with a non-zero status, printing one line that names the port and the cause, rather than running without HTTP/3.

Deprecated: the -http3 tags (9.2.0-http3, latest-http3, snapshot-http3) used to be the only images that could serve HTTP/3. They are now the same as the standard image and are kept for one more release only, so switch to the standard tag.

 

Environment Variables

It is possible configure MockServer behaviour through environment variables, this includes port mappings, log level and lots of other properties for example:

docker run -d --rm -p 1090:1090 --env MOCKSERVER_LOG_LEVEL=TRACE --env MOCKSERVER_SERVER_PORT=1090 mockserver/mockserver
 

JVM Heap Size

The Docker image caps the JVM heap at 45% of the container's memory limit (it sets -XX:MaxRAMPercentage=45.0). Always run the container with an explicit memory limit — without one the JVM sizes its heap off the host's total memory and can be OOM-killed under load. 512 MiB (--memory=512m) is the smallest supported limit (768 MiB for the -clustered image when clustering is switched on — see clustering); use --memory=1g or more for larger bodies or many expectations, and --memory=2g for sustained production load. The rest of the limit is not spare: the Java process needs memory the heap setting does not count — class metadata and compiled code, thread stacks, garbage-collector bookkeeping, the off-heap network buffers Netty uses for bodies, and the kernel's per-connection socket buffers — and most of it does not shrink when the heap does, so it is a bigger share of a small container. To set an explicit heap (for high-throughput use cases or large response bodies), pass -Xmx via JAVA_TOOL_OPTIONS, which disables the percentage cap — keep the heap you pin at or under 45% of the limit on a small container. If a container is killed with exit code 137 and OOMKilled: true (no Java stack trace — the kernel killed it), the fix is a larger --memory or a smaller heap, not a bigger one. See the memory tuning guide for the sizing arithmetic:

docker run -d --rm -p 1080:1080 --memory=1g --env JAVA_TOOL_OPTIONS="-XX:+UseZGC -Xmx512m" mockserver/mockserver

The images use the Z garbage collector (ZGC) by default (the -aot fast-start image is the exception and stays on the default collector). ZGC collects concurrently with request handling, which markedly lowers response tail latency (p95/p99) under load at the same throughput — you get this without configuring anything. It uses a little more memory than the previous default — under load it grows to its full heap and keeps it while the load lasts, in memory the kernel cannot reclaim — which the images' heap cap allows for, so it runs under sustained load within a --memory=512m limit. The collector is set through the JAVA_TOOL_OPTIONS environment variable, so if you set JAVA_TOOL_OPTIONS yourself it replaces the default — include -XX:+UseZGC when you set it for another reason (for example JAVA_TOOL_OPTIONS="-XX:+UseZGC -Xmx512m"), or you will silently fall back to the JDK's default collector. To switch back to the G1 collector, set JAVA_TOOL_OPTIONS=-XX:+UseG1GC:

docker run -d --rm -p 1080:1080 --memory=1g --env JAVA_TOOL_OPTIONS="-XX:+UseG1GC" mockserver/mockserver

How much memory does MockServer actually use? A freshly started, idle MockServer settles at roughly 120 MB of container memory, and this barely changes between --memory=512m and --memory=1g. Under load it grows well beyond that: at --memory=512m on one CPU core, serving a small mocked response at 16,000 requests a second over about 4,500 open connections, the container peaked at about 79–83% of the limit (a 232 MB heap plus about 150 MB of other JVM memory and about 20 MB of kernel socket buffers). So 512 MB suits small request and response bodies (up to a few kilobytes) with a modest number of expectations; at the default INFO log level it is not enough once individual bodies reach roughly 16 KB (measured with a single expectation — a best case) — see the memory tuning guide for body-size guidance and the levers available. --memory=256m is not supported with the default settings: it starts and idles (around 95 MB), but under load the container is killed. If you must run in 256 MB, set a small explicit heap (for example JAVA_TOOL_OPTIONS="-XX:+UseZGC -Xmx96m") and keep traffic and body sizes light — even then the container runs close to its limit (about 95% at 8,000 requests a second in our tests). Memory in use grows with your expectations, request log, response sizes and number of open connections, and rises on hosts with more CPU cores (MockServer sizes its network thread pools to the available cores).

If MockServer becomes slow or unresponsive under sustained load, see the troubleshooting guide for recommended memory and logging configuration.

 

Modifying Default Command

The MockServer container entrypoint calls org.mockserver.cli.Main directly with CMD [] (no default arguments). The SERVER_PORT environment variable defaults to 1080 in the Dockerfile. Command line options can be explicitly provided, for example:

docker run --rm --name mockserver -p 1080:1090 mockserver/mockserver -logLevel INFO -serverPort 1090 -proxyRemotePort 443 -proxyRemoteHost mock-server.com

The application code is split across two jars in the image, /mockserver.jar (MockServer's own classes) and /mockserver-deps.jar (its dependencies), instead of the single mockserver-netty-jar-with-dependencies.jar used before 9.0.0. /mockserver.jar's manifest carries a Class-Path: mockserver-deps.jar entry, so java -jar /mockserver.jar still runs correctly on its own — it just starts more slowly, because it bypasses the image's AppCDS shared archive (-XX:SharedArchiveFile=/mockserver.jsa, built against the full -cp /mockserver.jar:/mockserver-deps.jar:/libs/*:/extensions/* below). java -jar /mockserver-deps.jar does not run; it has no Main-Class.

If you override the container's entrypoint rather than only its command — for example a Dockerfile ENTRYPOINT, a Compose entrypoint: list, or a Kubernetes command: list — base your override on the exact ENTRYPOINT the image you run already has, rather than retyping one by hand: the Java binary's path, and whether -XX:SharedArchiveFile/-XX:AOTCache is present, differ between the standard, -clustered, -graaljs and -aot images, and a hand-written override that drops -Dmockserver.propertyFile=/config/mockserver.properties silently stops /config properties (see "Detailed MockServer Configuration" below) from loading. Check the real entrypoint first:

docker inspect --format '{{json .Config.Entrypoint}}' mockserver/mockserver:9.2.0

For the standard image, that is the following exec-form array — the same JSON-array shape a Dockerfile ENTRYPOINT, a Compose entrypoint:, or a Kubernetes command: list each expect, one argument per element (quoting /libs/* and /extensions/* inside the single -cp element, as shown, avoids the shell expanding them before Java sees them):

[
  "/usr/lib/jvm/temurin25-trimmed/bin/java",
  "-Dfile.encoding=UTF-8",
  "--enable-native-access=ALL-UNNAMED",
  "-XX:MaxRAMPercentage=45.0",
  "-XX:SharedArchiveFile=/mockserver.jsa",
  "-cp", "/mockserver.jar:/mockserver-deps.jar:/libs/*:/extensions/*",
  "-Dmockserver.propertyFile=/config/mockserver.properties",
  "org.mockserver.cli.Main"
]

Copy it verbatim and change only what you need to — for example appending -serverPort 1080 as an extra element, or (more simply) leaving the entrypoint untouched and passing -serverPort 1080 as the CMD/command instead, which needs no entrypoint override at all.

 

Adding Extensions

Every MockServer image loads any JAR in /extensions, so you can add your own extensions without building a new image. Mount the folder read-only and name the extension classes:

docker run -v $(pwd)/ext:/extensions:ro -e MOCKSERVER_EXTENSIONS=com.example.AuditExtension -p 1080:1080 mockserver/mockserver

When nothing is mounted at /extensions, the image starts exactly as before.

Detailed MockServer Configuration

To support configuring MockServer a mockserver.properties will be loaded from /config directory if it exists.

A mockserver.properties configuration file and other related configuration files such as json expectation initialization, or custom TLS CA, X.509 Certificate or Private Key should be mapping into the /config directory.

For example to add configuration files in the current directory, such as mockserver.properties, map $(pwd) into /config, as follows:
docker run -v $(pwd):/config -p 1080:1080  mockserver/mockserver -serverPort 1080

See MockServer Configuration for details of all configuration options.

As the Docker image is based from gcr.io/distroless/java-base-debian12:nonroot and the user nonroot is used, we need to configure permissions in order to allow the user in the container read/write files in mounted volumes:
chmod o+r $(pwd)/mockserver.properties
 

Extending MockServer Classpath

To use class callbacks or an expectation initializer class the classpath for MockServer must include the specified classes.

To support adding classes to the classpath any jar files contained in the /libs directory will be added into MockServer classpath.

For example to add all jar files in the current directory, map $(pwd) into /libs, as follows:
docker run -v $(pwd):/libs -p 1080:1080  mockserver/mockserver -serverPort 1080
 

Docker Health Checks

MockServer Docker images include a built-in HEALTHCHECK instruction that verifies the server is serving requests. Since the images are based on distroless containers (no shell, no curl), the image ships its own tiny health check program, /mockserver-healthcheck, which calls the PUT /mockserver/status endpoint over plain HTTP on localhost. It is a small native binary (about 2 MB on disk and about 4 MB of memory for the moment it runs) rather than a second Java process, so running it every 10 seconds does not eat into the container's memory limit.

The built-in health check works automatically with no configuration required:

HEALTHCHECK --interval=10s --timeout=5s --start-period=120s --retries=3
  CMD ["/mockserver-healthcheck"]

The health check reads the MOCKSERVER_SERVER_PORT or SERVER_PORT environment variable to determine the port (the first port if several are listed; defaults to 1080). It reports healthy only when the status endpoint answers 200 within 3 seconds. If you set the port another way (for example -serverPort on the command line or mockserver.serverPort in a properties file), also set SERVER_PORT to the same value so the health check probes the right port. Docker reports the container as healthy once MockServer is ready to accept requests.

Using with Docker Compose

The built-in health check integrates with Docker Compose depends_on conditions:

services:
  mockserver:
    image: mockserver/mockserver:9.2.0
    ports:
      - "1080:1080"

  app:
    image: my-app:latest
    depends_on:
      mockserver:
        condition: service_healthy

To override or disable the built-in health check, use the healthcheck key in your Compose file.

Kubernetes Liveness and Readiness Probes

In Kubernetes, use httpGet probes with the configurable liveness endpoint:

containers:
  - name: mockserver
    image: mockserver/mockserver:9.2.0
    ports:
      - containerPort: 1080
    env:
      - name: MOCKSERVER_LIVENESS_HTTP_GET_PATH
        value: "/liveness/probe"
    livenessProbe:
      httpGet:
        path: /liveness/probe
        port: 1080
      initialDelaySeconds: 10
      periodSeconds: 5
    readinessProbe:
      httpGet:
        path: /mockserver/ready
        port: 1080
      initialDelaySeconds: 5
      periodSeconds: 5

Important: the MOCKSERVER_LIVENESS_HTTP_GET_PATH environment variable must be set (as shown above) for the livenessProbe httpGet to work. This path is empty (disabled) by default — without the env var, the liveness probe will return a 404. If you copy only the livenessProbe block without the env section, it will fail. The readinessProbe uses /mockserver/ready, a fixed built-in endpoint that needs no env var: it returns 503 until expectation initializers and OpenAPI seeding complete, then 200, so traffic is not routed to the pod before the seeded mocks exist.

The MockServer Helm chart configures these probes automatically.

Amazon ECS Health Check

For ECS task definitions, the built-in HEALTHCHECK in the Docker image is used automatically. Alternatively, configure an explicit health check — call the bundled probe directly, because the image has no shell or curl for a CMD-SHELL command to use:

{
  "containerDefinitions": [{
    "name": "mockserver",
    "image": "mockserver/mockserver:9.2.0",
    "healthCheck": {
      "command": ["CMD", "/mockserver-healthcheck"],
      "interval": 10,
      "timeout": 5,
      "retries": 3,
      "startPeriod": 120
    }
  }]
}

Note: The ECS CMD-SHELL health check runs on the host, not inside the distroless container, so curl is available.

For more information on the liveness endpoint configuration, see liveness configuration properties.

A selection of commonly used environment variables is shown in the Docker Compose examples below. MOCKSERVER_MAX_LLM_CONVERSATION_BODY_SIZE controls the maximum request body size that conversation-aware LLM matchers will parse (default 1 MiB; valid range 16 KiB–64 MiB). See Performance Configuration for details.

 

Docker Compose

MockServer can be run using docker compose by adding the container as a service.

For ready-to-run, one-command starting points — mock from an OpenAPI spec, a record/replay proxy, a contract-validating proxy, or a chaos proxy — see the Docker Compose recipes.

The MockServer container uses an entrypoint, so it is possible to configure the MockServer by specifying the command line flags using by specifying the command, as follows:

services:
  mockServer:
    image: mockserver/mockserver:9.2.0
    command: -logLevel DEBUG -serverPort 1090 -proxyRemotePort 80 -proxyRemoteHost www.mock-server.com
    ports:
      - 1080:1090

It is also possible to configure the MockServer by setting environment variables, as follows:

services:
  mockServer:
    image: mockserver/mockserver:9.2.0
    ports:
      - 1080:1090
    environment:
      MOCKSERVER_MAX_EXPECTATIONS: 100
      MOCKSERVER_MAX_HEADER_SIZE: 8192
      MOCKSERVER_MAX_LLM_CONVERSATION_BODY_SIZE: 1048576

It is also possible to configure the MockServer by mounting a volume containing a properties file or JSON expectation initializer, as follows:

services:
  mockServer:
    image: mockserver/mockserver:9.2.0
    ports:
      - 1080:1080
    environment:
      MOCKSERVER_PROPERTY_FILE: /config/mockserver.properties
      MOCKSERVER_INITIALIZATION_JSON_PATH: /config/initializerJson.json
    volumes:
      - type: bind
        source: .
        target: /config

To initialise MockServer using an OpenAPI specification file, mount the file and set the MOCKSERVER_INITIALIZATION_OPENAPI_PATH environment variable:

services:
  mockServer:
    image: mockserver/mockserver:9.2.0
    ports:
      - 1080:1080
    environment:
      MOCKSERVER_INITIALIZATION_OPENAPI_PATH: /config/petstore.yaml
    volumes:
      - type: bind
        source: .
        target: /config