Article How do I install a production environment?

This is a more realistic, full setup of Community with Docker Compose and no debug services, host bind mounts, antivirus, external SQL server, email, and more.

For a more full-featured and scalable environment, consider using a Kubernetes cluster for hosting these containers instead of Compose. That is beyond the scope of this documentation. Hosting with Verint already provides auto-scaling via Kubernetes.

Prerequisites

What This Uses

Save the following sample Docker Compose files:

compose.yml:

name: community

x-common-variables: &common-variables
  # Note: The following credentials are for development and testing purposes only.
  # Use strong passwords in production and consider using secrets management for sensitive information
  MSSQL_HOST: database
  MSSQL_SA_USER: SA
  MSSQL_SA_PASSWORD: T3ll1g3nt
  MSSQL_APP_USER: community_user
  MSSQL_APP_PASSWORD: T3ll1g3nt
  DB_FORCE_UPGRADE: ${DB_FORCE_UPGRADE:-false}
  APP_DB_NAME: ${APP_DB_NAME:-community_app}
  REPORTING_DB_NAME: ${REPORTING_DB_NAME:-community_reporting}
  ADMIN_USERNAME: admin
  ADMIN_PASSWORD: p
  ADMIN_EMAIL: admin@example.com

x-app-variables: &app-variables
  EVOLUTION_CONFIGURATION_SOURCES: file=~/communitySettings.json;file=/community/config/compose.settings.json;env;command

networks:
  community:
    name: community-net

services:
  web:
    image: af1.verintconnect.com/dfe-community/community/web:14.0.0.644
    restart: unless-stopped
    networks:
      - community
    ports:
      - 8080:8080
    read_only: true
    tmpfs:
      - /tmp
    volumes:
      - ./data/cfs:/app/cfs
      - ./config/settings.json:/community/config/compose.settings.json:ro
    environment:
      <<: *app-variables
    healthcheck:
      test: ["CMD", "/app/tools/healthcheck"]
      start_period: 20s
      interval: 60s
      timeout: 10s
      retries: 5
    depends_on:
      database:
        condition: service_healthy
      search:
        condition: service_healthy
      antivirus:
        condition: service_healthy
      installer:
        condition: service_completed_successfully
      cfs-init:
        condition: service_completed_successfully

  job:
    image: af1.verintconnect.com/dfe-community/community/job:14.0.0.644
    restart: unless-stopped
    networks:
      - community
    read_only: true
    tmpfs:
      - /tmp
    volumes:
      - ./data/cfs:/app/cfs
      - ./config/settings.json:/community/config/compose.settings.json:ro
    environment:
      <<: *app-variables
    healthcheck:
      test: ["CMD", "/app/tools/healthcheck"]
      start_period: 20s
      interval: 60s
      timeout: 10s
      retries: 5
    depends_on:
      database:
        condition: service_healthy
      search:
        condition: service_healthy
      antivirus:
        condition: service_healthy
      installer:
        condition: service_completed_successfully
      cfs-init:
        condition: service_completed_successfully

  database:
    image: mcr.microsoft.com/mssql/server:2022-CU20-ubuntu-22.04
    restart: unless-stopped
    networks:
      - community
    ports:
      - 5433:1433
    volumes:
      - ./data/sql:/var/opt/mssql
    environment:
      <<: *common-variables
      ACCEPT_EULA: Y
    healthcheck:
      test: >-
        /opt/mssql-tools18/bin/sqlcmd -C -S localhost -U SA -P "$$MSSQL_SA_PASSWORD" -Q "SELECT 1" || exit 1
      interval: 10s
      timeout: 3s
      retries: 10
      start_period: 10s

  search:
    image: af1.verintconnect.com/dfe-community/community/search:14.0.0.619
    restart: unless-stopped
    networks:
      - community
    ports:
      - 5983:8983
    volumes:
      - ./data/solr:/var/solr
    environment:
      CORE_CONTENT: telligent-content
      CORE_CONVERSATIONS: telligent-conversations
    healthcheck:
      test: >-
        curl -s -A 'healthcheck' http://localhost:8983/solr/$$CORE_CONTENT/admin/ping?wt=json | grep -q '"status":"OK"'
      start_period: 15s
      interval: 10s
      timeout: 5s
      retries: 3

  infra:
    image: af1.verintconnect.com/dfe-community/community/infra:14.0.0.644
    restart: unless-stopped
    networks:
      - community
    ports:
      - 5700:8080
    read_only: true
    tmpfs:
      - /tmp
    environment:
      INFRA_Cache_MemoryLimitMegabytes: 500
      INFRA_MessageBus_MaxLengthBytes: 102400
      INFRA_MessageBus_IdleSeconds: 60
      INFRA_Metrics_EnableOtlp: true
      INFRA_Metrics_EnableConsole: false
      INFRA_Metrics_OtlpEndpointProtocol: grpc
      INFRA_Metrics_OtlpEndpoint: http://telemetry:18889/
      INFRA_Logging_EnableOtlp: true
      INFRA_Logging_EnableConsole: false
      INFRA_Logging_OtlpEndpointProtocol: grpc
      INFRA_Logging_OtlpEndpoint: http://telemetry:18889/
      INFRA_Logging_MinimumLevel: Information,Microsoft.AspNetCore:Warning
    healthcheck:
      test: ["CMD", "/app/tools/healthcheck"]
      start_period: 20s
      interval: 60s
      timeout: 10s
      retries: 5

  telemetry:
    image: mcr.microsoft.com/dotnet/aspire-dashboard:9.3.0
    restart: unless-stopped
    networks:
      - community
    ports:
      - 5888:5888
      - 5317:18889
    environment:
      ASPNETCORE_URLS: http://+:5888

  smtp:
    image: axllent/mailpit:v1.27
    restart: unless-stopped
    networks:
      - community
    ports:
      - 5825:8025
      - 5025:1025

  installer:
    image: af1.verintconnect.com/dfe-community/community/installer:14.0.0.644
    networks:
      - community
    environment:
      <<: *common-variables
    depends_on:
      database:
        condition: service_healthy
        restart: true

  antivirus:
    image: clamav/clamav-debian:1.4.3
    restart: unless-stopped
    networks:
      - community
    ports:
      - 5310:3310
    healthcheck:
      test: ["CMD-SHELL", "echo 'PING' | nc -w 5 localhost 3310"]
      interval: 30s
      timeout: 10s
      retries: 5

  # Ensure file storage volume is owned by
  # app user (1654) of the web and job services
  cfs-init:
    image: alpine:3.22.1
    volumes:
      - ./data/cfs:/app/cfs
    networks:
      - community
    entrypoint: chown -R 1654:1654 /app/cfs

settings.json:

{
  "Core": {
    "DisableEmail": false,
    "SiteUrl": "http://localhost:8080",
    "ApplicationPort": 8080
  },
  "ConnectionStrings": {
    "SiteSqlServer": "server=database;uid=community_user;pwd=T3ll1g3nt;Trusted_Connection=no;TrustServerCertificate=True;database=community_app",
    "Reporting": "server=database;uid=community_user;pwd=T3ll1g3nt;Trusted_Connection=no;TrustServerCertificate=True;database=community_reporting"
  },
  "CentralizedFileStorage": {
    "RootPath": "/app/cfs"
  },
  "Search": {
    "SolrContentUrl": "http://search:8983/solr/telligent-content/",
    "SolrConversationsUrl": "http://search:8983/solr/telligent-conversations/"
  },
  "PluginEnablement": {
    "Telligent.Evolution.Infra.Connector.InfraPlugin, Telligent.Evolution.Infra.Connector": true,
    "Telligent.Evolution.Api.Plugins.FileValidators.ClamAvFileValidator, Telligent.Evolution.Platform":  true
  },
  "PluginConfiguration": {
    "Telligent.Evolution.Infra.Connector.InfraPlugin, Telligent.Evolution.Infra.Connector:host": "http://infra:8080",
    "Telligent.Evolution.Api.Plugins.FileValidators.ClamAvFileValidator, Telligent.Evolution.Platform:host": "antivirus",
    "Telligent.Evolution.Api.Plugins.FileValidators.ClamAvFileValidator, Telligent.Evolution.Platform:port": 3310
  },
  "Tracing": {
    "EnableOtlp": true,
    "OtlpEndpointProtocol": "grpc",
    "OtlpEndpoint": "http://telemetry:18889/"
  },
  "Metrics": {
    "EnableOtlp": true,
    "OtlpEndpointProtocol": "grpc",
    "OtlpEndpoint": "http://telemetry:18889/"
  },
  "Logging": {
    "EnableOtlp": true,
    "OtlpEndpointProtocol": "grpc",
    "OtlpEndpoint": "http://telemetry:18889/"
  }
}

They provide:

  • One Web container
  • One Job container
  • Containerized SQL Server
  •  Search, Infra, Installer, ClamAV for antivirus, and Aspire Dashboard for telemetry
  • Bind mounts for persisted data
  • Direct HTTP access to web on port 8080

Prepare a Working Directory

Create a directory for the stack with the sample files:

community/
  compose.yml
  config/
    settings.json
  data/
    sql/
    cfs/
    solr/

Bind Mounts

Named volumes are easy for a quick start. Bind mounts are often better when you need to:

  • Inspect or replace SQL, CFS, or Solr data from the host
  • Have easier ability to back up state
  • Keep configuration files under your own directory layout

The above structure defines physical paths for SQL, CFS, and Solr data bind mounts. Those locations are reflected in compose.yml's services' volume mounts, such as the following snippet where ./data/cfs matches the structure above relative to the location of compose.yml. If you use different locations for SQL, CFS, and Solr data, update their corresponding paths within compose.yml.

services:
  web:
    # ...
    volumes:
      - ./data/cfs:/app/cfs
    # ...

Credentials

Adjust any user names or passwords for database and application accounts at the top of compose.yml as you see fit.

Non-Containerized SQL Server

Using containerized SQL Server is the easiest option, but you can also use an external database.

Edit compose.yml:

MSSQL_HOST: <SQL_DATABASE_SERVER>
MSSQL_SA_USER: <SQL_ADMIN_USER_NAME>
MSSQL_SA_PASSWORD: <SQL_ADMIN_PASSWORD>
MSSQL_APP_USER: community_user
MSSQL_APP_PASSWORD: <COMMUNITY_USER_PASSWORD>
APP_DB_NAME: community_app
REPORTING_DB_NAME: community_reporting

When the installer container runs, it connects to the SQL host using SA to create or update the app and reporting databases, create the community user, and grant the proper permissions to the community user.

Connection Strings

Ensure SQL credentials are also updated in settings.json's ConnectionStrings nodes.

The named server, database, in connection strings matches the name of the service (database) defined in compose.yml.

Start the Stack

From the directory containing your customized compose.yml:

docker compose up -d --remove-orphans

If SQL Server is included in the stack, make sure your use of the Microsoft SQL Server image is covered by an accepted EULA. The sample service uses ACCEPT_EULA=Y. SQL Server runs in the free Developer edition MSSQL_PID=Developer by default. For more information, refer to Microsoft's documentation.

On first startup, expect a longer wait while:

  • Images are pulled
  • SQL Server initializes
  • Solr creates Community cores
  • The installer creates or upgrades databases

Log in

After the stack is healthy, log in to Community at http://localhost:8080 with the admin username and password configured at the top of your compose.yml.

Endpoints

All endpoints made available:

Warning

If using this Compose stack in a production environment, remove port forwards for all of these services except for Community or ensure whatever reverse proxy is routing traffic to Community is not also exposing these other services.

What to Customize First

The sample settings.json is the main configuration layer mounted into web and job.

While logged in as an Administrator:

Configure telemetry and logging endpoints  if you do not want local Aspire

Notes on Site URL, Host Names, and Proxying

The sample stack exposes a single web directly on port 8080. To modify this, customize the port or non-default host name by modifying Core:SiteUrl and Core:ApplicationPort in settings.json and the forwarded port for the web service in compose.yml. Restart the stack after these changes.

Add a local hosts entry for the custom host name. This provides host-based access only. TLS and standard web ports still need an external reverse proxy or TLS offloader.

If using a reverse proxy, you can add more web instances by copying and pasting the web service into a web2, web3, etc, with different forwarded ports. Routing to these nodes would defined by the reverse proxy.

Next Steps

While out of scope for this guide, Community images can be used with Kubernetes as well. Please review what container images make up Verint Community .