(Answers required) Advanced Guide: Deploying via .NET Binaries (Multi Instance)

This guide explains how to install and deploy the Nextcloud Exchange Connector application using Binary files (.NET 8).

While Docker is the recommended deployment method for most users, binary installations are specifically supported for advanced use cases, such as air-gapped networks, closed environments, or organizations with strict security policies that prohibit the use of containerization.

Pre-requirements

Before deploying the application, ensure the following dependencies are ready and reachable by the connector:

  1. The Nextcloud service account details are available (Configuring Nextcloud)

  2. The Exchange service account or app registration details are configured (Configuring Exchange - TO ADD LINK TO SUBCATEGORIES)

  3. A supported database is available and reachable from the application

Which databases are supported?
  1. The latest version of .NET Runtime 8.0 is installed on your machine (Official .NET 8.0 download page)

  2. For Linux deployments connecting to Exchange On-Premise via Kerberos, ensure the libgssapi-krb5-2 package is installed.

How to install libgssapi-krb5-2?

Use the following command:

sudo apt install libgssapi-krb5-2
  1. You have downloaded the ZIP file containing the Nextcloud Exchange Connector release.

Step 1. Verify .NET installation

Run the following command in your terminal to check if .NET 8 is installed:

dotnet --version

The output should show a version starting with 8.0.

Note:

Step 2. Extract the application files

Unlike Docker deployments that automatically scale via replicas, a binary application cannot auto-scale itself. To achieve a multi-instance setup, you must physically create independent directories for each instance process.

Extract the downloaded ZIP archive into dedicated folders for each instance you plan to run.

For a multi-instance setup:

/usr/sendent-sync/worker-1/
/usr/sendent-sync/worker-2/
/usr/sendent-sync/worker-3/

Note: Use a separate folder for each instance. The number of workers depends on your scaling and throughput needs.

How do I know how many instances I need? - to ask Luc to provide answer

Step 3. Prepare the configuration file (.env)

Why this is needed: The application requires credentials, connection strings, and synchronization rules to communicate with Nextcloud, Exchange, and your database.

Place the environment configuration file directly in the root of each worker's directory.

Warning: Strict File Naming

The environment file must be named exactly “.env” (an empty filename with a .env extension).

Naming the file settings.env will cause the application to fail to read the configuration.

Warning: Shared Secret Mismatch

Your Service__NextcloudConfiguration__SharedSecret value must perfectly match the shared secret configured inside the Sendent Sync app within your Nextcloud web interface.

Below is an example of the .env file tailored for a binary deployment:

# Service Configuration
Service__IsPrimary=true
# Deployment Types: Docker(0), Binary(1)
Service__DeploymentType=1
Service__AspNetCoreUrl="http://localhost:5001"
Service__DefaultWorkerName="SendentWorker-1"
Service__BatchLimit=50
Service__WorkerIntervalSeconds=60
Service__SyncIntervalInSeconds=60
Service__CriticalSyncIntervalInSeconds=100
Service__BatchSaveSize=100
Service__StartWeekend=6
# Synchronization Modes: None(0), Calendars(1), Contacts(2), Tasks(4)
# You can combine modes, just place sum of necessary numbers in this property
Service__SyncMode=1
# Synchronization Types: Full(0), Sensitive(1)
Service__SyncType=0
 
# Database Configuration
# Allowed Database types: Postgres(0), SqlServer(1), MariaDB(2), MySql(3)
DatabaseConfiguration__DatabaseType=2
DatabaseConfiguration__DatabaseEncryptionKey=YourSuperSecretKey123!
DatabaseConfiguration__ConnectionString=Server=localhost;Port=3306;Database=SendentDB;Uid=root;Pwd=YourStrong!Pass123
 
# Postgres Example: Host=localhost;Port=5432;Database=SendentDB;Username=postgres;Password=YourStrong!Pass123
# SqlServer Example: Server=localhost;Database=SendentDB;User Id=sa;Password=YourStrong!Pass123;Encrypt=False;
# MariaDB Example: Server=localhost;Port=3306;Database=SendentDB;Uid=root;Pwd=YourStrong!Pass123
# MySql Example: Server=localhost;Port=3306;Database=SendentDB;Uid=root;Pwd=YourStrong!Pass123
 
# Nextcloud Configuration
Service__NextcloudConfiguration__NextcloudBaseUrl=your-nextcloud-base-url
Service__NextcloudConfiguration__NextcloudServiceUsername=your-nextcloud-admin
Service__NextcloudConfiguration__NextcloudServicePassword=your-nextcloud-password
Service__NextcloudConfiguration__SharedSecret=your-shared-secret
 
# Exchange Configuration
# Allowed Exchange Types: Cloud(1), OnPremKerberos(2), OnPremBasicAuth(3), OnPremADFS(4)
Service__ExchangeConfiguration__ExchangeType=1
Service__ExchangeConfiguration__ExchangeOnPremUrl=your-exchange-on-prem-url
Service__ExchangeConfiguration__ExchangeOnPremDomain=your-domain
Service__ExchangeConfiguration__ExchangeOnPremAdfsAuthorityUrl=your-adfs-authority-url
Service__ExchangeConfiguration__ExchangeTenantId=yor-exchange-tenant-id
 
# Admin credentials - use a JSON file (recommended) or inline JSON
# File path to admin credentials JSON (e.g., /app/settings/admins.json). See Demo files/admins.json.example
Service__ExchangeConfiguration__ExchangeAdminFile=
# Inline JSON fallback (used when ExchangeAdminFile is not set)
# Cloud Example: "[{\"AppId\":\"AppId1\", \"ClientSecret\":\"Secret1\"}, {\"AppId\":\"AppId2\", \"ClientSecret\":\"Secret2\"}]"
# OnPrem(Kerberos/BasicAuth) Example: "[{\"User\":\"Admin1\", \"Pass\":\"Password1\"}, {\"User\":\"Admin2\", \"Pass\":\"Password2\"}]"
# OnPremADFS Example: "[{\"ClientId\":\"ClientId1\", \"ClientSecret\":\"Secret1\"}, {\"ClientId\":\"ClientId2\", \"ClientSecret\":\"Secret2\"}]"
Service__ExchangeConfiguration__ExchangeAdminRaw="[{}]"
 
# Concurrency Configuration
Service__ConcurrencyConfiguration__MaxParallelProcessingUsers=1000
Service__ConcurrencyConfiguration__MaxUsersPerAdmin=100
 
# Full Synchronization Configuration
Service__FullSyncConfiguration__ProcessAttachments=true
 
# Sensitive Synchronization Configuration
Service__SensitiveSyncConfiguration__SensitiveTitle="Busy"
Service__SensitiveSyncConfiguration__SensitiveCategory="Nextcloud Sync"
 
# Logging (Serilog)
# Change global Log level: Information, Debug
Serilog__MinimumLevel__Default=Information
#Change Logs output: None(0), Console(1), Database(2), File(4), Grafana(8)
# You can combine outputs, just place sum of necessary numbers in this property
Service__LoggingConfiguration__LogsOutput=3
Service__LoggingConfiguration__LogDirectoryPath=
# For Limiting log's file size in MB
Service__LoggingConfiguration__LogFileSizeLimit=50
# For Limiting amount of log files
Service__LoggingConfiguration__LogFileAmountLimit=20

To understand the meaning of each parameter in .env refer to Configuring the .env File.

Step 4. Configure binary-specific instance values

Why this is needed: To prevent network port conflicts between running instances and to designate exactly one node as the primary synchronization coordinator.

You must edit the bottom three variables in the .env file for each instance directory. All other settings (database, Exchange, Nextcloud) should remain identical across all your worker folders.

Property

Requirement

Service__IsPrimary

Exactly one instance (e.g., worker-1) must be set to true. All other instances must be set to false.

Service__AspNetCoreUrl

You must assign a different port for each instance (e.g., http://localhost:5001, http://localhost:5002).

Service__DefaultWorkerName

Must be a unique identifier per instance (e.g., SendentWorker-1, SendentWorker-2).

Step 5. Set up Exchange Credentials (admins.json)

Why this is needed: Securely passing credentials to the application. In a multi-instance setup, providing multiple service accounts distributes the synchronization load and prevents Microsoft Exchange from throttling your connections.

Inside each worker directory (or in a shared accessible path), create a folder named exchangeAdmins and place your admins.json file inside it. Ensure your .env file points to this location via the Service__ExchangeConfiguration__ExchangeAdminFile parameter.

Warning: Avoid Raw Exchange Credentials

Do not configure Exchange credentials directly in the .env file via the Service__ExchangeConfiguration__ExchangeAdminRaw parameter.

Escaping quotes and slashes in this string breaks the parser. Always use the admins.json file.

Warning: Do Not Mix Exchange Types

Do not mix different Exchange connection types (e.g., Cloud and On-Premise) in a single admins.json file. The "ExchangeType" field inside the JSON file acts merely as a visual comment. The actual active connection type is dictated strictly by the Service__ExchangeConfiguration__ExchangeType parameter in your .env file.

An example of the correct admins.json :

[
{
"AppId": "your-app-id-1",
"ClientSecret": "your-client-secret-1"
},
{
"AppId": "your-app-id-2",
"ClientSecret": "your-client-secret-2"
}
]

Step 6. Start the application

Why this is needed: To execute the synchronization processes for each isolated worker.

Warning: Execution Context

You must open your terminal or command prompt specifically inside the target worker's directory before executing the start command. This ensures the application reads the correct local .env file.

Run the following command in each instance directory separately:

cd /usr/sendent-sync/worker-1/
dotnet Sendent.Synchronisation.Service.dll

Repeat this process for /worker-2/, /worker-3/, etc.

Step 7. Configure Logging

Use the Service__LoggingConfiguration__LogsOutput setting to control where logs are written. You can combine values by summing them up (e.g., 1 for Console + 4 for File System = 5).

File System Logging (Recommended for Binaries)

If you set your output to include the file system (4 or 5), the application will automatically generate a dedicated logs folder (e.g., SendentLogs) within the root directory of each worker instance.

You can configure automatic log rotation and cleanup using these parameters:

  • Service__LoggingConfiguration__LogFileSizeLimit=50: The maximum size of a single log file (in MB) before a new file is created.

  • Service__LoggingConfiguration__LogFileAmountLimit=20: The maximum number of log files retained per instance. Older files are automatically deleted to save disk space.

Next Step

Logging & Monitoring


Was this article helpful?