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:
DmsDataAccess__MaxPoolSize=200RateLimiting__Enabled=falseThis page is the guided version. For the exhaustive key-by-key table, see Configuration keys.
Required before first start
Section titled “Required before first start”| 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.
Data access
Section titled “Data access”"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 and uploads
Section titled “Storage and uploads”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.
Previews
Section titled “Previews”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.
Background jobs
Section titled “Background jobs”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.
Rate limiting and shedding
Section titled “Rate limiting and shedding”"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.
Account security
Section titled “Account security”"AccountSecurity": { "MaxFailedAccessAttempts": 5, "LockoutMinutes": 15, "AllowSelfRegistration": false}Security headers
Section titled “Security headers”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.
Workflow engine
Section titled “Workflow engine”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
Section titled “Logging”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.