Docker Container Installation - Smile CDR Documentation

Docker Container Installation

This page provides additional details and guidance regarding installing Smile CDR in a Docker container. This section can be skipped if Smile CDR is being installed as a server application.

Quick Start

Note: As of the 2023.02.R01 Release, Smile CDR no longer runs as the root user inside the Docker container. Therefore, the following Docker container instructions have been revised to assume that the user deploying Smile CDR inside the Docker container is also not the root user. If you are running on a Linux-based system and you are NOT the root user, then you will need to prefix the operating system commands shown below with sudo, but you will NOT need to use the sudo prefix if you are the root user on your system.

Deploying from Releases Page

The following steps will result in a basic deployment of Smile CDR with out-of-the-box configuration in a Docker container.

Note These instructions will deploy Smile CDR from a Docker image created for AMD64 platforms. If you are deploying on a server or workstation that has ARM64 architecture, see the Deploying from Docker Repository section instead.

  1. Download the Smile CDR Docker Release that you wish to use from our Releases web site.

In the following scenario, we will be using the 2025.11.R06 version. Click on the Download Docker button shown in the screenshot:

Note: You can contact your Customer Success representative to obtain your login information.

  1. Create a working folder on your machine and save the downloaded Docker Image file called smilecdr-2025.11.R06-docker.tar.gz inside that working folder.

  2. Create a file called docker-compose.yml in your working folder with the following contents:

version: "3.8"
services:
  smilecdr:
    container_name: smilecdr-2025.11.R06
    image: smilecdr:2025.11.R06
    platform: linux/amd64
    build:
      context: .
      dockerfile: Dockerfile
    ports:
      - "8000:8000"
      - "8001:8001"
      - "9000:9000"
      - "9100:9100"
      - "9200:9200"
      - "9201:9201"
    volumes:
      - db:/home/smile/smilecdr/database
      - log:/home/smile/smilecdr/log
      - mq:/home/smile/smilecdr/activemq-data
      - tmp:/home/smile/smilecdr/tmp
    restart: "unless-stopped"
volumes:
  db:
  log:
  mq:
  tmp:

Copy

Note: The platform: element in your docker-compose.yml file must be set to linux/amd64 if deploying a Smile CDR image downloaded from the Releases web site. Smile supports images for both linux/amd64 and linux/arm64 platforms, but the Releases web site only includes images for the linux/amd64 platform. For instructions on how to deploy a Smile CDR Docker container with a linux/arm64 platform image, see the Deploying from Docker Repository section.

  1. Create another file in your working folder called Dockerfile with the following contents:
FROM smilecdr:2025.11.R06

RUN mkdir /home/smile/smilecdr/activemq-data
RUN mkdir /home/smile/smilecdr/database
RUN mkdir /home/smile/smilecdr/log
RUN mkdir /home/smile/smilecdr/tmp
RUN chown -R smile:smile /home/smile/smilecdr/activemq-data
RUN chown -R smile:smile /home/smile/smilecdr/database
RUN chown -R smile:smile /home/smile/smilecdr/log
RUN chown -R smile:smile /home/smile/smilecdr/tmp
RUN chmod 775 /home/smile/smilecdr/activemq-data
RUN chmod 775 /home/smile/smilecdr/database
RUN chmod 775 /home/smile/smilecdr/log
RUN chmod 775 /home/smile/smilecdr/tmp

Copy

  1. Load the Smile CDR image into Docker
docker image load --input smilecdr-2025.11.R06-docker.tar.gz

Copy

Deploying from Docker Repository

Starting with the 2023.11.R01 Release release, Smile CDR Docker images supporting ARM64 platforms were added to the Smile CDR Docker repository. However the ARM64 compatible images are only available from the Smile CDR Docker repository and not in the Releases web site.

The following steps can be used to deploy either the pre-built ARM64 or AMD64 Smile CDR Docker image, which will result in a basic deployment of Smile CDR with out-of-the-box configuration in a Docker container.

  1. First login to the Smile CDR Docker repository using the same credentials used to access the Releases web site:
docker login https://docker.smilecdr.com -u [username]

Copy

Note: You can contact your Customer Success representative to obtain your login information.

  1. Use the docker pull command to download the appropriate Smile CDR Docker image and platform version to your local repository. Note that the docker pull command can infer the platform type to use, but the --platform option can be used to override the default platform setting. In the following scenario, we will use docker pull to retrieve the 2025.11.R06 version for ARM64 platform.
docker pull --platform linux/arm64 docker.smilecdr.com/smilecdr:2025.11.R06

Copy

If you instead need to download the AMD64 platform image, replace linux/arm64 in the above command with linux/amd64.

  1. Create a working folder on your machine.

  2. Create a file called docker-compose.yml in your working folder with the following contents:

services:
  smilecdr:
    container_name: smilecdr-2025.11.R06
    image: docker.smilecdr.com/smilecdr:2025.11.R06
    platform: linux/arm64
    build:
      context: .
      dockerfile: Dockerfile
    ports:
      - "8000:8000"
      - "8001:8001"
      - "9000:9000"
      - "9100:9100"
      - "9200:9200"
      - "9201:9201"
    volumes:
      - db:/home/smile/smilecdr/database
      - log:/home/smile/smilecdr/log
      - mq:/home/smile/smilecdr/activemq-data
      - tmp:/home/smile/smilecdr/tmp
    restart: "unless-stopped"
volumes:
  db:
  log:
  mq:
  tmp:

Copy

Set the platform: element in docker-compose.yml to match the platform of the image pulled from the Smile CDR Docker repository. Also make sure to prefix the image: name with docker.smilecdr.com/.

  1. Create another file in your working folder called Dockerfile with the following contents:
FROM docker.smilecdr.com/smilecdr:2025.11.R06

Copy

Make sure to prefix the image name in the `FROM` command with `docker.smilecdr.com/`.

## Starting Smile CDR Docker container

1. Start the Docker container

```bash
docker compose -f docker-compose.yml up -d --build

Copy

  1. Monitor the logs during the startup process
docker container logs -f smilecdr-2025.11.R06

Copy

Verifying Deployment

Assuming you see the phrase Smile, we're up and running! :) in the logs, you have now started the software. To exit the logs without stopping the container, simply type (ctrl-c).

With the software started, you can try a few things (replace localhost in the URLs below with the host name of your server if you are installing to a remote server):

Troubleshooting Problems

If Smile CDR fails to start or does not appear to be responsive, here are a couple things that you can check:

CONTAINER ID        IMAGE               COMMAND                  CREATED             STATUS              PORTS                                                                                                                NAMES
7e401352ab80        smilecdr            "/home/smile/smilecd…"   22 minutes ago      Up 17 minutes       0.0.0.0:8000-8001->8000-8001/tcp, 0.0.0.0:9000->9000/tcp, 0.0.0.0:9100->9100/tcp, 0.0.0.0:9200-9201->9200-9201/tcp   smilecdr

Copy

docker exec -it smilecdr-2025.11.R06 /bin/bash

Copy

docker cp smilecdr-2025.11.R06:/home/smile/smilecdr/log/smile.log ./smile.log

Copy

Clean Up

When you are finished with this initial test, you can use the following command to stop and clean up the running container:

docker-compose -f docker-compose.yml down -v

Copy

Basic Configuration

To retrieve and review copies of the bin/ and classes/ folders deployed to the container when it is not running, you can use the docker cp command as follows:

Before starting Smile CDR for the first time, there are two files you will want to examine for settings.

1. Environment Settings

In the bin/ directory you will find a file called setenv. This file may be used to change the amount of RAM available to Smile CDR, as well as number of other low level settings. It is a good idea to glance over it and ensure that the default settings make sense for your installation.

2. Application Configuration

In the classes/ directory you will find a file called cdr-config-Master.properties. This file contains all of the configuration for the modules which will be created the first time the system is started.

If changes are required to either of the configuration files above, these can be made by editing local copies of the configuration files and then copying the modified local files back to the container using the docker cp command:

docker cp ./bin/setenv smilecdr-2025.11.R06:/home/smile/smilecdr/bin

Customizing Smile CDR in Docker Container

If there is a need to change the configuration files or environment settings or to add jars to the customerlib/ directory in the Smile CDR container you can do this by creating a customized Smile CDR image based on the provided Smile CDR image and then re-creating the container using the command shown previously.

To create a customized Smile CDR image:

  1. Setup Docker context

When building Docker images, you need to specify a single folder or context where Docker can find all of the build dependencies. Ensure that all of your configuration changes and additions are contained within a single folder, or create a new subfolder and copy all of your changes there.

  1. Create a Dockerfile

Create a new Dockerfile that uses the original Smile CDR image as the base image and includes instructions for any additions or updates needed for the new image. For example:

# Use base Smile CDR image as parent image
FROM smilecdr

# Set the smilecdr folder as working directory
WORKDIR /home/smile/smilecdr

# Copy modified properties file to the container.
copy ./my-config-Master.properties ./classes/cdr-config-Master.properties

# Copy modified environment settings file to the container.
copy ./setenv_modified ./bin/setenv

# Add jar files to customerlib folder.
copy ./sitelib.jar ./customerlib/sitelib.jar

Copy

  1. Build a new Docker image

Execute the docker image build command to build a new image, for example:

docker image build -f Dockerfile .

Copy

The -f option above is used to specify the path and name of the Dockerfile. The last parameter (.) is the location of the Docker context folder which contains all of the changes and additions that are to be copied/added to the image. In the above example, it is specifying the current directory but it can point to any valid path on your local machine.

Mounting Customizations with Bind Mounts

Building a customized image as shown above bakes your changes into an image that must be rebuilt for every Smile CDR upgrade. As an alternative, the Smile CDR installation reserves a customer/ directory whose subdirectories hold nothing but a README.txt describing them, and exist only to receive bind mounts:

Directory Contents
customer/classes Loose files placed on the classpath: JavaScript callback scripts, narrative templates, and any other resource loaded through a classpath: path.
customer/lib JAR files placed on the classpath: interceptors, custom operation providers, Camel components, and their dependencies.

The classpath is assembled at startup in the order classes/, lib/, customerlib/, customer/classes, customer/lib. A resource that exists under both classes/ and customer/classes is therefore loaded from classes/, and a class present in both customerlib/ and customer/lib is loaded from customerlib/; a bind mount adds files to the classpath but cannot replace one that Smile CDR ships. Because the customer/ directories are separate from the directories that ship with Smile CDR, mounting a host directory over customer/classes or customer/lib hides no file Smile CDR needs, and no file needs to be copied out of the container first.

The following docker-compose.yml mounts a host directory into each of them, mounts a node configuration file into customer/, and sets the CONFIGNAME environment variable to the path of that file:

services:
  smilecdr:
    container_name: smilecdr
    image: smilecdr
    ports:
      - "8000:8000"
      - "9000:9000"
      - "9100:9100"
    environment:
      CONFIGNAME: /home/smile/smilecdr/customer/cdr-config-node1.properties
    volumes:
      - ./customizations/classes:/home/smile/smilecdr/customer/classes:ro
      - ./customizations/lib:/home/smile/smilecdr/customer/lib:ro
      - ./my-config-node1.properties:/home/smile/smilecdr/customer/cdr-config-node1.properties:ro

Copy

The equivalent using docker run:

docker run -d --name smilecdr \
  -p 8000:8000 -p 9000:9000 -p 9100:9100 \
  -e "CONFIGNAME=/home/smile/smilecdr/customer/cdr-config-node1.properties" \
  -v "$(pwd)/customizations/classes:/home/smile/smilecdr/customer/classes:ro" \
  -v "$(pwd)/customizations/lib:/home/smile/smilecdr/customer/lib:ro" \
  -v "$(pwd)/my-config-node1.properties:/home/smile/smilecdr/customer/cdr-config-node1.properties:ro" \
  smilecdr

Copy

Because the CONFIGNAME value starts with /, Smile CDR reads it as a file path. The customer/ directory itself is not on the classpath, so the configuration file mounted there is found only through this path. See The Node Configuration Properties File for the other values CONFIGNAME accepts. Mounting the configuration file into customer/ also avoids mounting over classes/, which would hide the other files Smile CDR ships there.

Smile CDR reads the classpath once, at startup, so a container restart is required after adding or changing a JAR in customer/lib.

Using System Environment for Variable Substitution

Environment variables can be set inside the Smile CDR Docker container using the environment or env_file options in the docker-compose.yml file.

Configuration Properties

For example, if different environments use a different database password, you can alter the default Smile CDR configuration file inside the Docker container which includes a cdr-config-Master.properties file with the following parameters:

module.clustermgr.config.db.password = #{env['DB_PASSWORD_CLUSTERMGR']}

Copy

Then you can set a different password for each environment using a docker-compose.yml file for each environment, similar to the following:

services:
  smilecdr:
    container_name: smilecdr-2025.11.R06
    image: smilecdr:2025.11.R06
    build:
      context: .
      dockerfile: Dockerfile
    ports:
      - "8000:8000"
      - "9000:9000"
      - "9100:9100"
      - "8001:8001"
      - "9200:9200"
      - "9201:9201"
    environment:
      - DB_PASSWORD_CLUSTERMGR=password
    volumes:
      - db:/home/smile/smilecdr/database
      - log:/home/smile/smilecdr/log
      - mq:/home/smile/smilecdr/activemq-data
      - tmp:/home/smile/smilecdr/tmp
    restart: "unless-stopped"
volumes:
  db:
  log:
  mq:
  tmp:

Copy

Runtime Environment Settings

Alternatively, Docker container environment variables can be used to override default JVM and other environment settings normally determined by the setenv script. For example, the following command could be used to build and launch a Smile CDR Docker container with the JVMARGS setting determined by an external file (jvmargs.env in the example below):

version: "3.8"
services:
  smilecdr:
    container_name: smilecdr-2025.11.R06
    image: smilecdr:2025.11.R06
    build:
      context: .
      dockerfile: Dockerfile
    ports:
      - "8000:8000"
      - "9000:9000"
      - "9100:9100"
      - "8001:8001"
      - "9200:9200"
      - "9201:9201"
    env_file:
      - ./jvmargs.env
    volumes:
      - db:/home/smile/smilecdr/database
      - log:/home/smile/smilecdr/log
      - mq:/home/smile/smilecdr/activemq-data
      - tmp:/home/smile/smilecdr/tmp
    restart: "unless-stopped"
volumes:
  db:
  log:
  mq:
  tmp:

Copy

Read-Only Filesystem Support

Smile CDR supports running in a container with a read-only filesystem (for example, Kubernetes' readOnlyRootFilesystem: true or Docker's --read-only). Read-only filesystem mode can be enabled with the cdr.read_only_filesystem.enabled=true system property, or the CDR_READ_ONLY_FILESYSTEM=true environment variable (which takes precedence); both default to false. Out of the box, several Smile CDR components write into the installation directory, so read-only deployments require that each of these components is either configured to use an external service or be given a writable mounted volume.

Logging in a Read-Only Filesystem

When read-only filesystem mode is enabled, Smile CDR writes logs to stdout only, so the platform can aggregate them and no log files accumulate in the container's writable layer (see Stdout-Only Logging Configuration for the shipped configuration). Otherwise (the default), logs are written to files under the log/ directory.

Logging is customized only by supplying a modified customerlib/logback-smile-custom.xml file. If logs also need to be written to files, add file appenders in logback-smile-custom.xml and mount a writable volume at the log/ directory. See Custom Logging for the file's format and examples. Common ways to supply the file:

-v ./logback-smile-custom.xml:/home/smile/smilecdr/customerlib/logback-smile-custom.xml:ro

Copy

Configuring Smile CDR with a Read-Only Filesystem

Routing logs to stdout is not enough to enable read-only filesystem support for Smile CDR. By default, several modules persist data into the installation directory (e.g., database/, activemq-data/). Before deploying with a read-only filesystem, review your configuration and, for each installation-directory writer, either replace it with an externalized, service-backed equivalent or give it a writable volume.

The settings that require attention, with solutions on how to adapt them to a read-only filesystem:

This list covers the features that write to the installation directory out of the box; it is not exhaustive. Any interceptor, custom module, or feature you configure to write files under the installation directory (for example a file-based ETL/import staging directory, or a custom log/appender) will likewise fail on a read-only filesystem and must be pointed at a writable volume or an external service.

Stdout-Only Logging Configuration

The configuration below is the stdout-only logging config that ships in the official Docker image since 2026.11 and activates when read-only filesystem mode is enabled.

<configuration scan="true" scanPeriod="30 seconds">
    <appender name="STDOUT_SYNC" class="ch.qos.logback.core.ConsoleAppender">
        <filter class="ca.cdr.api.log.CdrPHISafetyLogFilter"/>
        <encoder>
            <pattern>%d{HH:mm:ss.SSS} [%thread] %highlight(%-5level) M:%X{moduleId} R:%X{requestId} T:%X{trace_id} S:%X{span_id} J:%X{instanceId} C:%X{chunkId} %logger{36} - %msg%n${log.stackfilter.pattern}</pattern>
        </encoder>
    </appender>
    <appender name="STDOUT" class="ch.qos.logback.classic.AsyncAppender">
        <includeCallerData>false</includeCallerData>
        <appender-ref ref="STDOUT_SYNC" />
    </appender>

<root level="INFO">
        <appender-ref ref="STDOUT" />
    </root>

<!-- Required for runtime troubleshooting logging. -->
    <appender name="TROUBLESHOOTING_APPENDER" class="ch.qos.logback.core.helpers.NOPAppender"/>
    <logger name="ca.cdr.log"><appender-ref ref="TROUBLESHOOTING_APPENDER"/></logger>
    <logger name="ca.uhn.fhir.log"><appender-ref ref="TROUBLESHOOTING_APPENDER"/></logger>

<!-- Keep DLQ payloads and PHI out of stdout. -->
    <logger name="ca.cdr.DLQ-FAILURES" level="OFF"/>
    <logger name="ca.cdr.api.log.CdrPHISafetyLogFilter.REDACTED" level="OFF"/>

<!-- hook for customer configuration from customerlib -->
    <include file="customerlib/logback-smile-custom.xml" optional="true" />
</configuration>

Copy

Configuring Databases for Smile CDR Installed in Container

When configuring a database that requires a URL with a hostname such as PostgreSQL or MySQL, the hostname "localhost" will not be recognized by Smile CDR implementations running in a Docker container. Instead, you will need to specify one of the following:

An alternative approach is to install both Smile CDR and the database in a Docker stack. See this page for an example of how this could be done.

Deploying a Kubernetes Managed Cluster

Docker Container Installation

Installing

Platform Requirements Preparing a Linux Host Installing Smile CDR, NGINX and PostgreSQL in a Docker Stack Deploying a Kubernetes Managed Cluster Docker Container Installation Configuring Smile CDR Unix Service Installation Tuning your Installation Designing a Cluster Message Brokers Message Broker Failure Management Message Broker: Kafka Message Broker: ActiveMQ Message Broker: Pulsar Pre-Seeding Configuration and Data Production Checklist Module Licensing

Configuring Smile CDR