Deploying an ASP.NET Core app means a published artifact (framework-dependent or self-contained), a process manager, config outside the binary, and a reverse proxy or platform that terminates TLS. The product name is .NET; “.NET Core” is the historical 1.x–3.x line.
Publish
dotnet publish -c Release -o ./out
# or: docker build, then run the image
- Framework-dependent: smaller; the host must have the runtime.
- Self-contained: ships the runtime, so the artifact is larger. Useful when you do not control the host.
- Native AOT: a different publish. Trimmed, and stricter about reflection. Not a bigger self-contained build.
- Containers: default for new services; one process per container; listen on 8080 (or whatever you document), not 80 as root.
Hosts
Kestrel is the server. In production put IIS / nginx / Caddy / a cloud load balancer in front, or use a platform (App Service, Container Apps, Kubernetes) that does that for you. Set ASPNETCORE_ENVIRONMENT, bind URLs, and do not ship Development to the internet (detailed errors, user secrets).
Config and secrets
appsettings.json for non-secrets. Environment variables or a vault for connection strings. User secrets are for laptops. Connection strings in source control are a rotate-now event.
What breaks it
Development on the public host turns on detailed errors, and data-protection keys that live only in memory log every user out on the next deploy. Run Production, read secrets from the environment or a vault, and persist the key ring.
ASPNETCORE_ENVIRONMENT=Development
ASPNETCORE_ENVIRONMENT=Production
Pitfalls
- Running as root in a container “because it bound to 80.”
dotnet runon a VM as the production strategy.- In-memory Data Protection keys that reset cookies on every deploy (persist the key ring).
CI: Azure Pipelines. HTTP surface: Minimal APIs.