Print Manager: Installation & Getting Started

Guide for installing the Print Manager and getting started.

Print Manager Technical Guide

Thank you for using the Bergstein DIGI Print Manager!

In this document the following technical technical details are explained;

Intro

The Print Manager is an application suite of up to 5 virtualized container applications:

The Print Manager Server application is the central hub for all Print Manager interactions. Depending on enabled features, it can process uploaded files, like PDF images, scan files for malware and use the files to create custom print jobs for (Bergstein DIGI) printers.

The Print Manager Client application is a web app, which allows users to interface with the Print Manager Server.

Postgres is the database server and is used to store the data generated by the Server application.

ClamAv is used to scan files for Malware.

Traefik is the load balancer for all the applications and provides FQDN registration and SSL certificate renewal.

The containers are OCI and can be run with Docker or Podman. All container images are built on Linux kernel, if your target host device is Windows you can use WSL to allow running of (Linux) images in Docker on Windows.

Besides these 5 main containers, there are also a handful of helper containers to make maintainability easier:

Requirements

Before installation, please make sure the target device which will host the Print Manager has the required (hardware) capabilities.

To ensure optimal performance and compatibility, use the following system requirements as a guideline for a Print Manager system with 5 printers with a default workload of 10 unique jobs per minute concurrently.

The following specifications are indicative and may vary depending on the amount of printers and actual (print) workload.

For higher printer count and or print workload see the 'Hardware Scaling' section.

'* depends on usage'

1. Hardware Requirements

2. Software Requirements

3. Network & Connectivity

Ensure that the following network connectivity is allowed on the target network.

Ports and protocol standards can be altered via specific environment variables when running the application containers.

The following are default values.

Installation

To install the Print Manager on the target device please follow the next steps;

1) Fetch the (latest) container images

The majority of container images are available on our Azure cloud hosted container registry. To access it you should first request ACR login credentials at support@bergstein.nl.

To login you need to instal the AZ_CLI in your console/terminal. See the Microsoft AZ CLI page: https://github.com/Azure/azure-cli .

After you've received the credentials, you can perform the following command in your console/terminal:

az login --service-principal --username <APP_ID> --password <CLIENT_SECRET> --tenant <TENANT_ID> && az acr login --name bgppregistryprintmanager

Now you should be logged in and able to fetch docker images. The convention is always the same: <REGISTRY_NAME>/<IMAGE_NAME>: Our registry name is bgppregistryprintmanager.azurecr.io.

So for example you should be able to get the latest Print Manager Server by doing:

docker pull bgppregistryprintmanager.azurecr.io/printmanager_server:latest

Or use a specific version like 1.8.0.0:

docker pull bgppregistryprintmanager.azurecr.io/printmanager_server:1.8.0.0

This is the list of available images:

2) Orchestration & deployment

As stated before, the Print Manager consists of several application images. To avoid pulling each individual container and manually configuring them, we've opted to use an orchestration tool like Docker-Compose, however you can also use tools like Kubernetes or the Podman-Compose.

We will provide you with an example Docker-Compose file which you can use as an initial setup. Just copy the following data into a docker-compose.yaml file. This example expects a network within Docker with the name printmanager. This network can be created with command: docker network create printmanager. Now the Print Manager software can be started with command: docker compose pull and then docker compose up (or docker compose up -d to run everything headless).

services:
  PrintManagerServer:
    image: bgppregistryprintmanager.azurecr.io/printmanager_server:1.8.0.0
    container_name: printmanagerserver
    networks:
      - printmanager
    restart: unless-stopped
    depends_on:
      PrintManagerDb:
        condition: service_healthy
    volumes:
      - c:\ONYXThrive25\Input:/onyx_input
      - c:\ISI_files:/onyx_isi_files
      - c:\Bergstein\Printmanager\SSL:/https:ro
      - c:\Bergstein\Printmanager\FileData:/data
      - C:\Bergstein\Printmanager\Logs:/app/logs/
    environment:
      "ASPNETCORE_ENVIRONMENT": "Development"
      "ASPNETCORE_HTTP_PORTS": "5000,5002,5004"
      "ASPNETCORE_HTTPS_PORTS": "5001"
      "ConnectionStrings__ApplicationModuleV1_Database": "Server=printmanagerdb; Port=5432; Database=application; Username=user; Password=<ChangeThisToAStrongPassword!>"
      "ConnectionStrings__JobComposingModuleV1_Database": "Server=printmanagerdb; Port=5432; Database=jobcompose; Username=user; Password=<ChangeThisToAStrongPassword!>"
      "ConnectionStrings__AuthenticationModuleV1_Database": "Server=printmanagerdb; Port=5432; Database=authentication; Username=user; Password=<ChangeThisToAStrongPassword!>"
      "ConnectionStrings__PrinterGatewayModuleV1_Database": "Server=printmanagerdb; Port=5432; Database=printergateway; Username=user; Password=<ChangeThisToAStrongPassword!>"
      "ConnectionStrings__FilesModuleV1_Database": "Server=printmanagerdb; Port=5432; Database=file; Username=user; Password=<ChangeThisToAStrongPassword!>"
      "Serilog__Using__0": "Serilog.Sinks.Console"
      "Serilog__Using__1": "Serilog.Sinks.File"
      "Serilog__MinimumLevel__Default": "Information"
      "Serilog__MinimumLevel__Override__Microsoft": "Warning"
      "Serilog__MinimumLevel__Override__System": "Warning"
      "Serilog__Enrich__0": "FromLogContext"
      "Serilog__Enrich__1": "WithMachineName"
      "Serilog__Enrich__2": "WithThreadId"
      "Serilog__WriteTo__0__Name": "Console"
      "Serilog__WriteTo__0__Args__outputTemplate": "[{Timestamp:HH:mm:ss} {Level:u3}] {Message:lj} {Properties:j}{NewLine}{Exception}"
      "Serilog__WriteTo__1__Name": "File"
      "Serilog__WriteTo__1__Args__path": "./logs/structured-log-.clef"
      "Serilog__WriteTo__1__Args__rollingInterval": "Day"
      "Serilog__WriteTo__1__Args__fileSizeLimitBytes": 104857600
      "Serilog__WriteTo__1__Args__rollOnFileSizeLimit": true
      "OnyxThriveOptions__FtpOptions__ServerUrl": "ftp://MY_ONYX_PC"
      "OnyxThriveOptions__FtpOptions__Port": 21
      "OnyxThriveOptions__FtpOptions__UserName": ""
      "OnyxThriveOptions__FtpOptions__Password": ""
      "OnyxThriveOptions__FtpOptions__AnonymousLogin": false
      "OnyxThriveOptions__FtpOptions__UsePassive": true
      "OnyxThriveOptions__FtpOptions__KeepAlive": false
      "OnyxThriveOptions__FtpOptions__EnableSsl": false
      "OnyxThriveOptions__UncOptions__ServerUrl": "/"
      "OnyxThriveOptions__PrinterName": "INX JetINX"
      "OnyxThriveOptions__QuickSet": "MY_QUICKSET"
      "AvOptions__ClamAvOptions__ServerAddress": "clam_av"
      "AvOptions__ClamAvOptions__Port": 3310
      "JwtTokenOptions__Issuer": "localhost"
      "JwtTokenOptions__Audience": "Bergstein"
      "JwtTokenOptions__Key": "<PLEASE_ENTER_128_RANDOM_CHARACTERS_HERE>"
      "GrpcClientOptions__Address": "https://localhost:5001/"
      "GrpcClientOptions__UseSsl": true
      "GrpcClientOptions__AcceptInvalidSslCertificate": true
      "GrpcClientOptions__UseAuthentication": true
      "GrpcClientOptions__AuthenticationSchemeNameValue": "Admin"
      "GrpcClientOptions__AuthenticationSchemeSecretValue": "B3rgst3!n"
      "FeatureFlags__DeveloperMode": true
      "FeatureFlags__DetailedLogging": true
      "FeatureFlags__HTTPS" : true
      "FeatureFlags__AuthenticationModuleV1" : true
      "FeatureFlags__AuthenticationModuleV1_InMemoryDatabase" : false
      "FeatureFlags__AuthenticationModuleV1_PostgresDatabase" : true
      "FeatureFlags__AuthenticationModuleV1_SeedEntities" : true
      "FeatureFlags__FilesModuleV1": true
      "FeatureFlags__FilesModuleV1_InMemoryDatabase": false
      "FeatureFlags__FilesModuleV1_PostgresDatabase": true
      "FeatureFlags__FilesModuleV1_InMemoryStorage": false
      "FeatureFlags__FilesModuleV1_PhysicalStorage": true
      "FeatureFlags__FilesModuleV1_SeedEntities": false
      "FeatureFlags__JobComposingModuleV1": true
      "FeatureFlags__JobComposingModuleV1_DigiRip" : false
      "FeatureFlags__JobComposingModuleV1_OnyxRip" : true
      "FeatureFlags__JobComposingModuleV1_InMemoryDatabase" : false
      "FeatureFlags__JobComposingModuleV1_PostgresDatabase" : true
      "FeatureFlags__JobComposingModuleV1_SeedEntities" : false
      "FeatureFlags__PrinterGatewayModuleV1" : true
      "FeatureFlags__PrinterGatewayModuleV1_InMemoryDatabase" : false
      "FeatureFlags__PrinterGatewayModuleV1_PostgresDatabase" : true
      "FeatureFlags__PrinterGatewayModuleV1_SeedEntities" : false
      "FeatureFlags__ApplicationModuleV1": true
      "FeatureFlags__ApplicationModuleV1_InMemoryDatabase": false
      "FeatureFlags__ApplicationModuleV1_PostgresDatabase": true
      "FeatureFlags__JobSchedulingModuleV1" : true
      "FeatureFlags__RasterizationModuleV1" : true
      "FeatureFlags__RasterizationModuleV1_DigiRip" : false
      "FeatureFlags__RasterizationModuleV1_OnyxRip" : true
      "FeatureFlags__RasterizationModuleV1_OnyxRipFtp" : false
      "FeatureFlags__RasterizationModuleV1_OnyxRipUnc" : true
      "FeatureFlags__ClamAv" : true
      "FeatureFlags__NoAv" : false
      "ASPNETCORE_Kestrel__Certificates__Default__Path": "/https/certificate.pfx"
      "ASPNETCORE_Kestrel__Certificates__Default__Password": "<CERTIFICATE_PASSWORD>"
  PrintManagerClient:
    image: bgppregistryprintmanager.azurecr.io/printmanager_client:1.8.0.0
    container_name: printmanagerclient
    networks:
      - printmanager
    restart: unless-stopped
    environment:
      "GrpcClientOptions__Address": "https://server.localhost"
      "GrpcClientOptions__UseSsl" : true
      "GrpcClientOptions__AcceptInvalidSslCertificate": true
      "GrpcClientOptions__UseAuthentication" : true
      "ASPNETCORE_HTTP_PORTS": "7000"
      "ASPNETCORE_HTTPS_PORTS": "7001"
      "ASPNETCORE_ENVIRONMENT": "Development"
    volumes:
      - c:\Bergstein\Printmanager\SSL:/etc/ssl:ro
  Traefik:
    image: traefik:v3.3.3
    container_name: traefik
    ports:
      - 80:80
      - 443:443
    restart: unless-stopped
    networks:
      - printmanager
    volumes:
      - c:\Bergstein\Printmanager\Traefik\Config\traefik.yml:/etc/traefik/traefik.yml
      - c:\Bergstein\Printmanager\Traefik\Config\DynamicDev\:/etc/traefik/dynamic/
      - c:\Bergstein\Printmanager\SSL\:/etc/traefik/certs:ro
  ClamAv:
    image: clamav/clamav:1.5.2
    container_name: clam_av
    networks:
      - printmanager
    restart: unless-stopped
  PrintManagerDb:
    image: postgres:18-alpine
    container_name: printmanagerdb
    restart: unless-stopped
    networks:
      - printmanager
    environment:
      "POSTGRES_USER": "user"
      "PGUSER": "user"
      "POSTGRES_PASSWORD": "<ChangeThisToAStrongPassword!>"
      "POSTGRES_DB": "user"
    volumes:
      - c:\Bergstein\Printmanager\Postgres\postgres-data:/var/lib/postgresql
      - c:\Bergstein\Printmanager\Postgres\Init\:/docker-entrypoint-initdb.d
    healthcheck:
      test: ["CMD-SHELL", "pg_isready", "-d", "jobcompose"]
      start_period: 30s
      interval: 30s
      timeout: 5s
      retries: 3
  GrpcUi:
    image: fullstorydev/grpcui:v1.4.3
    container_name: grpc_ui
    command: "-insecure printmanagerserver:5001"
    depends_on:
      PrintManagerServer:
        condition: service_started
    networks:
      - printmanager
    restart: unless-stopped
  Adminer:
    ports:
      - 8080:8080
    image: adminer
    container_name: adminer
    environment:
      ADMINER_DEFAULT_SERVER: "PrintManagerDb"
      ADMINER_DESIGN: dracula
    depends_on:
      PrintManagerDb:
        condition: service_healthy
    networks:
      - printmanager
    restart: unless-stopped
  Swagger:
    image: swaggerapi/swagger-ui:v5.29.0
    container_name: swagger_ui
    environment:
      URLS: "[ { url: \"https://server.localhost/swagger/Authentication.v1/swagger.json\", name: \"Authentication.V1\" },{ url: \"https://server.localhost/swagger/JobComposing.v1/swagger.json\", name: \"JobComposing.V1\" },{ url: \"https://server.localhost/swagger/PrinterGateway.v1/swagger.json\", name: \"PrinterGateway.V1\" },{ url: \"https://server.localhost/swagger/Rasterization.v1/swagger.json\", name: \"Rasterization.V1\" },{ url: \"https://server.localhost/swagger/JobScheduling.v1/swagger.json\", name: \"JobScheduling.V1\" },{ url: \"https://server.localhost/swagger/Files.v1/swagger.json\", name: \"Files.V1\" },{ url: \"https://server.localhost/swagger/Application.v1/swagger.json\", name: \"Application.V1\" } ]"
    networks:
      - printmanager
    depends_on:
      PrintManagerServer:
        condition: service_started
    restart: unless-stopped
networks:
  printmanager:
    external: true 

Initial configuration

As you can see from the docker-compose file, there are a whole lot of sections and settings you can adjust. In order to have everything working optimally , make sure you've read and understood what each section does.

SSL certificates

Because the Print Manager is web based, a proper network connection is required. To make use of the latest security features, we've opted to use HTTPS with TLS1.3. This means we encrypt our network communication with SSL/TLS certificates. These certificates come in the form of an X.509 and need to be:

A most common free CA would be Let's Encrypt.

These certificates need to be provided in all the following formats for the Printmanager:

If one of the certificate formats is missing, please refer to the steps below to generate the specific format (Step 4 and Step 5 in particular).

If for some reason you cannot use online certificates, you can provide self-signed-certificates. While a self-signed certificate is not recommended, it can be useful for development purposes. Here are the steps to generate the required certificate files.

[!CAUTION] Self signed certificates should never be used in Production environments

Prerequisite: Certificates are generated using OpenSSL. This is usually already installed in Linux environments. For Windows it can be installed using

winget source update
winget install FireDaemon.OpenSSL

Step 1: Create an RSA key

openssl genrsa -out certificate.key 2048

Step 2: Create the Certificate Signing Request (CSR). When running this command, openssl asks for certain details. The Common Name and a Challenge Password are required. Remember this password, because it is needed in the next few steps but also needed in the docker-compose config!

openssl req -new -key certificate.key -out certificate.csr

Step 3: Create the Certificate in CRT format.

openssl x509 -req -days 365 -in certificate.csr -signkey certificate.key -out certificate.crt

Step 4: Create the Certificate in PFX format. This step requires the password from Step 2.

openssl pkcs12 -export -out certificate.pfx -inkey certificate.key -in certificate.crt

Step 5: Create the Certificate in PEM format. This step requires the password from Step 2, but also asks you to set a PEM passphrase. This pass phrase can be the same password as the one from step 2.

openssl pkcs12 -in certificate.pfx -out certificate.pem -clcerts

Finally, upload the certificate certificate.pem file into the volume mount of the SSL certificate. Default mapped volume is c:/temp/ssl.

Printmanager Server

Volumes

The Server needs to be able to save files, which can be achieved by mounting a volume. The following volumes are used by the application:

NameRequiredDescription
C:\Bergstein\Printmanager\Logs:/app/logsyesThis folder will contain the generated log files by the Printmanager
c:\Bergstein\Printmanager\FileData:/datayes, if FeatureFlags__FileModuleV1_PhysicalStorage is trueThis folder will contain the image data used by the Printmanager.
c:\ONYXThrive25\Input:/inputyes, if FeatureFlags__RasterizationModuleV1_OnyxRipUnc is trueThis folder is the input folder for Onyx. The Printmanager will place files that require rasterization in here.
c:\ISI_files:/isi_filesyes, if FeatureFlags__RasterizationModuleV1_OnyxRipUnc is trueThis folder is the output folder for Onyx. The Printmanager will read rasterized files from here and remove them when processed.
c:\Bergstein\Printmanager\SSL:/httpsyes, if FeatureFlags__HTTPS is trueThis folder contains the SSL certificates so the Printmanager can work securely.

Feature flags and environment variables

The functionality of the Server application can be expanded by enabling or disabling features with flags. The following feature flags can be enabled or disabled:

Feature nameDefault valueDescription
FeatureFlags__AuthenticationModuleV1trueEnable endpoint Authentication through the Authentication Module
FeatureFlags__AuthenticationModuleV1_InMemoryDatabasefalseUse an InMemoryDatabase for the Authentication Module (no data retention)
FeatureFlags__AuthenticationModuleV1_PostgresDatabasetrueUse Postgres for the Authentication Module
FeatureFlags__AuthenticationModuleV1_SeedEntitiesfalseFill the Authentication Module database with default values
FeatureFlags__FilesModuleV1trueEnable the File module
FeatureFlags__FilesModuleV1_InMemoryDatabasefalseUse an InMemoryDatabase for the File Module (no data retention)
FeatureFlags__FilesModuleV1_PostgresDatabasetrueUse Postgres for the File Module
FeatureFlags__FilesModuleV1_InMemoryStoragefalseUse memory storage for the File Module (no data retention)
FeatureFlags__FilesModuleV1_PhysicalStoragetrueUse physical storage for the File Module (the location is determined with the FileStorageOptions__BasePath environment variable)
FeatureFlags__FilesModuleV1_SeedEntitiesfalseFill the File Module database with default values
FileStorageOptions__BasePath/dataThe location where files are saved (Only used if FeatureFlags__FileModuleV1_PhysicalStorage is true) For persistence between restarts, this should link to a mounted volume
FeatureFlags__JobComposingModuleV1trueEnable the JobComposing module
FeatureFlags__JobComposingModuleV1_InMemoryDatabasefalseUse an InMemoryDatabase for the JobComposing Module (no data retention)
FeatureFlags__JobComposingModuleV1_PostgresDatabasetrueUse Postgres for the JobComposing Module
FeatureFlags__JobComposingModuleV1_SeedEntitiesfalseFill the JobComposing Module database with default values
FeatureFlags__PrinterGatewayModuleV1trueEnable the PrinterGateway module
FeatureFlags__PrinterGatewayModuleV1_InMemoryDatabasefalseUse an InMemoryDatabase for the PrinterGateway Module (no data retention)
FeatureFlags__PrinterGatewayModuleV1_PostgresDatabasetrueUse Postgres for the PrinterGateway Module
FeatureFlags__PrinterGatewayModuleV1_SeedEntitiesfalseFill the PrinterGateway Module database with default values
FeatureFlags__ApplicationModuleV1trueEnable the Application module
FeatureFlags__ApplicationModuleV1_InMemoryDatabasefalseUse an InMemoryDatabase for the Application module (no data retention)
FeatureFlags__ApplicationModuleV1_PostgresDatabasetrueUse Postgres for the Application Module
FeatureFlags__JobSchedulingModuleV1trueEnable the JobScheduling module
FeatureFlags__RasterizationModuleV1trueEnable the Rasterization module
FeatureFlags__RasterizationModuleV1_DigiRipfalseUse DigiRip to process images
FeatureFlags__RasterizationModuleV1_OnyxRiptrueUse OnyxRip to process images
FeatureFlags__RasterizationModuleV1_OnyxRipFtptrueUse FTP to send and receive images from Onyx
FeatureFlags__RasterizationModuleV1_OnyxRipUncfalseUse UNC to send and receive images from Onyx
FeatureFlags__DeveloperModefalseEnable developer mode. This exposes the gRPC transcoding service
FeatureFlags__DetailedLoggingfalseEnforce HTTPS communication with the application
FeatureFlags__HTTPStrueEnforce HTTPS communication with the application
FeatureFlags__ClamAvtrueUse ClamAv to check uploaded files for malicious content
FeatureFlags__NoAvfalseDisable antivirus scanning for uploaded files

Database connections

NameValueDescription
ConnectionStrings__ApplicationModuleV1_Database"Server=printmanagerdb; Port=5432; Database=application; Username=user; Password=<ChangeThisToAStrongPassword!>"The ConnectionString used by the Application module to connect to the database
ConnectionStrings__JobComposingModuleV1_Database"Server=printmanagerdb; Port=5432; Database=jobcompose; Username=user; Password=<ChangeThisToAStrongPassword!>"The ConnectionString used by the JobCompose module to connect to the database
ConnectionStrings__AuthenticationModuleV1_Database"Server=printmanagerdb; Port=5432; Database=authentication; Username=user; Password=<ChangeThisToAStrongPassword!>"The ConnectionString used by the Authentication module to connect to the database
ConnectionStrings__PrinterGatewayModuleV1_Database"Server=printmanagerdb; Port=5432; Database=printergateway; Username=user; Password=<ChangeThisToAStrongPassword!>"The ConnectionString used by the PrinterGateway module to connect to the database
ConnectionStrings__FilesModuleV1_Database"Server=printmanagerdb; Port=5432; Database=file; Username=user; Password=<ChangeThisToAStrongPassword!>"The ConnectionString used by the File module to connect to the database

Onyx Thrive options

When Onyx Thrive is used (FeatureFlags__RasterizationModuleV1_OnyxRip is true), some extra options have to be provided:

NameValueDescription
OnyxThriveOptions__InputFileType"PDF"Extension to be used for the input file type
OnyxThriveOptions__OutputFileType"ISI"Extension to be used for the output file type
OnyxThriveOptions__PrinterName"INX JetINX"Name of the printer configured in Onyx
OnyxThriveOptions__QuickSet"360_Level5"Name of the QuickSet configured in Onyx
OnyxThriveOptions__FileSuffix"-1"Name of the FileSuffix configured in Onyx
OnyxThriveOptions__RipTimeOutInSeconds30Time to wait before checking if Onyx has ripped a file
OnyxThriveOptions__RipFileHandleReleaseTimeInSeconds2Time to wait before reading the ripped file Onyx has created
OnyxThriveOptions__RipFileInputPath"input"Folder where input files can be placed for Onyx
OnyxThriveOptions__RipFileOutputPath"isi_files"Folder where Onyx places its output files
OnyxThrive FTP OptionsThese options are used when FeatureFlags__RasterizationModuleV1_OnyxRipFtp is true
OnyxThriveOptions__FtpOptions__ServerUrl"ftp://192.168.1.1"Server url for FTP
OnyxThriveOptions__FtpOptions__Port21Server port for FTP
OnyxThriveOptions__FtpOptions__UserName"user"Username to authenticate with FTP
OnyxThriveOptions__FtpOptions__Password"1234"Password to authenticate with FTP
OnyxThriveOptions__FtpOptions__AnonymousLoginfalseUse FTP without any authentication
OnyxThriveOptions__FtpOptions__UsePassivetrueUse a passive connection for FTP
OnyxThriveOptions__FtpOptions__KeepAlivefalseKeep the FTP connection alive
OnyxThriveOptions__FtpOptions__EnableSslfalseUse an FTPS connection
OnyxThrive UNC OptionsThese options are used when FeatureFlags__RasterizationModuleV1_OnyxRipUnc is true
OnyxThriveOptions__UncOptions__ServerUrl"/"The UNC path for Onyx when a network share is used

Digirip options

When Digirip is used (FeatureFlags__RasterizationModuleV1_DigiRip is true), some extra options have to be provided:

NameValueDescription
DigiRipOptions__VerticalDpi"360"Vertical DPI used for DigiRip
DigiRipOptions__HorizontalDpi"360"Horizontal DPI used for DigiRip
DigiRipOptions__PixelBitDepth8Bit Depth used per Pixel
DigiRipOptions__CompressOutputFiletrueEnable Compression on the Output File

Anti-Virus options

When Anti-Virus scanning is enabled (FeatureFlags__ClamAv is true), some extra options have to be provided:

NameValueDescription
AvOptions__ClamAvOptions__ServerAddress"clam_av"The IpAddress or hostname for ClamAv. Here the name of the ClamAv container is used
AvOptions__ClamAvOptions__Port3310The Port used for ClamAv

JWT Token options

JTW tokens are pieces of encrypted data that are send when you perform API interactions. They contain user and user accesses information.

When Authentication is enabled (FeatureFlags__AuthenticationModuleV1 is true), some extra options have to be provided:

NameValueDescription
JwtTokenOptions__IssuerlocalhostThe issuer of the token
JwtTokenOptions__AudienceBergsteinThe intended recipient of the token
JwtTokenOptions__Key<PLEASE_ENTER_128_RANDOM_CHARACTERS_HERE>The 128-bit Key used for Hash-based Message Authentication Code (HMAC)
JwtTokenOptions__AccessTokenExpirationInSeconds600The time in seconds before a token expires
GrpcClientOptions__Address"https://localhost:5001/"Connection url for intermodule communication. This should be localhost, since all Printmanager modules run in the same container.
GrpcClientOptions__UseSsltrueFlag to indicate whether to use SSL for intermodule communication.
GrpcClientOptions__AcceptInvalidSslCertificatefalseFlag to indicate whether to trust invalid certificates.
GrpcClientOptions__UseAuthenticationtrueFlag to indicate whether to use authentication for intermodule communication. This is required when FeatureFlags__AuthenticationModuleV1 is true
GrpcClientOptions__AuthenticationSchemeNameValueadminThe username used for intermodule communication
GrpcClientOptions__AuthenticationSchemeSecretValueCHANGEMEThe password used for intermodule communication

Logging options

For logging we use Serilog which has several output channels, called sinks, to which log data can be forwarded.

Default we output to Console (STDOUT) and File (a local rolling logfile somewhere on the system).

NameValueDescription
Serilog__Using__0Serilog.Sinks.ConsoleWrite logging to stdout
Serilog__Using__1Serilog.Sinks.FileWrite logging to a file
Serilog__MinimumLevel__DefaultInformationThe default logging level
Serilog__MinimumLevel__Override__MicrosoftWarningOverride for the default Microsoft logging
Serilog__MinimumLevel__Override__SystemWarningOverride for the default System logging
Serilog__Enrich__0FromLogContextAdditional enrichment parameter for logging
Serilog__Enrich__1WithMachineNameAdditional enrichment parameter for logging
Serilog__Enrich__2WithThreadIdAdditional enrichment parameter for logging
Serilog__WriteTo__0__NameConsoleName for the Console logging sink
Serilog__WriteTo__0__Args__outputTemplate[{Timestamp:HH:mm:ss} {Level:u3}] {Message:lj} {Properties:j}{NewLine}{Exception}Additional parameter for Console logging sink
Serilog__WriteTo__1__NameFileName for the File logging sink
Serilog__WriteTo__1__Args__path./logs/structured-log-.clefAdditional parameter for File logging sink
Serilog__WriteTo__1__Args__rollingIntervalDayAdditional parameter for File logging sink
Serilog__WriteTo__1__Args__fileSizeLimitBytes104857600Additional parameter for File logging sink
Serilog__WriteTo__1__Args__rollOnFileSizeLimittrueAdditional parameter for File logging sink

Other Environment variables

NameValueDescription
ServerOptions__AllowedOrigins__0"*"Allowed Hosts to connect to the application
ServerOptions__HttpsRedirectionPort5001Redirection port for upgrading an HTTP connection to HTTPS
ServerOptions__RedirectToHttpstrueBoolean to enable / disable the redirection of HTTP traffic to HTTPS
ServerOptions__Kestrel__Limits__MaxRequestBodySize27018864The max request size of an HTTP(S) request in bytes (Default is ~27MB)
AllowedHosts"*"Allowed Hosts to connect to the application
Kestrel__Endpoints__Grpc-Web__Urlhttp://*:5000Instructions for Kestrel to listen on this port
Kestrel__Endpoints__Grpc-Web__ProtocolsHttp1AndHttp2Instructions for Kestrel to use these HTTP protocol versions
Kestrel__Endpoints__Http1__Urlhttp://*:5002Instructions for Kestrel to listen on this port
Kestrel__Endpoints__Http1__ProtocolsHttp1Instructions for Kestrel to use these HTTP protocol versions
Kestrel__Endpoints__Grpc__Urlhttp://*:5004Instructions for Kestrel to listen on this port
Kestrel__Endpoints__Http1__ProtocolsHttp2Instructions for Kestrel to use these HTTP protocol versions
Kestrel__Endpoints__Https1__Urlhttps://*:5001Instructions for Kestrel to listen on this port
Kestrel__Endpoints__Https1__ProtocolsHttp2Instructions for Kestrel to use these HTTP protocol versions

Ports

The following ports are exposed for the Server application:

PortUsageProtocol
5000Grpc-WebHttp1AndHttp2
5002Http1Http1
5004GrpcHttp2
5001Https1Http2

Printmanager Client

Volumes

The Client needs a volume where the SSL files are stored. Note: Nginx is currently hardcoded to use the files certificate.crt and certificate.key. Please rename the certificate files to these specific names to ensure proper functioning.

NameRequiredDescription
c:\Bergstein\Printmanager\SSL:/etc/ssl:royes, if FeatureFlags__HTTPS is trueThis folder contains the SSL certificates so the Printmanager can work securely.

Environment variables

The Client application requires a few environment variables as default values to work properly:

NameDefault valueDescription
GrpcClientOptions__Addresshttps://server.localhost:5001The external url of the Server application.
GrpcClientOptions__UseSsltrueFlag to indicate whether to use SSL to connect to the Server application.
GrpcClientOptions__AcceptInvalidSslCertificatefalseFlag to indicate whether to trust invalid certificates.
GrpcClientOptions__UseAuthenticationtrueFlag to indicate whether to use Authentication while connecting to the Server application.

Ports

Ports 80 and 443 are exposed for Nginx.

ClamAv

The ClamAv container is used to scan uploaded files for malware. This container doesn't require any further configuration.

Ports

ClamAv runs internally on port 3310

Postgres database

The Postgres database is used to store all the data configured in the Printmanager system.

Volumes

The database has to be persistent, which can be achieved by mounting a volume. There are 2 volume mounts we use to setup the database:

NameRequiredDescription
c:\Bergstein\Printmanager\Postgres\postgres-data:/var/lib/postgresqlyesThis folder contains all the database data. It is recommended to create automated backups of this folder.
c:\Bergstein\Printmanager\Postgres\Init:/docker-entrypoint-initdb.dyesThis folder contains the setup sql queries to create the databases

Init file

The following script tells Postgres how to initialize the databases and should be mounted as a volume inside the /docker-entrypoint-initdb.d folder with the filename 01-init.sh.

#!/usr/bin/env sh
set -e

# || true is used to continue on error
createdb --username=$POSTGRES_USER --owner=$POSTGRES_USER jobcompose || true
createdb --username=$POSTGRES_USER --owner=$POSTGRES_USER authentication || true
createdb --username=$POSTGRES_USER --owner=$POSTGRES_USER printergateway || true
createdb --username=$POSTGRES_USER --owner=$POSTGRES_USER file || true
createdb --username=$POSTGRES_USER --owner=$POSTGRES_USER application || true

Environment variables

The Postgres database container has the following required environment variables:

"POSTGRES_USER": "user"
"PGUSER": "user"
"POSTGRES_PASSWORD": "<ChangeThisToAStrongPassword!>"
"POSTGRES_DB": "user"

Ports

Postgres runs internally on port 5432

Traefik

The traefik container is used as a reverse proxy for the Printmanager system and routes specific domain names to the proper docker containers.

Volumes

Treafik uses configuration files to setup the routing functionality for the reverse proxy. These files are mounted with the following volumes

NameDescription
c:\Bergstein\Printmanager\Traefik\Config\traefik.yml:/etc/traefik/traefik.ymlThis file contains the main configuration for Traefik.
c:\Bergstein\Printmanager\Traefik\Config\DynamicDev:/etc/traefik/dynamic/This folder contains the specific configuration for Traefik with all the endpoints for the Printmanager.
c:\Bergstein\Printmanager\SSL:/etc/traefik/certs:roThis folder contains the SSL certificates so the Printmanager can work securely.

Traefik config file

The main configuration for traefik is:

entryPoints:
  web:
    address: ":80"
    http:
      redirections:
        entryPoint:
          to: websecure
          scheme: https
  websecure:
    address: ":443"
providers:
  file:
    directory: "/etc/traefik/dynamic"
api:
  insecure: true
  dashboard: true
serversTransport:
  insecureSkipVerify: true
ping: {}
log:
  level: DEBUG

Printmanager config file

The specific configuration file for the Printmanager is given below. The Host urls should be adjusted to reflect a domain instead of localhost.

http:
  routers:
    traefik:
      rule: "Host(`traefik.localhost`)"
      service: traefik
      entryPoints:
        - websecure
      tls: {}
    client:
      rule: "Host(`client.localhost`)"
      service: client
      entryPoints:
        - websecure
      tls: {}
    server:
      service: server
      rule: "Host(`server.localhost`)"
      entryPoints:
        - websecure
      middlewares:
        - corsheaders
      tls: {}
    grpcui:
      service: grpcui
      rule: "Host(`grpcui.server.localhost`)"
      entryPoints:
        - websecure
      tls: {}
    adminer:
      service: adminer
      rule: "Host(`adminer.localhost`)"
      entryPoints:
        - websecure
      tls: {}
    swagger:
      service: swagger
      rule: "Host(`swagger.server.localhost`)"
      entryPoints:
        - websecure
      tls: {}

  middlewares:
    corsheaders:
      headers:
        accessControlAllowMethods:
          - Get
          - Options
          - Post
          - Put
          - Delete
        accessControlAllowHeaders: "*"
        accessControlAllowCredentials: true
        accessControlAllowOriginList:
          - https://swagger.server.localhost
          - https://server.localhost

  services:
    traefik:
      loadBalancer:
        servers:
          - url: "http://traefik:8080"
    client:
      loadBalancer:
        servers:
          - url: "https://printmanagerclient:443"
    server:
      loadBalancer:
        servers:
          - url: "https://printmanagerserver:5001"
    grpcui:
      loadBalancer:
        servers:
          - url: "http://grpc_ui:8080"
    swagger:
      loadBalancer:
        servers:
          - url: "http://swagger_ui:8080"
    adminer:
      loadBalancer:
        servers:
          - url: "http://adminer:8080"
tls:
  stores:
    default:
      defaultCertificate:
        certFile: /etc/traefik/certs/certificate.crt
        keyFile: /etc/traefik/certs/certificate.key
  certificates:
    - certFile: /etc/traefik/certs/certificate.crt
      keyFile: /etc/traefik/certs/certificate.key

Ports

Traefik uses port 80 and 443 and these have to be externally available.

Notes and limitations

Support

If at anypoint you have question and/or remarks, please contact us via support@bergstein.nl! +++ title = "Print Manager: Installation & Getting Started" description = "Guide for installing the Print Manager and getting started." +++

Print Manager Technical Guide

Thank you for using the Bergstein DIGI Print Manager!

In this document the following technical technical details are explained;

Intro

The Print Manager is an application suite of up to 5 virtualized container applications:

The Print Manager Server application is the central hub for all Print Manager interactions. Depending on enabled features, it can process uploaded files, like PDF images, scan files for malware and use the files to create custom print jobs for (Bergstein DIGI) printers.

The Print Manager Client application is a web app, which allows users to interface with the Print Manager Server.

Postgres is the database server and is used to store the data generated by the Server application.

ClamAv is used to scan files for Malware.

Traefik is the load balancer for all the applications and provides FQDN registration and SSL certificate renewal.

The containers are OCI and can be run with Docker or Podman. All container images are built on Linux kernel, if your target host device is Windows you can use WSL to allow running of (Linux) images in Docker on Windows.

Besides these 5 main containers, there are also a handful of helper containers to make maintainability easier:

Requirements

Before installation, please make sure the target device which will host the Print Manager has the required (hardware) capabilities.

To ensure optimal performance and compatibility, use the following system requirements as a guideline for a Print Manager system with 5 printers with a default workload of 10 unique jobs per minute concurrently.

The following specifications are indicative and may vary depending on the amount of printers and actual (print) workload.

For higher printer count and or print workload see the 'Hardware Scaling' section.

'* depends on usage'

1. Hardware Requirements

2. Software Requirements

3. Network & Connectivity

Ensure that the following network connectivity is allowed on the target network.

Ports and protocol standards can be altered via specific environment variables when running the application containers.

The following are default values.

Installation

To install the Print Manager on the target device please follow the next steps;

1) Fetch the (latest) container images

The majority of container images are available on our Azure cloud hosted container registry. To access it you should first request ACR login credentials at support@bergstein.nl.

To login you need to instal the AZ_CLI in your console/terminal. See the Microsoft AZ CLI page: https://github.com/Azure/azure-cli .

After you've received the credentials, you can perform the following command in your console/terminal:

az login --service-principal --username <APP_ID> --password <CLIENT_SECRET> --tenant <TENANT_ID> && az acr login --name bgppregistryprintmanager

Now you should be logged in and able to fetch docker images. The convention is always the same: <REGISTRY_NAME>/<IMAGE_NAME>: Our registry name is bgppregistryprintmanager.azurecr.io.

So for example you should be able to get the latest Print Manager Server by doing:

docker pull bgppregistryprintmanager.azurecr.io/printmanager_server:latest

Or use a specific version like 1.8.0.0:

docker pull bgppregistryprintmanager.azurecr.io/printmanager_server:1.8.0.0

This is the list of available images:

2) Orchestration & deployment

As stated before, the Print Manager consists of several application images. To avoid pulling each individual container and manually configuring them, we've opted to use an orchestration tool like Docker-Compose, however you can also use tools like Kubernetes or the Podman-Compose.

We will provide you with an example Docker-Compose file which you can use as an initial setup. Just copy the following data into a docker-compose.yaml file and run it with command; docker-compose build and then docker-compose up -d .

services:
  PrintManagerServer:
    image: bgppregistryprintmanager.azurecr.io/printmanager_server:1.8.0.0
    container_name: printmanagerserver
    networks:
      - printmanager
    restart: unless-stopped
    depends_on:
      PrintManagerDb:
        condition: service_healthy
    volumes:
      - c:\ONYXThrive25\Input:/onyx_input
      - c:\ISI_files:/onyx_isi_files
      - c:\Bergstein\Printmanager\SSL:/https:ro
      - c:\Bergstein\Printmanager\FileData:/data
      - C:\Bergstein\Printmanager\Logs:/app/logs/
    environment:
      "ASPNETCORE_ENVIRONMENT": "Development"
      "ASPNETCORE_HTTP_PORTS": "5000,5002,5004"
      "ASPNETCORE_HTTPS_PORTS": "5001"
      "ConnectionStrings__ApplicationModuleV1_Database": "Server=printmanagerdb; Port=5432; Database=application; Username=user; Password=<ChangeThisToAStrongPassword!>"
      "ConnectionStrings__JobComposingModuleV1_Database": "Server=printmanagerdb; Port=5432; Database=jobcompose; Username=user; Password=<ChangeThisToAStrongPassword!>"
      "ConnectionStrings__AuthenticationModuleV1_Database": "Server=printmanagerdb; Port=5432; Database=authentication; Username=user; Password=<ChangeThisToAStrongPassword!>"
      "ConnectionStrings__PrinterGatewayModuleV1_Database": "Server=printmanagerdb; Port=5432; Database=printergateway; Username=user; Password=<ChangeThisToAStrongPassword!>"
      "ConnectionStrings__FilesModuleV1_Database": "Server=printmanagerdb; Port=5432; Database=file; Username=user; Password=<ChangeThisToAStrongPassword!>"
      "Serilog__Using__0": "Serilog.Sinks.Console"
      "Serilog__Using__1": "Serilog.Sinks.File"
      "Serilog__MinimumLevel__Default": "Information"
      "Serilog__MinimumLevel__Override__Microsoft": "Warning"
      "Serilog__MinimumLevel__Override__System": "Warning"
      "Serilog__Enrich__0": "FromLogContext"
      "Serilog__Enrich__1": "WithMachineName"
      "Serilog__Enrich__2": "WithThreadId"
      "Serilog__WriteTo__0__Name": "Console"
      "Serilog__WriteTo__0__Args__outputTemplate": "[{Timestamp:HH:mm:ss} {Level:u3}] {Message:lj} {Properties:j}{NewLine}{Exception}"
      "Serilog__WriteTo__1__Name": "File"
      "Serilog__WriteTo__1__Args__path": "./logs/structured-log-.clef"
      "Serilog__WriteTo__1__Args__rollingInterval": "Day"
      "Serilog__WriteTo__1__Args__fileSizeLimitBytes": 104857600
      "Serilog__WriteTo__1__Args__rollOnFileSizeLimit": true
      "OnyxThriveOptions__FtpOptions__ServerUrl": "ftp://MY_ONYX_PC"
      "OnyxThriveOptions__FtpOptions__Port": 21
      "OnyxThriveOptions__FtpOptions__UserName": ""
      "OnyxThriveOptions__FtpOptions__Password": ""
      "OnyxThriveOptions__FtpOptions__AnonymousLogin": false
      "OnyxThriveOptions__FtpOptions__UsePassive": true
      "OnyxThriveOptions__FtpOptions__KeepAlive": false
      "OnyxThriveOptions__FtpOptions__EnableSsl": false
      "OnyxThriveOptions__UncOptions__ServerUrl": "/"
      "OnyxThriveOptions__PrinterName": "INX JetINX"
      "OnyxThriveOptions__QuickSet": "MY_QUICKSET"
      "AvOptions__ClamAvOptions__ServerAddress": "clam_av"
      "AvOptions__ClamAvOptions__Port": 3310
      "JwtTokenOptions__Issuer": "localhost"
      "JwtTokenOptions__Audience": "Bergstein"
      "JwtTokenOptions__Key": "<PLEASE_ENTER_128_RANDOM_CHARACTERS_HERE>"
      "GrpcClientOptions__Address": "https://localhost:5001/"
      "GrpcClientOptions__UseSsl": true
      "GrpcClientOptions__AcceptInvalidSslCertificate": true
      "GrpcClientOptions__UseAuthentication": true
      "GrpcClientOptions__AuthenticationSchemeNameValue": "Admin"
      "GrpcClientOptions__AuthenticationSchemeSecretValue": "B3rgst3!n"
      "FeatureFlags__DeveloperMode": true
      "FeatureFlags__DetailedLogging": true
      "FeatureFlags__HTTPS" : true
      "FeatureFlags__AuthenticationModuleV1" : true
      "FeatureFlags__AuthenticationModuleV1_InMemoryDatabase" : false
      "FeatureFlags__AuthenticationModuleV1_PostgresDatabase" : true
      "FeatureFlags__AuthenticationModuleV1_SeedEntities" : true
      "FeatureFlags__FilesModuleV1": true
      "FeatureFlags__FilesModuleV1_InMemoryDatabase": false
      "FeatureFlags__FilesModuleV1_PostgresDatabase": true
      "FeatureFlags__FilesModuleV1_InMemoryStorage": false
      "FeatureFlags__FilesModuleV1_PhysicalStorage": true
      "FeatureFlags__FilesModuleV1_SeedEntities": false
      "FeatureFlags__JobComposingModuleV1": true
      "FeatureFlags__JobComposingModuleV1_DigiRip" : false
      "FeatureFlags__JobComposingModuleV1_OnyxRip" : true
      "FeatureFlags__JobComposingModuleV1_InMemoryDatabase" : false
      "FeatureFlags__JobComposingModuleV1_PostgresDatabase" : true
      "FeatureFlags__JobComposingModuleV1_SeedEntities" : false
      "FeatureFlags__PrinterGatewayModuleV1" : true
      "FeatureFlags__PrinterGatewayModuleV1_InMemoryDatabase" : false
      "FeatureFlags__PrinterGatewayModuleV1_PostgresDatabase" : true
      "FeatureFlags__PrinterGatewayModuleV1_SeedEntities" : false
      "FeatureFlags__ApplicationModuleV1": true
      "FeatureFlags__ApplicationModuleV1_InMemoryDatabase": false
      "FeatureFlags__ApplicationModuleV1_PostgresDatabase": true
      "FeatureFlags__JobSchedulingModuleV1" : true
      "FeatureFlags__RasterizationModuleV1" : true
      "FeatureFlags__RasterizationModuleV1_DigiRip" : false
      "FeatureFlags__RasterizationModuleV1_OnyxRip" : true
      "FeatureFlags__RasterizationModuleV1_OnyxRipFtp" : false
      "FeatureFlags__RasterizationModuleV1_OnyxRipUnc" : true
      "FeatureFlags__ClamAv" : true
      "FeatureFlags__NoAv" : false
      "ASPNETCORE_Kestrel__Certificates__Default__Path": "/https/certificate.pfx"
      "ASPNETCORE_Kestrel__Certificates__Default__Password": "<CERTIFICATE_PASSWORD>"
  PrintManagerClient:
    image: bgppregistryprintmanager.azurecr.io/printmanager_client:1.8.0.0
    container_name: printmanagerclient
    networks:
      - printmanager
    restart: unless-stopped
    environment:
      "GrpcClientOptions__Address": "https://server.localhost"
      "GrpcClientOptions__UseSsl" : true
      "GrpcClientOptions__AcceptInvalidSslCertificate": true
      "GrpcClientOptions__UseAuthentication" : true
      "ASPNETCORE_HTTP_PORTS": "7000"
      "ASPNETCORE_HTTPS_PORTS": "7001"
      "ASPNETCORE_ENVIRONMENT": "Development"
    volumes:
      - c:\Bergstein\Printmanager\SSL:/etc/ssl:ro
  Traefik:
    image: traefik:v3.3.3
    container_name: traefik
    ports:
      - 80:80
      - 443:443
    restart: unless-stopped
    networks:
      - printmanager
    volumes:
      - c:\Bergstein\Printmanager\Traefik\Config\traefik.yml:/etc/traefik/traefik.yml
      - c:\Bergstein\Printmanager\Traefik\Config\DynamicDev\:/etc/traefik/dynamic/
      - c:\Bergstein\Printmanager\SSL\:/etc/traefik/certs:ro
  ClamAv:
    image: clamav/clamav:1.0.7
    container_name: clam_av
    networks:
      - printmanager
    restart: unless-stopped
  PrintManagerDb:
    image: postgres:18-alpine
    container_name: printmanagerdb

Back to documents