Skip to content

Configuration

Settings live in appsettings.json, with environment-specific overrides layered on top. Options are bound with validation on start, so an invalid value stops the host at startup rather than surfacing as a confusing failure at first use.

Any key can be overridden by environment variable, using __ as the section separator:

Terminal window
DmsDataAccess__MaxPoolSize=200
RateLimiting__Enabled=false

This page is the guided version. For the exhaustive key-by-key table, see Configuration keys.

Key Consequence if wrong
ConnectionStrings:DefaultConnection Nothing works. Must authenticate as a least-privilege DocsentryAppRole member, not the deployment or schema-owner principal - a startup probe enforces this.
DataProtection:KeyPath Outside Development the host refuses to start. Must be an absolute path outside the content root.
DataProtection:CertificateThumbprint Required for a non-Windows host or a multi-instance deployment. Omitted means Windows DPAPI, which is machine-scoped and cannot be restored onto a different machine.
AllowedHosts Ships as the placeholder docsentry.example.com. Leaving it unchanged makes host filtering reject every request with a bare 400 and no explanatory log entry.

The Data Protection key ring protects every authentication cookie, the “remember this machine” two-factor cookie, and stored secrets such as the antivirus API key. Reading it is enough to forge a session for any user and bypass two-factor authentication. Treat it as a credential: back it up, restrict access to it, and never place it inside the content root where a misconfigured static file handler could serve it.

"DmsDataAccess": {
"MaxPoolSize": 100,
"CommandTimeoutSeconds": 30,
"DefaultPageSize": 50,
"MaxPageSize": 200
}

MaxPoolSize is the ceiling on concurrent SQL connections and is the single most important capacity lever. MaxPageSize bounds how much a caller can request in one page, which stops a client asking for the whole repository at once. See Performance and tuning.

Storage:RootPath is the root of the file store; TempSubpath, QuarantineSubpath, and BlobSubpath are resolved beneath it. All of these are storage-root-relative - an absolute path in a subpath is rejected at startup.

"Uploads": {
"ChunkSizeBytes": 4194304,
"MaxFileSizeBytes": 104857600,
"SessionLifetime": "02:00:00"
}

That is a 4 MB chunk, a 100 MB per-file ceiling, and a two-hour window to finish a resumable upload. AllowedContentTypes is the global allowlist; per-folder policies layer on top of it. See Upload allowlist.

PreviewOptions bounds generated artefacts at 1600x2000 with a 320-pixel thumbnail edge, stored as WebP. ImageContentTypes, PdfContentType, and OfficeContentTypes decide which renderer handles a given file. SofficePath may be left empty for auto-discovery.

BackgroundJobs holds one block per recurring job, each with at least Enabled, Interval, and MaxItems. Twelve jobs are configured here; FolderEmailIntake is the only one disabled by default.

Cadence is a real cost, not a free knob. The configuration file itself records why the permission rebuild job runs every 30 seconds rather than every 5: access-control writes drain the rebuild queue inline within the same transaction, so the job is a safety net rather than the primary path, and a 5-second cadence made the job runner’s own bookkeeping the dominant cost of an otherwise idle system.

See Background jobs for the full table.

"RateLimiting": {
"Enabled": true,
"WindowSeconds": 10,
"AuthenticatedPermitLimit": 200,
"AnonymousPermitLimit": 50,
"AuthenticationWindowSeconds": 300,
"AuthenticationPermitLimit": 100,
"AuthenticationAccountPermitLimit": 10
}

Authentication forms use two independent fixed windows: a strict per-account bucket that applies across all source addresses, and a looser per-address bucket sized for shared office egress. The two-bucket design exists so that one user failing to log in repeatedly cannot lock out everyone else behind the same public address.

AuthenticationConcurrency separately bounds simultaneous password verification, which is CPU-intensive. Its PermitLimit defaults in code to the processor count and its QueueLimit to four times that; override them only after measuring the host.

"AccountSecurity": {
"MaxFailedAccessAttempts": 5,
"LockoutMinutes": 15,
"AllowSelfRegistration": false
}

Security:Csp:Mode switches the Content Security Policy between enforcing and reporting. Security:Hsts controls max-age, subdomain inclusion, and preload.

Security:ForwardedHeaders is the one to get right behind a reverse proxy. Populate KnownProxies or KnownNetworks with your proxy. The handling is fail-closed: with neither configured, forwarded headers are not trusted at all, so a spoofed client address cannot be used to slip past address-based rate limiting. The cost of getting this wrong is that every request appears to come from the proxy.

Workflows:Engine selects Dapper (the default, built in) or Elsa. Elsa requires its deploy script to have been applied; the application fails fast at startup otherwise rather than failing at the first workflow. See Workflow concepts.

Logging:SlowRequestThresholdMs (default 1000) is the boundary above which a request is logged as slow. Serilog handles structured output. Lower the threshold when hunting a latency problem; leave it alone otherwise, because request logging at volume is itself a cost.