Language Frankfurt, Germany

Deploy .NET and ASP.NET Core on Nodion

Nodion recognizes .NET by a project file, a solution or a global.json. The .NET buildpack runs dotnet publish -c Release with the SDK your project targets and starts the published app on the ASP.NET Core runtime, listening on the port Nodion sets; the SDK stays out of the run image. The app runs in Frankfurt, next to a managed PostgreSQL database if you need one.

Deploy to Nodion ›

from 1 EUR / month

Up to 15 € credit when signing up

Detected by
*.csproj, *.fsproj, *.sln or global.json
Start
dotnet <App>.dll on http://0.0.0.0:$PORT
.NET
8, 9, 10 (default)
Region
EU Central (Frankfurt)

Deploy .NET and ASP.NET Core step by step

  1. One project at the root, or DOTNET_PROJECT Nodion publishes the one .csproj or .fsproj in the base directory, framework-dependent. With several projects, or a solution whose projects sit in subfolders, set DOTNET_PROJECT to the web project's path with the Build flag on the Environment tab; the root still needs a .sln or global.json so Nodion detects .NET. Pointing the base directory at the project folder only works if it references no projects outside it, because the build sees nothing above that folder. Build variable
    DOTNET_PROJECT=src/MyApp.Web/MyApp.Web.csproj
  2. Leave the address to Nodion Nodion starts the app with ASPNETCORE_URLS=http://0.0.0.0:$PORT. Remove hard-coded URLs such as app.Run("http://localhost:5000") and Kestrel endpoints in appsettings.json, which take precedence over it. An API without a page at / needs a health endpoint; set its path as the health check path in the app settings. Program.cs
    var builder = WebApplication.CreateBuilder(args);
    builder.Services.AddHealthChecks();
    
    var app = builder.Build();
    app.MapHealthChecks("/healthz");
    app.MapGet("/", () => "Hello from Nodion");
    
    app.Run();
  3. Keep AllowedHosts open for the health check The health check calls each instance with its internal IP as the host. The template default "AllowedHosts": "*" lets it through. A list of your domains makes ASP.NET Core answer 400, and the release never goes live; keep *, or check hosts in your own middleware that skips the health check path. appsettings.json
    {
      "AllowedHosts": "*"
    }
  4. Create the app and attach PostgreSQL Create an application from your repository in the region EU Central, then a PostgreSQL database in the same region. Npgsql uses key-value connection strings, not postgres:// URLs like DATABASE_URL, so when you attach the database on the Environment tab, inject host, port, database, user and password under your own names and build the connection string from them. Program.cs
    var cs = new Npgsql.NpgsqlConnectionStringBuilder
    {
        Host = builder.Configuration["DB_HOST"],
        Port = int.Parse(builder.Configuration["DB_PORT"] ?? "5432"),
        Database = builder.Configuration["DB_NAME"],
        Username = builder.Configuration["DB_USER"],
        Password = builder.Configuration["DB_PASSWORD"],
    }.ConnectionString;
    builder.Services.AddDbContext<AppDbContext>(o => o.UseNpgsql(cs));
  5. Apply EF Core migrations Nodion does not run EF Core migrations, and the run image has no SDK, so dotnet ef cannot run as a release step. Apply them when the app starts with Database.Migrate(), which is fine for a single instance, or switch to a Dockerfile that builds an EF Core migration bundle and runs it as the app's release command. Program.cs
    using (var scope = app.Services.CreateScope())
    {
        scope.ServiceProvider.GetRequiredService<AppDbContext>().Database.Migrate();
    }

Good to know

  • SDK and runtime versionThe .NET line comes from global.json, else from the TargetFramework of the project in the base directory, else .NET 10, and the run image gets the ASP.NET Core runtime of the same line. A project in a subfolder is not read for this, so a net8.0 or net9.0 app selected with DOTNET_PROJECT needs a global.json with that version. Nodion installs the current SDK of that line, which can be a newer feature band, so set "rollForward": "latestFeature" there.
  • Production settingsNodion does not set ASPNETCORE_ENVIRONMENT, so ASP.NET Core runs as Production and reads appsettings.Production.json on top of appsettings.json. Keep secrets in environment variables marked secret; ConnectionStrings__Default maps to ConnectionStrings:Default.

What Nodion runs for you

  • Deploys without downtime Push to your branch and Nodion builds a new release. Traffic switches once the new instances answer their health check; a failed release leaves the running one in place. Apps with a local volume restart instead, because the disk belongs to one instance.
  • Databases next to the app Managed PostgreSQL, pgvector, MySQL, Valkey and ClickHouse in the same region. Attached databases arrive as DATABASE_URL, REDIS_URL or CLICKHOUSE_URL.
  • Previews per pull request Turn on previews and pull requests from your repository get their own app with its own URL and fresh, empty databases, created automatically or by hand. Forks and bot pull requests are skipped.
  • Workers, cron jobs and scaling Run workers as extra processes of the same app, schedule jobs on the Cron tab, and scale every process to up to 16 instances.
  • Release step With buildpacks, a Procfile release: line runs with every new build. Dockerfile apps, and redeploys or rollbacks to an earlier image, use a release command set on the app itself, which also takes precedence over the Procfile line. On static sites a release step runs in an image that holds only the built files.
  • Logs and metrics Build, release and runtime logs plus CPU, memory, disk and network metrics for every instance in the dashboard.
  • Domains and HTTPS A default hostname with HTTPS from the first deploy; your own domains get certificates automatically.

Further reading

.NET and ASP.NET Core on Nodion: questions and answers

Why does my ASP.NET Core deploy never become ready?

Usually the health check gets a 400 from a restricted AllowedHosts, a 404 on / in an API project, or no answer because a hard-coded URL or Kestrel endpoint makes the app listen elsewhere. Keep AllowedHosts at *, set a health check path such as /healthz and let ASPNETCORE_URLS decide the address.

Can I deploy a Blazor app?

Blazor Server apps and the server project of a Blazor Web App run as ASP.NET Core apps; point DOTNET_PROJECT at the server project if the repository has several. A standalone Blazor WebAssembly app has no server to start, so the .NET buildpack cannot deploy it: host it in an ASP.NET Core project or use a Dockerfile.

Does Nodion run EF Core migrations?

No. Apply them at startup with Database.Migrate(), or build an EF Core migration bundle in a Dockerfile and run it as the release command. The dotnet ef tool needs the SDK, which is not in the buildpack's run image.

Does F# work?

Yes. An .fsproj is detected and published like a .csproj, so F# web apps on ASP.NET Core deploy the same way.

Where does my .NET and ASP.NET Core app run?

In the EU Central region in Frankfurt, Germany. Build, registry, the app and its databases, volumes, buckets, logs and metrics stay in that region, and Nodion's API and control plane are hosted in Germany. Nodion GmbH is based in Stuttgart.

Can I use .NET and ASP.NET Core in line with the GDPR?

Nodion provides the basis for it: Nodion GmbH is based in Stuttgart, Germany, in the Frankfurt region the app, its databases and volumes run in Germany, and you conclude the data processing agreement (DPA) under Art. 28 GDPR electronically in the dashboard. Whether your setup complies also depends on how you configure and use the app.

How much does it cost to run .NET and ASP.NET Core on Nodion?

An app instance starts at 1 EUR per month. The setup in the cost box costs 3.50 EUR per month: App 2 EUR, PostgreSQL 1.50 EUR. Prices are net and billed per second, and you pick bigger sizes or more instances whenever you need them.

Can I use my own domain for my .NET and ASP.NET Core app?

Yes. Every app gets a default hostname with HTTPS. Add your own domain on the app's Domains tab; the TLS certificate is issued and renewed automatically.

Give your agent a cloud.

Earn up to 15 € in credit when signing up.

Continue with GitHub

or with email

Stay in the loop.

Product news, no spam. Unsubscribe anytime.