Run Progress-supplied Docker images with Docker Compose
- Last Updated: July 8, 2026
- 5 minute read
- Semaphore
- Documentation
Using Docker Compose is recommended for running multiple Progress-supplied Semaphore containers on a single host. By using this method, you can use a single compose.yml to describe the services, networks, and volumes. In addition, a single command can be used to start, stop, and upgrade all containers.
In this topic, we cover the following:
Example compose file
The following compose.yml runs Semaphore Studio with the Classification and Language Service, the Semantic Enhancement Server, and all required internal Semaphore services, including:
- Document Analyzer (DA)
- Rulebase Manager (RM)
- SES Manager (SM)
- Concepts Manager (CM)
- Alerting
- Knowledge Model Management (KMM)
- KMM AI Assistant
To use this example, adjust the image tags, mount points, and credentials to match your environment.
Be aware that the example applies the following settings:
- Recommended container security-hardening settings, including:
read_only: truecap_drop: [ALL]security_opt: [no-new-privileges:true]
- Each service uses a dedicated
tmpfsmount for temporary files. - Semaphore Studio declares
depends_onwithcondition: service_healthyfor internal services to help ensure the correct startup order.
Note that because all services are attached to the semaphore-network bridge network, Semaphore Studio can reach the other services using the Compose service names (cs, ses, da, rm, sm, cm, alerting, ai, kmm) as host names. When configuring Semaphore Studio, use the Compose service names as host names in the service URLs. For example, set the CS URL to http://cs:5058 and the SES URL to http://ses:8983/ses.
services:
cs:
image: semaphore-cs:5.10.4
container_name: semaphore-cs
read_only: true
cap_drop:
- ALL
security_opt:
- no-new-privileges:true
tmpfs:
- /var/opt/semaphore/CS/tmp:uid=185,gid=0
restart: unless-stopped
ports:
- "5058:5058"
- "5059:5059"
volumes:
- /mnt/cs-licence/licence:/opt/semaphore/licence:ro
- /mnt/cs-data:/var/opt/semaphore/CS
networks:
- semaphore-network
ses:
image: semaphore-ses:5.10.4
container_name: semaphore-ses
read_only: true
cap_drop:
- ALL
security_opt:
- no-new-privileges:true
tmpfs:
- /var/opt/semaphore/SES/temp:uid=185,gid=0
restart: unless-stopped
ports:
- "8983:8983"
environment:
- SOLR_JAVA_MEM=-Xms1g -Xmx4g
- SEMAPHORE_LICENCE_DIR=/opt/semaphore/licence
volumes:
- /mnt/ses-licence:/opt/semaphore/licence:ro
- /mnt/ses-config:/etc/opt/semaphore/SES
- /mnt/ses-data:/var/opt/semaphore/SES/data
- /mnt/ses-logs:/var/opt/semaphore/SES/logs
networks:
- semaphore-network
da:
image: semaphore-da:5.10.4
container_name: semaphore-da
read_only: true
cap_drop:
- ALL
security_opt:
- no-new-privileges:true
tmpfs:
- /var/opt/semaphore/da/temp:uid=185,gid=0
restart: unless-stopped
volumes:
- /mnt/da-config:/etc/opt/semaphore/da
- /mnt/da-data:/var/opt/semaphore/da/data
- /mnt/da-logs:/var/opt/semaphore/da/logs
healthcheck:
test: ["CMD", "curl", "-sf", "http://localhost:5081/", "-o", "/dev/null"]
interval: 30s
timeout: 10s
start_period: 60s
retries: 3
networks:
- semaphore-network
rm:
image: semaphore-rm:5.10.4
container_name: semaphore-rm
read_only: true
cap_drop:
- ALL
security_opt:
- no-new-privileges:true
tmpfs:
- /var/opt/semaphore/rm/temp:uid=185,gid=0
restart: unless-stopped
volumes:
- /mnt/rm-config:/etc/opt/semaphore/rm
- /mnt/rm-data:/var/opt/semaphore/rm/data
- /mnt/rm-logs:/var/opt/semaphore/rm/logs
healthcheck:
test: ["CMD", "curl", "-sf", "http://localhost:5083/", "-o", "/dev/null"]
interval: 30s
timeout: 10s
start_period: 60s
retries: 3
networks:
- semaphore-network
sm:
image: semaphore-sm:5.10.4
container_name: semaphore-sm
read_only: true
cap_drop:
- ALL
security_opt:
- no-new-privileges:true
tmpfs:
- /var/opt/semaphore/sm/temp:uid=185,gid=0
restart: unless-stopped
volumes:
- /mnt/sm-config:/etc/opt/semaphore/sm
- /mnt/sm-data:/var/opt/semaphore/sm/data
- /mnt/sm-logs:/var/opt/semaphore/sm/logs
healthcheck:
test: ["CMD", "curl", "-sf", "http://localhost:5084/", "-o", "/dev/null"]
interval: 30s
timeout: 10s
start_period: 60s
retries: 3
networks:
- semaphore-network
cm:
image: semaphore-cm:5.10.4
container_name: semaphore-cm
read_only: true
cap_drop:
- ALL
security_opt:
- no-new-privileges:true
tmpfs:
- /var/opt/semaphore/cm/temp:uid=185,gid=0
restart: unless-stopped
volumes:
- /mnt/cm-config:/etc/opt/semaphore/cm
- /mnt/cm-data:/var/opt/semaphore/cm/data
- /mnt/cm-logs:/var/opt/semaphore/cm/logs
healthcheck:
test: ["CMD", "curl", "-sf", "http://localhost:5085/", "-o", "/dev/null"]
interval: 30s
timeout: 10s
start_period: 60s
retries: 3
networks:
- semaphore-network
alerting:
image: semaphore-alerting:5.10.4
container_name: semaphore-alerting
read_only: true
cap_drop:
- ALL
security_opt:
- no-new-privileges:true
tmpfs:
- /var/opt/semaphore/alerting/temp:uid=185,gid=0
restart: unless-stopped
environment:
- QUARKUS_MAILER_HOST=smtp.example.com
- QUARKUS_MAILER_PORT=587
- QUARKUS_MAILER_USERNAME=alerting@example.com
- QUARKUS_MAILER_PASSWORD=<password>
- QUARKUS_MAILER_FROM=alerting@example.com
volumes:
- /mnt/alerting-config:/etc/opt/semaphore/alerting
- /mnt/alerting-data:/var/opt/semaphore/alerting/data
- /mnt/alerting-logs:/var/opt/semaphore/alerting/logs
healthcheck:
test: ["CMD", "curl", "-sf", "http://localhost:5086/application/info", "-o", "/dev/null"]
interval: 30s
timeout: 10s
start_period: 60s
retries: 3
networks:
- semaphore-network
ai:
image: semaphore-ai:5.10.4
container_name: semaphore-ai
read_only: true
cap_drop:
- ALL
security_opt:
- no-new-privileges:true
tmpfs:
- /var/opt/semaphore/ai/temp:uid=185,gid=0
restart: unless-stopped
volumes:
- /mnt/ai-config:/etc/opt/semaphore/ai
- /mnt/ai-data:/var/opt/semaphore/ai/data
- /mnt/ai-logs:/var/opt/semaphore/ai/logs
healthcheck:
test: ["CMD", "curl", "-sf", "http://localhost:5087/application/info", "-o", "/dev/null"]
interval: 30s
timeout: 10s
start_period: 60s
retries: 3
networks:
- semaphore-network
kmm:
image: semaphore-kmm:5.10.4
container_name: semaphore-kmm
read_only: true
cap_drop:
- ALL
security_opt:
- no-new-privileges:true
tmpfs:
- /var/opt/semaphore/kmm/temp:uid=185,gid=0
restart: unless-stopped
volumes:
- /mnt/kmm-config:/etc/opt/semaphore/kmm
- /mnt/kmm-data:/var/opt/semaphore/kmm/workspace
- /mnt/kmm-logs:/var/opt/semaphore/kmm/logs
- /mnt/studio-data/licenses:/var/opt/semaphore/studio/data/licenses:ro
depends_on:
alerting:
condition: service_healthy
healthcheck:
test: ["CMD", "curl", "-sf", "http://localhost:5082/", "-o", "/dev/null"]
interval: 30s
timeout: 10s
start_period: 60s
retries: 3
networks:
- semaphore-network
studio:
image: semaphore-studio:5.10.4
container_name: semaphore-studio
read_only: true
cap_drop:
- ALL
security_opt:
- no-new-privileges:true
tmpfs:
- /var/opt/semaphore/studio/temp:uid=185,gid=0
restart: unless-stopped
ports:
- "5080:5080"
environment:
- STUDIO_LOG_LEVEL=WARN
- JVM_OPTS_APPEND=-Xms128M -Xmx2048M
- STUDIO_KMM_URL=http://kmm:5082/
- STUDIO_DA_URL=http://da:5081/
- STUDIO_RM_URL=http://rm:5083/
- STUDIO_SM_URL=http://sm:5084/
- STUDIO_CM_URL=http://cm:5085/
- STUDIO_AI_URL=http://ai:5087/
volumes:
- /mnt/studio-config:/etc/opt/semaphore/studio
- /mnt/studio-data/tdb:/var/opt/semaphore/studio/data/tdb
- /mnt/studio-data/licenses:/var/opt/semaphore/studio/data/licenses
- /mnt/studio-logs:/var/opt/semaphore/studio/logs
depends_on:
kmm:
condition: service_healthy
da:
condition: service_healthy
rm:
condition: service_healthy
sm:
condition: service_healthy
cm:
condition: service_healthy
alerting:
condition: service_healthy
ai:
condition: service_healthy
healthcheck:
test: ["CMD", "curl", "-sf", "http://localhost:5080/", "-o", "/dev/null"]
interval: 30s
timeout: 10s
start_period: 60s
retries: 3
networks:
- semaphore-network
networks:
semaphore-network:
name: semaphore-network
The :ro suffix on the licence volume mount makes the directory read-only inside the container. The read_only: true setting makes the entire container root filesystem read-only. Only explicitly mounted volumes and tmpfs mounts are writable.
Important: The Semaphore Studio licenses directory must be mounted read-write (do not use :ro). The KMM licence mount may remain read-only. See Licence directory requirements for details.
For details on the dual URL configuration required by CS, SES, and the Concepts Server (Inter-Service URL vs Client URL), see Run individual Progress-supplied Docker images.
Common commands
This section describes some common commands for Docker Compose that you might need to use with your Semaphore deployment.
Note that these commands should be issued from the directory containing your compose.yml file.
Refer to the Docker Compose documentation for the full command reference.
-
docker compose pull: Pulls the configured image versions. -
docker compose up -d: Creates and starts all services in the background. -
docker compose ps: Displays the status of running services. -
docker compose logs -f <service>: Follows the logs for a service. -
docker compose stop: Stops the services without removing the containers. -
docker compose down: Stops and removes the containers (mounted volumes are preserved).
Upgrading
To upgrade your Semaphore deployment to a newer release:
-
Stop the running services by executing the following command:
docker compose stopStopping the services prevents files from changing when backing up the deployment.
-
Back up every host directory that is mounted into a container. Although mounted volumes are preserved when containers are recreated, a new image may apply schema or on-disk migrations that cannot be reversed by reverting the image tag. A file-system snapshot or copy makes it possible to roll back if necessary. For example:
tar czf semaphore-backup-$(date +%F).tgz \ /mnt/cs-data \ /mnt/ses-config /mnt/ses-data /mnt/ses-logs \ /mnt/studio-config /mnt/studio-data -
Update the image tags in
compose.yml. For example, changesemaphore-studio:5.10.3tosemaphore-studio:5.10.4. -
Pull the new images:
docker compose pull -
Recreate the containers with the new images:
docker compose up -d
Result: The containers are now running the new image version. Mounted configuration and data directories are preserved, so the new containers start with the existing state.