Updated conf
services:
nginx:
image: orthancteam/orthanc-nginx:25.9.0
depends_on: [orthanc, orthanc-auth-service]
restart: unless-stopped
ports: ["80:80", "443:443"]
volumes:
- /etc/letsencrypt/live/pacs.biomediqa.com/fullchain.pem:/etc/nginx/tls/crt.pem
- /etc/letsencrypt/live/pacs.biomediqa.com/privkey.pem:/etc/nginx/tls/key.pem
environment:
ENABLE_ORTHANC: "true"
ENABLE_KEYCLOAK: "true"
ENABLE_HTTPS: "true"
ENABLE_ORTHANC_TOKEN_SERVICE: "true"
ENABLE_OHIF: "true"
DOMAIN_NAME: "pacs.biomediqa.com"
orthanc:
image: orthancteam/orthanc:25.9.0
depends_on: [orthanc-db]
volumes:
- orthanc-storage:/var/lib/orthanc/db:z
- orthanc-tls:/var/lib/orthanc/tls:z
- ./orthanc.jsonc:/etc/orthanc/orthanc.json
restart: unless-stopped
environment:
ORTHANC__NAME: "Orthanc"
ORTHANC__DATABASE_SERVER_IDENTIFIER: "orthanc2"
VERBOSE_ENABLED: "true"
VERBOSE_STARTUP: "true"
VOLVIEW_PLUGIN_ENABLED: "true"
ORTHANC__POSTGRESQL__HOST: "orthanc-db"
ORTHANC__POSTGRESQL__INDEX_CONNECTIONS_COUNT: 20
ORTHANC__POSTGRESQL__TRANSACTION_MODE: "ReadCommitted"
orthanc-db:
image: postgres:16
restart: unless-stopped
volumes:
- orthanc-db:/var/lib/orthanc/data:z
environment:
POSTGRES_HOST_AUTH_METHOD: "trust"
orthanc-auth-service:
image: orthancteam/orthanc-auth-service:25.9.0
# always disable this port mapping in production !!!
# ports: ["8000:8000"]
depends_on: [keycloak]
restart: unless-stopped
environment:
ENABLE_KEYCLOAK: "true"
KEYCLOAK_URI: "https://pacs.biomediqa.com/keycloak/realms/orthanc"
KEYCLOAK_REALM: "orthanc"
KEYCLOAK_CLIENT_ID: "orthanc"
KEYCLOAK_ADMIN_URI: "https://pacs.biomediqa.com/keycloak/realms/master"
PUBLIC_ORTHANC_ROOT: "https://pacs.biomediqa.com/orthanc/"
PUBLIC_LANDING_ROOT: "https://pacs.biomediqa.com/orthanc/ui/app/token-landing.html"
PERMISSIONS_FILE_PATH: "/orthanc_auth_service/permissions.json"
ENABLE_KEYCLOAK_API_KEYS: "true"
PUBLIC_OHIF_ROOT: "https://pacs.biomediqa.com/ohif/"
env_file:
- ./secrets/orthanc-token.secret.env
secrets:
- SECRET_KEY
- KEYCLOAK_CLIENT_SECRET
volumes:
- ./permissions.json:/orthanc_auth_service/permissions.json
- ./anonymous-profile.json:/orthanc_auth_service/anonymous-profile.json
ohif:
image: orthancteam/ohif-v3:25.9.0
volumes:
- ./ohif-app-config.js:/usr/share/nginx/html/app-config.js
restart: unless-stopped
keycloak:
image: orthancteam/orthanc-keycloak:25.9.0
depends_on: [keycloak-db]
restart: unless-stopped
environment:
KC_BOOTSTRAP_ADMIN_USERNAME: "admin"
KC_DB: "postgres"
KC_DB_URL: "jdbc:postgresql://keycloak-db:5432/keycloak"
KC_DB_USERNAME: "keycloak"
KC_DB_PASSWORD: "keycloak"
KC_HOSTNAME: "https://pacs.biomediqa.com/keycloak"
secrets:
- KC_BOOTSTRAP_ADMIN_PASSWORD
keycloak-db:
image: postgres:16
restart: unless-stopped
volumes:
- keycloak-db:/var/lib/keycloak/data:Z
environment:
POSTGRES_PASSWORD: "keycloak"
POSTGRES_USER: "keycloak"
POSTGRES_DB: "keycloak"
volumes:
keycloak-db:
driver_opts:
type: none
o: bind
device: /home/bastion/orthanc/keycloak
orthanc-storage:
driver_opts:
type: none
o: bind
device: /home/bastion/orthanc/data
orthanc-db:
driver_opts:
type: none
o: bind
device: /home/bastion/orthanc/index
orthanc-tls:
driver_opts:
type: none
o: bind
device: /home/bastion/orthanc-setup/DicomTLS
secrets:
SECRET_KEY:
file: ./secrets/SECRET_KEY
KEYCLOAK_CLIENT_SECRET:
file: ./secrets/KEYCLOAK_CLIENT_SECRET
KEYCLOAK_ADMIN_PASSWORD:
file: ./secrets/KC_BOOTSTRAP_ADMIN_PASSWORD
Where permissions.json is
{
"roles" : {
"admin-role": {
"permissions": ["all", "admin-permissions"],
"authorized_labels": ["*"]
},
"doctor-role": {
"permissions":["view", "download", "share", "send"],
"authorized_labels": ["*"]
},
"upload": {
"permissions":["upload"],
"authorized_labels": ["*"]
},
"external-role": {
"authorized-labels": [
"external"
],
"permissions": [
"view",
"download",
]
}
},
"available-labels": []
}
And anonymous-profile.json is
{
"name": "Anonymous",
"user-id": null,
"authorized-labels": [
"*"
],
"permissions": [
"upload", "view", "send", "download"
],
"groups": [],
"validity": 60
}
orthanc.json is
{
"Name": "Orthanc",
"OrthancExplorer2": {
"Keycloak": {
"ClientId": "orthanc",
"Enable": true,
"Realm": "orthanc",
"Url": "https://pacs.biomediqa.com/keycloak"
},
"Tokens": {
"InstantLinksValidity": 3600,
"LandingOptions": [
{
"Type": "open-viewer-button"
},
{
"Type": "download-study"
},
{
"Icon": "bi bi-filetype-jpg",
"Id": "get-jpeg-archive",
"Title": "Download study as jpeg Archive",
"Type": "custom",
"Url": "../../studies/{UUID}/download-as-jpeg-archive?preview-level=instance&filename={StudyInstanceUID}.zip"
}
],
"ShareType": "stone-viewer-publication"
},
"UiOptions": {
"DefaultShareDuration": 90,
"EnableApiViewMenu": true,
"EnableDicomModalities": true,
"EnableOpenInOhifViewer3": true,
"EnableShares": true,
"OhifViewer3PublicRoot": "https://pacs.biomediqa.com/ohif/",
"ShareDurations": [
0,
7,
15,
30,
90,
365
],
"ShowSamePatientStudiesFilter": [
"PatientBirthDate",
"PatientID"
],
"StudyListContentIfNoSearch": "empty",
"StudyListSearchMode": "search-button"
}
},
"AuthenticationEnabled": false,
"Authorization": {
"CheckedLevel": "studies",
"Permissions": [
[
"post",
"^/auth/tokens/decode$",
""
],
[
"post",
"^/tools/find$",
"all|view"
],
[
"get",
"^/(patients|studies|series|instances)/([a-f0-9-]+)$",
"all|view"
],
[
"get",
"^/(patients|studies|series|instances)/([a-f0-9-]+)/(studies|study|series|instances)$",
"all|view"
],
[
"get",
"^/instances/([a-f0-9-]+)/(tags|header)$",
"all|view"
],
[
"get",
"^/statistics$",
"all|view"
],
[
"put",
"^/auth/tokens/(viewer-instant-link|meddream-instant-link)$",
"all|view"
],
[
"put",
"^/auth/tokens/(download-instant-link)$",
"all|download"
],
[
"put",
"^/auth/tokens/(stone-viewer-publication|meddream-viewer-publication|osimis-viewer-publication)$",
"all|share"
],
[
"post",
"^/instances$",
"all|upload"
],
[
"get",
"^/jobs/([a-f0-9-]+)$",
"all|send|modify|anonymize|q-r-remote-modalities"
],
[
"post",
"^/(peers|modalities)/(.*)/store$",
"all|send"
],
[
"get",
"^/(peers|modalities)$",
"all|send|q-r-remote-modalities"
],
[
"post",
"^/modalities/(.*)/echo$",
"all|send|q-r-remote-modalities"
],
[
"post",
"^/modalities/(.*)/query$",
"all|q-r-remote-modalities"
],
[
"get",
"^/queries/([a-f0-9-]+)/answers$",
"all|q-r-remote-modalities"
],
[
"post",
"^/modalities/(.*)/move$",
"all|q-r-remote-modalities"
],
[
"get",
"^/DICOM_WEB_ROOT/servers$",
"all|send|q-r-remote-modalities"
],
[
"get",
"^/DICOM_WEB_ROOT/(servers)/(.*)/stow$",
"all|send"
],
[
"post",
"^/(patients|studies|series|instances)/([a-f0-9-]+)/modify(.*)$",
"all|modify"
],
[
"post",
"^/(patients|studies|series|instances)/([a-f0-9-]+)/anonymize(.*)$",
"all|anonymize"
],
[
"delete",
"^/(patients|studies|series|instances)/([a-f0-9-]+)$",
"all|delete"
]
],
"StandardConfigurations": [
"stone-webviewer",
"orthanc-explorer-2",
"ohif",
"volview"
],
"TokenHttpHeaders": [
"Authorization", "api-key"
],
"UncheckedResources": [
"/app/images/unsupported.png",
"/system",
"/ui/api/pre-login-configuration"
],
"UncheckedFolders": [
"/ui/app/"
],
// auth checks are performed at study level
"UncheckedLevels": [
"patients",
"series",
"instances"
],
"WebServicePassword": "hidden",
"WebServiceRootUrl": "http://orthanc-auth-service:8000/",
"WebServiceUsername": "biomediqa"
},
"DicomModalities": {
"MICRODICOM": [
"MICRODICOM",
"x.x.x.x",
50000
],
"Slicer": [
"CTKSTORE",
"x.x.x.x",
11112
]
},
"DicomTlsCertificate": "/var/lib/orthanc/tls/orthanc.crt",
"DicomTlsEnabled": true,
"DicomAlwaysAllowEcho" : true,
"DicomTlsPrivateKey": "/var/lib/orthanc/tls/orthanc.key",
"DicomTlsRemoteCertificateRequired": false,
"DicomWeb": {
"Enable": true,
"PublicRoot": "/orthanc/dicom-web/"
},
"OverwriteInstances": true,
"StoneWebViewer": {
"ShowInfoPanelAtStartup": "Never"
}
}