After extensive testing, I arrived at a configuration that works using an "SSL Termination" architecture = using HTTP on the loadbalancer (optimized internal communication) and letting Traefik manage the SSL.
1. **Internal Communication**: The load balancer communicates via HTTP with the ARC container because:
2. **SSL Termination**: Traefik manages SSL termination:
services:
ldap:
image: dcm4che/slapd-dcm4chee:2.6.8-34.0
restart: always
logging:
driver: json-file
options:
max-size: "10m"
ports:
- "389:389"
- "636:636"
environment:
STORAGE_DIR: /storage/fs1
volumes:
- /var/local/dcm4chee-arc/ldap:/var/lib/openldap/openldap-data
- /var/local/dcm4chee-arc/slapd.d:/etc/openldap/slapd.d
networks:
- web
mariadb:
image: mariadb:10.11.4
restart: always
logging:
driver: json-file
options:
max-size: "10m"
ports:
- "3306:3306"
environment:
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
MYSQL_DATABASE: keycloak
MYSQL_USER: keycloak
MYSQL_PASSWORD: ${MYSQL_PASSWORD}
volumes:
- /etc/localtime:/etc/localtime:ro
- /etc/timezone:/etc/timezone:ro
- /var/local/dcm4chee-arc/mysql:/var/lib/mysql
networks:
- web
keycloak:
image: dcm4che/keycloak:26.0.6
restart: always
logging:
driver: json-file
options:
max-size: "10m"
ports:
- "8080:8080"
- "8843:8843"
environment:
KC_HTTP_ENABLED: true
KC_HTTPS_PORT: 8843
KC_PROXY: passthrough
KC_HOSTNAME_PORT: 443
KC_HOSTNAME_BACKCHANNEL_DYNAMIC: 'true'
KC_BOOTSTRAP_ADMIN_USERNAME: admin
KC_BOOTSTRAP_ADMIN_PASSWORD: ${KC_ADMIN_PASSWORD}
KC_DB: mariadb
KC_DB_URL_DATABASE: keycloak
KC_DB_URL_HOST: mariadb
KC_DB_USERNAME: keycloak
KC_DB_PASSWORD: ${KC_DB_PASSWORD}
KC_LOG: file
KEYCLOAK_WAIT_FOR: ldap:389 mariadb:3306
depends_on:
- ldap
- mariadb
volumes:
- /etc/localtime:/etc/localtime:ro
- /etc/timezone:/etc/timezone:ro
- /var/local/dcm4chee-arc/keycloak:/opt/keycloak/data
labels:
- traefik.enable=true
- traefik.http.routers.keycloak.entrypoints=secure
- traefik.http.routers.keycloak.service=keycloak-service
- traefik.http.routers.keycloak.tls=true
- traefik.http.routers.keycloak.tls.certresolver=letsencrypt
- traefik.http.services.keycloak-service.loadbalancer.server.port=8080
- traefik.http.services.keycloak-service.loadbalancer.server.scheme=http
- traefik.http.services.keycloak-service.loadbalancer.passHostHeader=true
# add security middlewares
- traefik.http.middlewares.keycloak-sslHeaders.headers.sslRedirect=true
- traefik.http.middlewares.keycloak-sslHeaders.headers.forceSTSHeader=true
- traefik.http.middlewares.keycloak-sslHeaders.headers.stsSeconds=31536000
- traefik.http.routers.keycloak.middlewares=keycloak-sslHeaders
networks:
- web
db:
image: dcm4che/postgres-dcm4chee:17.4-34
restart: always
logging:
driver: json-file
options:
max-size: "10m"
ports:
- "5432:5432"
environment:
POSTGRES_DB: pacsdb
POSTGRES_USER: pacs
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
volumes:
- /etc/localtime:/etc/localtime:ro
- /etc/timezone:/etc/timezone:ro
- /var/local/dcm4chee-arc/db:/var/lib/postgresql/data
networks:
- web
arc:
image: dcm4che/dcm4chee-arc-psql:5.34.0-secure
restart: always
ports:
- "8082:8080"
- "8443:8443"
- "9990:9990"
- "9993:9993"
- "11112:11112"
- "2762:2762"
- "2575:2575"
- "12575:12575"
environment:
POSTGRES_DB: pacsdb
POSTGRES_USER: pacs
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
HTTP_PROXY_ADDRESS_FORWARDING: true
WILDFLY_CHOWN: /storage
WILDFLY_WAIT_FOR: ldap:389 db:5432 keycloak:8843
# Optimisations JVM (SSL géré par Traefik)
JAVA_OPTS: "-Xms2g -Xmx8g -XX:+UseG1GC -XX:MaxGCPauseMillis=200"
depends_on:
- ldap
- keycloak
- db
volumes:
- /etc/localtime:/etc/localtime:ro
- /etc/timezone:/etc/timezone:ro
- /var/local/dcm4chee-arc/wildfly:/opt/wildfly/standalone
- /var/local/dcm4chee-arc/storage:/storage
networks:
- web
labels:
- "traefik.enable=true"
# HTTP/HTTPS for web
- "traefik.http.routers.arc-https.entrypoints=secure"
- "traefik.http.routers.arc-https.service=arc-https-service"
- "traefik.http.routers.arc-https.tls=true"
- "traefik.http.routers.arc-https.tls.certresolver=letsencrypt"
- "traefik.http.services.arc-https-service.loadbalancer.server.port=8080"
- "traefik.http.services.arc-https-service.loadbalancer.server.scheme=http"
- "traefik.http.services.arc-https-service.loadbalancer.passHostHeader=true"
# security middlewares for arc
- "traefik.http.middlewares.arc-sslHeaders.headers.sslRedirect=true"
- "traefik.http.middlewares.arc-sslHeaders.headers.forceSTSHeader=true"
- "traefik.http.middlewares.arc-sslHeaders.headers.stsSeconds=31536000"
- "traefik.http.routers.arc-https.middlewares=arc-sslHeaders"
# DICOM TCP
- "traefik.tcp.routers.dicom.entrypoints=dicom"
- "traefik.tcp.routers.dicom.rule=HostSNI(`*`)"
- "traefik.tcp.routers.dicom.service=arc-dicom"
- "traefik.tcp.services.arc-dicom.loadbalancer.server.port=11112"
# HL7 TCP
- "traefik.tcp.routers.hl7.entrypoints=hl7"
- "traefik.tcp.routers.hl7.rule=HostSNI(`*`)"
- "traefik.tcp.routers.hl7.service=arc-hl7"
- "traefik.tcp.services.arc-hl7.loadbalancer.server.port=2575"
networks:
web:
external: true
I also had a certificate issue that I resolved by also setting S3 to HTTP.