If you have ever tried to install .NET on Ubuntu and ended up in a maze of conflicting package feeds, broken SDK versions, and cryptic apt error messages, you are not alone. For years, the .NET-on-Linux installation story was a source of genuine frustration. Microsoft published packages to packages.microsoft.com. Canonical published their own builds to the Ubuntu archive. The two sets of packages had the same names but came from different sources, and mixing them produced the kind of silent breakage that wastes an afternoon.

Ubuntu 26.04 LTS ("Resolute Raccoon"), released on 23 April 2026, draws a line under that era. .NET 10 is in the default Ubuntu package archive. One command installs a fully functional SDK. The Microsoft feed no longer publishes packages for Ubuntu 24.04 or later. There is, at last, a single source of truth.

This matters beyond convenience. If your CI pipelines, Dockerfiles, or deployment scripts touch Ubuntu, the rules have changed. Here is what you need to know.

The one-command install

On a fresh Ubuntu 26.04 system, installing .NET 10 is exactly as simple as it should have been all along:

terminal
sudo apt update && sudo apt install -y dotnet-sdk-10.0

That pulls the SDK, runtime, and ASP.NET Core runtime from the built-in Ubuntu archive. No GPG keys to import. No third-party repositories to register. No packages-microsoft-prod.deb to download first. The packages are source-built by Canonical and ship through the same update channel as everything else on the system.

The available packages follow the standard naming convention:

Package What it installs
dotnet-sdk-10.0 SDK, runtime, and ASP.NET Core runtime
dotnet-runtime-10.0 .NET runtime only
aspnetcore-runtime-10.0 ASP.NET Core runtime (includes the base runtime)
dotnet-sdk-aot-10.0 Native AOT compilation toolchain

// TIP

If you are deploying an ASP.NET Core application and do not need the SDK on the target machine, install aspnetcore-runtime-10.0 rather than the full SDK. It includes both the ASP.NET Core and base .NET runtimes.

Updates arrive through the normal apt upgrade cycle. No separate update mechanism to remember:

terminal
sudo apt update && sudo apt upgrade -y dotnet-sdk-10.0

Running .NET 8 or 9 alongside .NET 10

Production systems rarely run a single .NET version. You might have a .NET 8 service that is not ready to migrate yet, or a .NET 9 application that you plan to skip straight to .NET 10 with. Ubuntu 26.04 handles this through the backports PPA, maintained by Canonical with best-effort support.

terminal
sudo apt install -y software-properties-common
sudo add-apt-repository ppa:dotnet/backports
sudo apt update
sudo apt install -y dotnet-sdk-8.0 dotnet-sdk-9.0

The backports PPA is compatible with the built-in Ubuntu feed, so there is no risk of the package conflicts that plagued earlier setups. You can install .NET 8, 9, and 10 side by side without worrying about feed priority or apt preferences files.

Keep in mind that both .NET 8 and .NET 9 reach end of life on 10 November 2026. If you are running either in production, plan the migration sooner rather than later.

// WARNING

The backports PPA provides best-effort support, which does not extend beyond Microsoft's own support lifetime. Once .NET 8 or 9 goes end of life, Canonical will not continue patching those packages.

The package conflict era is over

To appreciate what changed, a brief look back is useful.

When Canonical started shipping .NET packages in Ubuntu 22.04, the result was two competing package sources: the Ubuntu archive and the Microsoft feed at packages.microsoft.com. Both published packages with the same names. If you had the Microsoft feed configured (perhaps from installing PowerShell or SQL Server tools) and then tried to install .NET from Ubuntu's archive, apt would pull some packages from one feed and some from the other. The result was a broken SDK that reported missing frameworks, failed to find installed runtimes, or refused to build entirely.

The fix required a ritual of apt preferences files to pin packages to one feed, or uninstalling everything and starting fresh. The official documentation eventually grew an entire troubleshooting page dedicated to this single problem.

Starting with Ubuntu 24.04, Microsoft stopped publishing .NET packages to the Microsoft feed for Ubuntu entirely. On Ubuntu 26.04, there is no Microsoft feed to conflict with. The packages come from Canonical, full stop.

If you are upgrading from an older Ubuntu version where the Microsoft feed was configured, uninstall all .NET packages before upgrading. The package names are the same, but the provenance has changed, and leftover configuration from the old feed can still cause problems.

terminal
# Before upgrading Ubuntu, remove old .NET packages
sudo apt remove 'dotnet*' 'aspnet*'
sudo apt autoremove

# Remove the Microsoft feed if it exists
sudo rm -f /etc/apt/sources.list.d/microsoft-prod.list
sudo rm -f /etc/apt/trusted.gpg.d/microsoft.asc.gpg

After upgrading to 26.04, reinstall from the Ubuntu archive:

terminal
sudo apt update && sudo apt install -y dotnet-sdk-10.0

// IMPORTANT

If you use other Microsoft packages like powershell, mssql-tools, or mdatp that still come from the Microsoft feed, you need to deprioritise the .NET packages from that feed to avoid conflicts. The Microsoft documentation has a dedicated guide for configuring apt preferences in this scenario.

Container images: noble to resolute

If you are running .NET in containers on Ubuntu, the migration path is straightforward. The new container images use the resolute tag, replacing noble from Ubuntu 24.04.

Dockerfile
# Before (Ubuntu 24.04)
FROM mcr.microsoft.com/dotnet/aspnet:10.0-noble AS base

# After (Ubuntu 26.04)
FROM mcr.microsoft.com/dotnet/aspnet:10.0-resolute AS base

For an existing set of Dockerfiles, a one-liner handles the migration:

terminal
find . -name 'Dockerfile*' -exec sed -i 's/noble/resolute/g' {} +

All the image variants you are used to remain available: full images, chiseled images, and AOT-optimised images. Chiseled images are the distroless variant — they contain only the minimal set of packages .NET needs, with the shell, package manager, and everything else stripped out.

Dockerfile
FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build
WORKDIR /src
COPY ["OrderApi.csproj", "."]
RUN dotnet restore
COPY . .
RUN dotnet publish -c Release -o /app/publish

FROM mcr.microsoft.com/dotnet/aspnet:10.0-resolute-chiseled AS final
WORKDIR /app
COPY --from=build /app/publish .
ENTRYPOINT ["dotnet", "OrderApi.dll"]

One detail worth noting: containers inherit the host system's kernel. If you run Ubuntu 26.04 containers on an Ubuntu 24.04 host, your application uses the Linux 6.x kernel from the host, not the Linux 7.0 kernel that ships with 26.04. For most applications this makes no difference, but if you are relying on kernel-level features (io_uring improvements, new eBPF capabilities), you will need to upgrade the host as well.

Native AOT on Ubuntu 26.04

Native AOT compilation produces self-contained binaries that do not require the .NET runtime to be installed on the target machine. Ubuntu 26.04 makes this easy to set up:

terminal
sudo apt install -y dotnet-sdk-aot-10.0 clang

The clang package is needed because Native AOT uses LLVM's linker (LLD) under the hood. With both packages installed, you can publish a Native AOT binary:

terminal
dotnet publish -c Release -r linux-x64 /p:PublishAot=true

The results are compelling. A hello-world program compiles to roughly 1.4 MB and starts in about 3 milliseconds. A self-contained web API with source-generated JSON serialisation comes in at around 13 MB — small enough to fit comfortably in a minimal container image.

For containerised deployments, Native AOT pairs naturally with chiseled images:

Dockerfile
FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build
WORKDIR /src
COPY ["WeatherApi.csproj", "."]
RUN dotnet restore
COPY . .
RUN dotnet publish -c Release -r linux-x64 /p:PublishAot=true -o /app/publish

FROM mcr.microsoft.com/dotnet/runtime-deps:10.0-resolute-chiseled AS final
WORKDIR /app
COPY --from=build /app/publish .
ENTRYPOINT ["./WeatherApi"]

Notice the base image switches from aspnet to runtime-deps. Native AOT binaries are fully self-contained, so they only need the OS-level dependencies (libc, OpenSSL, ICU), not the .NET runtime itself.

OS changes that affect your .NET applications

Ubuntu 26.04 ships with three platform-level changes worth understanding.

Linux 7.0 kernel

The jump from Linux 6.x to 7.0 is the most visible change. Microsoft's dotnet/runtime team has been running CI against Ubuntu 26.04 images since late 2025, so the core .NET runtime and libraries are well tested. If your application uses P/Invoke to call native libraries or relies on kernel-specific behaviour (file system notifications, socket options, cgroup configuration), test on 26.04 before deploying.

Post-quantum cryptography

Ubuntu 26.04 ships with OpenSSL 3.5, which includes support for the post-quantum cryptographic algorithms ML-KEM, ML-DSA, and SLH-DSA. .NET 10 added native support for these algorithms through the System.Security.Cryptography namespace. If you are building systems that need long-term cryptographic security — certificate authorities, document signing, key exchange protocols — the toolchain is now available out of the box.

cgroup v1 removal

Ubuntu 26.04 removes support for cgroup v1 entirely. This is a non-event for .NET applications because the runtime added cgroup v2 support years ago. If you are running .NET in containers, the runtime already uses cgroup v2 to detect memory and CPU limits. No changes required.

Architecture support

One advantage of the Canonical-built packages over the old Microsoft feed is broader architecture support. The Ubuntu archive provides .NET 10 packages for:

The Microsoft feed only ever supported x64. If you are running .NET on ARM-based servers (Graviton instances on AWS, Ampere on Azure and Oracle Cloud), Ubuntu's packages have you covered without resorting to manual tarball installs.

Common pitfalls

Leftover Microsoft feed configuration. If you upgraded from Ubuntu 22.04, you may still have /etc/apt/sources.list.d/microsoft-prod.list on the system. Even if it points at an older Ubuntu version, its presence can confuse apt dependency resolution. Remove it.

SDK feature bands. Canonical publishes the .1xx feature band of each SDK version. If you need a higher feature band (say, 10.0.3xx for a specific workload), the Ubuntu packages will not have it. You will need to use the install script or a manual tarball in that case.

Missing software-properties-common. The add-apt-repository command used to configure the backports PPA requires the software-properties-common package. Most Ubuntu desktop installations include it, but minimal server installs and container images often do not. Install it first if you get a "command not found" error.

Preview versions. Neither the Ubuntu archive nor the backports PPA publishes preview releases. If you want to test .NET 11 previews, use the dotnet-install script or download the tarball manually. These side-by-side installs coexist with the apt-managed packages without conflict, as long as you install them to a separate location (the install script defaults to ~/.dotnet).

Chiseled image debugging. Chiseled container images have no shell. If you need to troubleshoot a running container, either attach a debug sidecar or use docker cp to pull logs. Do not use chiseled images in development — save them for staging and production where the smaller attack surface justifies the debugging inconvenience.

Summary