Show only results for:












Setup Portal Linux

Requirements

Installation Requirements

  • Docker is required
  • Microsoft SQL Server 2022 or later
    • A database must already be created.
    • A user with DB Owner permissions on that database is required.
    • To use the attribute indexing feature a non Express version should be used due to the storage requirements
  • Alias or (sub)domain for the server.
  • Trusted SSL certificate for the alias or (sub)domain:
    • Must meet current security standards.
  • Accurate server time configuration (using NTP is recommended).
  • TURN/STUN server may be required for BBV, depending on your local network.
  • Keycloak 26.x Server
    • Refer to the [Keycloak Installation Guide] if needed.
  • Latest validated version:
    • Keycloak 26.4.0
    • MSSQL 2025

Installation

We recommend using a guided installation with CAXperts for UDiTH Portal. Please contact support@caxperts.com for information

The docker images are available under quay.io/caxperts/portal and quay.io/caxperts/caxturn

Reverse Proxy

While it is possible to use Portal directly exposed with HTTPS this is not recommended. Please use a reverse proxy in front of Portal.

Installation Steps

  • Ensure that requirements are met
  • Ensure MSSQL Server and Keycloak are accessible from new container for Portal
  • Create a container for Portal. A template docker compose file with the most important flags is included below
    • In comparison to the windows version the docker variant mainly uses environment variables to configure the instance

Sample docker-compose.yml file

services:
  portal_demo:
    image: quay.io/caxperts/portal:${PORTAL_VERSION:-latest}
    restart: unless-stopped
    environment:
      - KeycloakAdmin__Name=${KEYCLOAK_ADMIN_USER}
      - KeycloakAdmin__Password_file=${KEYCLOAK_ADMIN_PASSWORD}
      - KeycloakUrl=https://${KEYCLOAK_DOMAIN}${KEYCLOAK_PATH:-/}
      - KeycloakRealm=${KEYCLOAK_REALM}
      - ConnectionStrings__AdminConnection=${PORTAL_CONNECTION_STRING}
      - ServerUrl=https://${PORTAL_DOMAIN}
      - LicenseKey_file=${PORTAL_LICENSEKEY}
    networks:
      - sqlserver
      - external
    volumes:
      - ${PORTAL_IMPORT_FOLDER}:/import
      - ${PORTAL_STORAGE_FOLDER}:/storage
networks:
  external:
    external: true
    name: external
  sqlserver:
    external: true
    name: sqlserver

Sample docker-compose.yml file with CAX Turn for BBV

services:
  portal_demo:
    image: quay.io/caxperts/portal:${PORTAL_VERSION:-latest}
    restart: unless-stopped
    environment:
      - KeycloakAdmin__Name=${KEYCLOAK_ADMIN_USER}
      - KeycloakAdmin__Password_file=${KEYCLOAK_ADMIN_PASSWORD}
      - KeycloakUrl=https://${KEYCLOAK_DOMAIN}${KEYCLOAK_PATH:-/}
      - KeycloakRealm=${KEYCLOAK_REALM}
      - ConnectionStrings__AdminConnection=${PORTAL_CONNECTION_STRING}
      - ServerUrl=https://${PORTAL_DOMAIN}
      - StreamingConfig__IceConfig__IceServers__0__Urls__0=turn:${TURNSERVER_ADDRESS}:${TURNSERVER_UDP_PORT}
      - StreamingConfig__IceConfig__IceServers__0__Urls__1=turn:${TURNSERVER_ADDRESS}:${TURNSERVER_TCP_PORT}?transport=tcp
      - StreamingConfig__IceConfig__IceServers__0__CredentialType=password
      - StreamingConfig__IceConfig__IceServers__0__Username=${TURNSERVER_USERNAME}
      - StreamingConfig__IceConfig__IceServers__0__Credential=${TURNSERVER_PASSWORD}
      - LicenseKey_file=${PORTAL_LICENSEKEY}
    networks:
      - sqlserver
      - external
    volumes:
      - ${PORTAL_IMPORT_FOLDER}:/import
      - ${PORTAL_STORAGE_FOLDER}:/storage
  turn:
    image: quay.io/caxperts/caxturn:${CAXTURN_VERSION:-latest}
    # Port range mapping is very slow so we use network_mode: host
    network_mode: host
    environment:
      - CAXTURN_ENABLE_UDP=true
      - CAXTURN_ENABLE_TCP=true
      - CAXTURN_UDP_PORT=${CAXTURN_UDP_PORT}
      - CAXTURN_TCP_PORT=${CAXTURN_TCP_PORT}

      - CAXTURN_MIN_PORT=${CAXTURN_MIN_PORT}
      - CAXTURN_MAX_PORT=${CAXTURN_MAX_PORT}

      - CAXTURN_PUBLIC_IP=${CAXTURN_PUBLIC_IP}
      - CAXTURN_USERNAME=${CAXTURN_USERNAME}
      - CAXTURN_PASSWORD=${CAXTURN_PASSWORD}
    restart: unless-stopped
networks:
  external:
    external: true
    name: external
  sqlserver:
    external: true
    name: sqlserver

Sample docker-compose Keycloak

services:
  keycloak:
    image: quay.io/keycloak/keycloak:${KEYCLOAK_VERSION:-26.4.0}
    restart: unless-stopped
    environment:
      # >= 26
      KC_BOOTSTRAP_ADMIN_USERNAME: ${KEYCLOAK_ADMIN_USER}
      KC_BOOTSTRAP_ADMIN_PASSWORD: ${KEYCLOAK_ADMIN_PASSWORD}
      # <26
      KEYCLOAK_ADMIN: ${KEYCLOAK_ADMIN_USER}
      KEYCLOAK_ADMIN_PASSWORD: ${KEYCLOAK_ADMIN_PASSWORD}
      KC_DB: mssql
      KC_DB_URL: "jdbc:sqlserver://${KEYCLOAK_SQLSERVER_ADDRESS:-mssql:1433};databaseName=${KEYCLOAK_SQLSERVER_DATABASENAME};encrypt=true;trustServerCertificate=true;"
      KC_DB_USERNAME: ${KEYCLOAK_SQLSERVER_USER}
      KC_DB_PASSWORD: ${KEYCLOAK_SQLSERVER_PASSWORD}
      KC_HEALTH_ENABLED: "true"
      KC_METRICS_ENABLED: "true"
      KC_HTTP_ENABLED: true
      KC_PROXY_HEADERS: xforwarded
      KC_HOSTNAME: https://${KEYCLOAK_DOMAIN}${KEYCLOAK_PATH:-/}
      KC_HTTP_RELATIVE_PATH: ${KEYCLOAK_RELATIVE_PATH:-/}
    command: start
    networks:
      - "sqlserver"
      - "external"
    healthcheck:
      test: ['CMD-SHELL', '[ -f /tmp/HealthCheck.java ] || echo "public class HealthCheck { public static void main(String[] args) throws java.lang.Throwable { System.exit(java.net.HttpURLConnection.HTTP_OK == ((java.net.HttpURLConnection)new java.net.URL(args[0]).openConnection()).getResponseCode() ? 0 : 1); } }" > /tmp/HealthCheck.java && java /tmp/HealthCheck.java http://localhost:9000${KEYCLOAK_RELATIVE_PATH:-/}/health/live']
      interval: 5s
      timeout: 3s
      retries: 3
      start_period: 1m
    volumes: 
      - /root/storage/keycloak/providers:/opt/keycloak/providers
networks:
  external:
    external: true
    name: "external"
  sqlserver:
    external: true
    name: "sqlserver"

Sample docker-compose.yml for MSSQL

services:
 mssql:
    image: mcr.microsoft.com/mssql/server:${MSSQL_VERSION:-2025-latest}
    environment:
      SA_PASSWORD: ${SQLSERVER_SA_PASSWORD}
      ACCEPT_EULA: "Y"
    volumes:
      - ${SQLSERVER_STORAGE_FOLDER}:/var/opt/mssql
    ports:
      - 1433:1433 #not required. But useful for remote connection. Secure this
    restart: unless-stopped
    healthcheck:
      # -C disable checks for encryption
      test: /opt/mssql-tools18/bin/sqlcmd -S localhost -C -U sa -P "$SQLSERVER_SA_PASSWORD" -Q "SELECT 1" -b -o /dev/null
      interval: 5s
      timeout: 3s
      retries: 3
      start_period: 10m
networks:
  default:
    external: true
    name: sqlserver

Accessing Portal

Goto the keycloak installation and update the defaultadmin password in the realm you specified Goto https://<alias/(sub)domain>/Portal and login via defaultadmin and your defined password

You can add additional users via the webinterface or link to a SSO provider.

Keycloak Login

Environment Variables

File secrets

All variables can also be read from a file like docker secrets. For this add a postfix of _file to the variable and reference the file where the secret is contained.

KeycloakAdmin__Password=<pw>
KeycloakAdmin__Password_file=/run/secrets/keycloak_password

Array based

Some settings represent an array. In this case please use the following format. They start with 0 and increment. In future settings array identifiers will be marked with []

Serilog__WriteTo__0__Name=Console
Serilog__WriteTo__1__Name=OpenTelemetry

They can also be multiple arrays in place

StreamingConfig__IceConfig__IceServers__0__Urls__0=turn:server1:3478
StreamingConfig__IceConfig__IceServers__0__Urls__1=turn:server1:3478?transport=tcp

Variables

# URL used to connect to keycloak. This is the same url as clients will use to authenticate
KeycloakUrl=https://...
# Keycloak Realm to use for authentications
KeycloakRealm=portal
# Keycloak Admin user name
KeycloakAdmin__Name=admin
# Keycloak Admin user password
KeycloakAdmin__Password=...

# MSSQL Database connection
ConnectionStrings__AdminConnection=...
# URL which the server will be reachable under
ServerUrl=https://
# If you are using a proxy you need to define this if it modifies the url to a new relative path
RelativePath=/ (default)
# The port Portal will listen on 
ServerPort=5000 (default)
# UDiTH License key to use. Can also be configured via the interface
LicenseKey=...
# Ignore Certificate errors for connections to Keycloak
IgnoreCertificateErrors=false (default)
# Log usernames for requests and BBV sessions
ShowPII=false (default)
# For what domains to add CORS allow origions
AccessControlAllowOrigin__[]=...

# if for Keycloak or Licensing a proxy server is required please specify
Proxy__Address=...
Proxy__UserName=...
Proxy__Password=...

# If you are running without a ReverseProxy or require fully encrypted connections you can specify either a PFX file or PEM key and cert. For PFX a password is required, for PEM its required if a encrypted PEM is used
StandaloneHttpsSettings__PfxFile=...
StandaloneHttpsSettings__PemKeyFile=...
StandaloneHttpsSettings__PemCertFile=...
StandaloneHttpsSettings__Password=...

# From which folder to import models from
ModelImport__ImportDirectory=/import (default)
# Where will imported models be placed
ModelImport__ProviderStoragePath=/storage (default)
# Fow often are ... checked
ModelImport__IntervalInMilliseconds=5000 (default)

# Dont allow model attributes to be imported into the database
ModelProcessing__ForcedSkipProcessing=false

# With modeloverwrites you can specify files which should be overwritten for each model
ModelFileOverwrites__Values__Data_default.upvf=/overwrittendefault.upvf

# For BBV an ICE server needs to be configured
StreamingConfig__IceConfig__IceServers__[]__CredentialType=password (default)
StreamingConfig__IceConfig__IceServers__[]__Urls__[]=turn:
StreamingConfig__IceConfig__IceServers__[]__Username=caxturn
StreamingConfig__IceConfig__IceServers__[]__Credential=...

#Logging&Monitoring
Serilog__Enrich__0=FromLogContext
Serilog__MinimumLevel__Default=Debug
Serilog__MinimumLevel__Override__Microsoft.AspNetCore.SignalR=Information
Serilog__MinimumLevel__Override__Microsoft  Warning
Serilog__MinimumLevel__Override__System Warning
Serilog__MinimumLevel__Override__Windows=Warning
Serilog__WriteTo__0__Name=Console
Serilog__WriteTo__1__Args__Endpoint=https://
Serilog__WriteTo__1__Args__IncludedData=157
Serilog__WriteTo__1__Args__Protocol=HttpProtobuf
Serilog__WriteTo__1__Name=OpenTelemetry
OTEL_EXPORTER_OTLP_ENDPOINT=https://...
OTEL_EXPORTER_OTLP_HEADERS=Authorization=...
OTEL_EXPORTER_OTLP_METRICS_PROTOCOL=http/protobuf
OTEL_METRIC_EXPORT_INTERVAL=10000
OTEL_RESOURCE_ATTRIBUTES=environment=...
OTEL_SERVICE_NAME=...



#Dont touch unless instructed
StreamingConfig__WatchdogSessionTimeOut=30000
StreamingConfig__ConnectionHandshakeTimeout=0
StreamingConfig__MaximumReceiveMessageSize=0

ModelHosting__ZipArchivePoolInitialSize=2
ModelHosting__ZipArchivePoolMinSize=2
ModelHosting__ZipArchivePoolMaxSize=10
ModelHosting__ZipArchiveCreateDuration=1000
ModelHosting__ZipArchiveRemoveDuration=5000
RunAsStandAlone=true (default)
RunMigrationsOnStartup=true (default)

Security

As with every web server, we recommend to keep it updated with the newest security fixes.