In Kestrel, leave SslProtocols at its default of None, which lets the operating system choose the protocol, and provide an explicit certificate in production because the development certificate is not installed outside development. Do not store certificate passwords in plain text in appsettings.json. Use a secret source and a managed store.
What the Kestrel documentation says
On protocols: "The default value, SslProtocols.None, causes Kestrel to use the operating system defaults to choose the best protocol. Unless you have a specific reason to select a protocol, use the default." You can set protocols in configuration, for example Tls12 and Tls13, or in code through ConfigureHttpsDefaults.
On certificates: the development certificate is used only locally. "In production, a TLS certificate must be explicitly configured. At a minimum, a default certificate must be provided." If an HTTPS endpoint has no certificate and no default is available, the server throws an exception and fails to start, which is the safe outcome.
On client certificates: the default ClientCertificateMode is NoCertificate, meaning Kestrel does not request or require one. Mutual TLS needs you to set it deliberately.
Why not hard code protocol versions
Microsoft's TLS guidance for .NET Framework makes the same argument that applies generally. If an app explicitly sets a protocol, it opts out of the OS defaults, and an explicit lower version prevents a TLS 1.3 connection. Letting the OS choose means the app picks up newer protocols later and the OS can block protocols found to be insecure. That guidance also warns against SslProtocols.Default, which forces older protocols. It is a .NET Framework page, so treat it as supporting reasoning, and use the Kestrel page for Kestrel settings.
If a policy requires a floor, for example no TLS 1.2 on an internal mesh, setting an explicit list is a legitimate choice. Document it so future upgrades revisit it. See also TLS 1.3 versus 1.2 and what to disable.
Certificate sources
Kestrel can load certificates from configuration or code:
| Source | Settings |
|---|---|
| PFX file | Path and Password |
| PEM files | Path, KeyPath and Password |
| Certificate store | Subject and Store, with optional Location and AllowInvalid, which defaults to false |
The docs warn against plain text passwords and show a placeholder, recommending user secrets for development and Azure Key Vault for production. Keep AllowInvalid false so a bad certificate does not slip in.
{
"Kestrel": {
"Certificates": {
"Default": {
"Path": "/etc/certs/site.pem",
"KeyPath": "/etc/certs/site.key"
}
}
}
}
PEM with an unencrypted key file avoids a password in configuration, but then the key file permissions are the control. Restrict it to the service account and mount it read only. Rotation also matters. Certificate lifetimes keep shrinking, so plan for renewal without a manual step.
Steps
- Do not set SslProtocols unless a policy needs it. If it does, list the allowed versions and record why.
- Provide a default certificate in production configuration.
- Keep passwords and private keys out of source control and plain configuration.
- Restrict file permissions on key files.
- Set ClientCertificateMode only where mutual TLS is intended.
- Test the endpoint with a TLS scanner and a client that offers only old protocols.
Try it yourself
Click through it at your own pace, or open it full screen. See how a scan looks at a live endpoint from outside.
Quick check
Does Kestrel use the development certificate in production?
No. The docs say the development certificate is not installed in non development environments, and a certificate must be configured explicitly.
Should I turn on client certificates everywhere?
Only for endpoints that should use mutual TLS. The default is not to request one.
Safeguard dependency scanning and SBOM generation cover the NuGet packages in your ASP.NET Core service, and the free scan is at gold.safeguard.sh/scan.
Sources
- Configure endpoints for the ASP.NET Core Kestrel web server (Microsoft Learn)
- Transport Layer Security best practices with .NET Framework (Microsoft Learn)
Last reviewed: 19 October 2026.