(Answer required) Quick Start: Deploying via Docker (Single Instance)
This guide explains how to install and deploy the Nextcloud Exchange Connector in a Single-instance architecture using Docker.
Docker is the officially recommended deployment method and is currently used by 95% of Sendent customers.
Pre-requirements
Before deploying the application, ensure the following dependencies are ready and reachable by the connector:
The Nextcloud service account details are available (Configuring Nextcloud)
The Exchange service account or app registration details are configured (Configuring Exchange - TO ADD LINK TO SUBCATEGORIES)
A supported database is available and reachable from the application
Which databases are supported?
PostgreSQL (PostgreSQL official installation guide)
Microsoft SQL Server (Microsoft SQL Server official installation guide)
MariaDB (MariaDB official installation guide)
Docker is installed on your host machine (Docker official installation guide)
Step 1. Prepare the Deployment Files
Extract the ready-to-use deployment files from the ZIP archive provided by Sendent. - to ask Luc to advise on how the User will get the necessary files
You do not need to alter the docker-compose.yml file.
All necessary configurations are managed entirely through environment variables (.env file).
The provided configuration will automatically pull the latest official container image from the public repository: rg.nl-ams.scw.cloud/sendent-public/sendent-sync:latest
Step 2. Configure the Environment Variables (.env)
Why this is needed: The application requires credentials and connection strings to communicate with Nextcloud, Exchange, and your database.
At a minimum, valid values should be provided for:
Service Configuration
Database Configuration
Nextcloud Configuration
Exchange Configuration
Exchange Administrator Credentials
Create the .env file by copy-pasting the following code in the same directory as your Docker compose files:
# Service ConfigurationService__StartWeekend=6# Synchronization Modes: None(0), Calendars(1), Contacts(2), Tasks(4)# You can combine modes, just place sum of necessary numbers in this propertyService__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=2DatabaseConfiguration__DatabaseEncryptionKey=YourSuperSecretKey123!DatabaseConfiguration__ConnectionString=Server=maria_db;Port=3306;Database=SendentDB;Uid=root;Pwd=YourStrong!Pass123 # Postgres Example: Host=postgres_db;Port=5432;Database=SendentDB;Username=postgres;Password=YourStrong!Pass123# SqlServer Example: Server=mssql_db;Database=SendentDB;User Id=sa;Password=YourStrong!Pass123;Encrypt=False;# MariaDB Example: Server=maria_db;Port=3306;Database=SendentDB;Uid=root;Pwd=YourStrong!Pass123# MySql Example: Server=mysql_db;Port=3306;Database=SendentDB;Uid=root;Pwd=YourStrong!Pass123 # Nextcloud ConfigurationService__NextcloudConfiguration__NextcloudBaseUrl=your-nextcloud-base-urlService__NextcloudConfiguration__NextcloudServiceUsername=your-nextcloud-adminService__NextcloudConfiguration__NextcloudServicePassword=your-nextcloud-passwordService__NextcloudConfiguration__SharedSecret=your-shared-secret # Exchange Configuration# Allowed Exchange Types: Cloud(1), OnPremKerberos(2), OnPremBasicAuth(3), OnPremADFS(4)Service__ExchangeConfiguration__ExchangeType=1Service__ExchangeConfiguration__ExchangeOnPremUrl=https://outlook.office365.com/EWS/Exchange.asmxService__ExchangeConfiguration__ExchangeOnPremDomain=your-domainService__ExchangeConfiguration__ExchangeOnPremAdfsAuthorityUrl=your-adfs-authority-urlService__ExchangeConfiguration__ExchangeTenantId=yor-exchange-tenant-id # Fill in your administrator's credentials in the property below using necessary template for filling in# Cloud: "[{\"AppId\":\"AppId1\", \"ClientSecret\":\"Secret1\"}, {\"AppId\":\"AppId1\", \"ClientSecret\":\"Secret1\"}]"# OnPrem(Kerberos/BasicAuth): "[{\"User\":\"Admin1\", \"Pass\":\"Password1\"}, {\"User\":\"Admin2\", \"Pass\":\"Password2\"}]"# OnPremADFS: "[{\"ClientId\":\"ClientId1\", \"ClientSecret\":\"Secret1\" }, {\"ClientId\":\"ClientId2\", \"ClientSecret\":\"Secret2\"}]"# or configure and use json files# Default: simple file admins.json in exchangeAdmins folder# Custom Example:# Service__ExchangeConfiguration__ExchangeAdminFile=administrators/myAdmins/myAdmin.json # Service__ExchangeConfiguration__ExchangeAdminRaw="[{\"AppId\":\"your-app-id\", \"ClientSecret\":\"your-client-Secret\"}]"# Service__ExchangeConfiguration__ExchangeAdminFile=# Service__ExchangeConfiguration__ExchangeAdminRaw=# Service__ExchangeConfiguration__ExchangeAdminFile=administrators/myAdmins/myAdmin.jsonService__ExchangeConfiguration__ExchangeAdminRaw=Service__ExchangeConfiguration__ExchangeAdminFile= # Full Synchronization ConfigurationService__FullSyncConfiguration__ProcessAttachments=true # Sensitive Synchronization ConfigurationService__SensitiveSyncConfiguration__SensitiveTitle="Busy"Service__SensitiveSyncConfiguration__SensitiveCategory="Nextcloud Sync" # Logging (Serilog & Loki)# Change global Log level: Information, DebugSerilog__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 propertyService__LoggingConfiguration__LogsOutput=3Service__LoggingConfiguration__LogDirectoryPath=# For Limiting log's file size in MBService__LoggingConfiguration__LogFileSizeLimit=50# For Limiting amount of log filesService__LoggingConfiguration__LogFileAmountLimit=20Service__LoggingConfiguration__LokiInternalUrl=http://loki:3100 # Grafana ConfigurationGRAFANA_USER="YourAdminLogin"GRAFANA_PASSWORD="YourAdminPassword"
To understand the meaning of each parameter in .env file, refer to the Configuring the .env File.
Warning: Escaping Special Characters in Docker
When configuring passwords, connection strings, or secrets in your .env file, be aware of Docker's character constraints. Specifically, the dollar sign $) is reserved for variable interpolation. If your actual password contains a literal $, you must escape it by doubling the character (e.g., a password of Pa$word must be written as Pa$$word in the .env file).
Failure to escape this will cause Docker to drop the character, resulting in severe authentication errors.
Warning: Shared Secret Mismatch
Your Service__NextcloudConfiguration__SharedSecret value must exactly match the shared secret configured in the Sendent Sync app within your Nextcloud web interface.
Warning: Strict File Naming
The environment file must be named exactly .env with no prefix. Naming the file like settings.env will cause Docker to fail to read the configuration.
Warning: Avoid Raw Exchange Credentials
We highly discourage configuring Exchange credentials directly in the .env file via the Service__ExchangeConfiguration__ExchangeAdminRaw parameter. Escaping quotes and slashes in this string breaks the parser.
Instead, use the admins.json file as described in Step 3.
Key Settings for Single Instance Configuration:
Log Level: Set
Serilog__MinimumLevel__Default=Information. You should only change this to Debug if Sendent Support requests it for troubleshooting.Log Output: It is recommended to set
Service__LoggingConfiguration__LogsOutput=1during the initial setup. This will help to ensure the service is running properly without issues.
Step 3. Set Up Exchange Credentials (admins.json)
Why this is needed: This file securely provides the application with the credentials needed to access Exchange mailboxes and helps bypass Exchange throttling limits by allowing multiple service accounts.
Inside your deployment folder, create a directory named exchangeAdmins and place your admins.json file inside it. Update your .env file to point to this file (e.g., Service__ExchangeConfiguration__ExchangeAdminFile=globalAdmins/admins.json).
Pro Tip for Environments: You can organize multiple JSON files in subfolders (e.g., testAdmins/admins.json or globalAdmins/admins.json). To switch environments, simply update the file path in your .env variable without needing to rebuild or rewrite files.
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 application instance connects to one specified Exchange type at a time. The "ExchangeType" field inside the admins.json.example 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.
Step 4. Start the Application
These commands tell Docker to pull the required images, map the volumes, and start the containers in the background.
The Sendent deployment is modular. You must build your startup command by chaining -f flags depending on which database and monitoring tools you want Docker to host for you.
Build your command by starting with the base file, adding your optional components, and ending with up:
1. The Base Command (Required): docker compose -f docker-compose.yml
2. Add your Database Container (Optional if using an external DB):
For PostgreSQL:
-f docker-compose.postgres.ymlFor MariaDB:
-f docker-compose.mariadb.ymlFor SQL Server:
-f docker-compose.sqlserver.yml
3. Add Monitoring (Optional):
For Loki & Grafana:
-f docker-compose.grafana.yml
Examples of complete commands:
Running with a local PostgreSQL container and Grafana:
docker compose -f docker-compose.yml -f docker-compose.postgres.yml -f docker-compose.grafana.yml up
Running with an external database (no local DB container) and no Grafana:
docker compose -f docker-compose.yml up
Step 5. Verify Container Status
Why this is needed: To ensure the primary synchronization service and your database containers are running without startup crashes.
Run the following command in your terminal:
docker compose ps
Step 6. Monitor Application Logs
Why this is needed: Logs are essential for verifying successful synchronization, reviewing scheduled runs, and troubleshooting errors.
To view real-time console logs, your Service__LoggingConfiguration__LogsOutput parameter in the .env file should be set to 1
Run:
docker compose logs
Warning: Grafana Security
If you chose to enable Grafana logging (Service__LoggingConfiguration__LogsOutput includes value 8) , be aware that the Grafana web interface is configured to be available only locally on the host machine running Docker. It is intentionally not exposed to external networks for security reasons.
Advanced: Handling Self-Signed Certificates (On-Premise Exchange)
If your On-Premise Microsoft Exchange server uses a self-signed SSL certificate (or a corporate CA), the .NET 8 Docker container will reject the connection for security reasons. You must manually inject your certificate into the container's trusted root store.
To do this without modifying the base files provided by Sendent, you can create a docker-compose.override.yml file.
Step 1. Prepare your certificate
Ensure your certificate is in .crt or .pem format (e.g., your-ca.crt).
Step 2. Place the certificate
Create a dedicated folder on your host machine to store the certificate. For example, create a folder named certs next to your deployment files and place your-ca.crt inside it.
Step 3. Create the override file
In the same directory as your main docker-compose.yml, create a new empty file named docker-compose.override.yml and paste the following configuration:
version: '3.4' services: sendent.synchronisation.service: volumes: - ./certs:/app/certs entrypoint: > /bin/sh -c "cp '/app/certs/your-ca.crt' /usr/local/share/ca-certificates/ && update-ca-certificates && dotnet Sendent.Synchronisation.Service.dll"
💡 Note: Filename Matching
Ensure you replace your-ca.crt in the entrypoint script with the exact filename of your actual certificate.
When you run your standard startup command (e.g., docker compose -f docker-compose.yml up -d), Docker will automatically detect this override file, mount the certificate folder, and execute the entrypoint script to trust your certificate before starting the synchronization service.