ASP.NET Core is Microsoft's cross-platform framework for building modern web applications and APIs. It runs on Linux, macOS, and Windows with near-native performance thanks to the Kestrel web server. The framework powers everything from lightweight microservices to enterprise-scale distributed systems.
With Out Plane, you can deploy your ASP.NET Core application in under a minute — no Windows Server or IIS required. This guide shows you exactly how.
What You'll Need
Before starting, make sure you have:
- .NET 8 SDK installed on your machine
- A GitHub account
- An ASP.NET Core application in a GitHub repository
- A
Dockerfilein your project root
Don't have .NET installed? Download it from dotnet.microsoft.com:
- Windows: Download the SDK installer from dotnet.microsoft.com and run it. Verify with
dotnet --versionin PowerShell. - macOS: Use
brew install dotnet-sdkor download the PKG installer from dotnet.microsoft.com - Linux: Run
sudo apt install -y dotnet-sdk-8.0(Ubuntu/Debian) or follow the instructions for your distribution at dotnet.microsoft.com
Once .NET is installed, create a project folder:
dotnet new webapi -n MyWebApi --use-controllers false
cd MyWebApiIf you don't have an ASP.NET Core app yet, use our example below.
Quick Start: Sample ASP.NET Core Application
Here's a minimal ASP.NET Core application using the Minimal API pattern. Create a new project:
dotnet new webapi -n MyWebApi --use-controllers false
cd MyWebApiReplace Program.cs with a simple API:
var builder = WebApplication.CreateBuilder(args);
builder.WebHost.UseUrls("http://0.0.0.0:8080");
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
var app = builder.Build();
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.MapGet("/", () => new
{
Message = "Hello from ASP.NET Core!",
Status = "running"
});
app.MapGet("/health", () => Results.Ok(new
{
Status = "healthy"
}));
var items = new List<object>
{
new { Id = 1, Name = "Item One" },
new { Id = 2, Name = "Item Two" },
new { Id = 3, Name = "Item Three" }
};
app.MapGet("/api/items", () => items);
app.MapGet("/api/items/{id}", (int id) =>
{
var item = items.FirstOrDefault(i => ((dynamic)i).Id == id);
return item is not null ? Results.Ok(item) : Results.NotFound(new { Error = "Item not found" });
});
app.Run();Alternatively, you can configure the port using an environment variable instead of hardcoding it. Remove the builder.WebHost.UseUrls() line and set ASPNETCORE_URLS=http://+:8080 in your environment or Dockerfile.
Test your application locally:
dotnet runVisit http://localhost:8080 in your browser. You should see the JSON response.
Add a Dockerfile
ASP.NET Core applications on Out Plane require a Dockerfile. Create a Dockerfile in the project root using a multi-stage build:
# Build stage
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
WORKDIR /src
COPY *.csproj ./
RUN dotnet restore
COPY . .
RUN dotnet publish -c Release -o /app/publish
# Runtime stage
FROM mcr.microsoft.com/dotnet/aspnet:8.0-alpine AS runtime
WORKDIR /app
COPY --from=build /app/publish .
EXPOSE 8080
ENV ASPNETCORE_URLS=http://+:8080
ENTRYPOINT ["dotnet", "MyWebApi.dll"]This produces a production-ready image under 100MB. The SDK image is only used during the build stage and discarded from the final image. The Alpine-based runtime image keeps the footprint small.
Push this code to a GitHub repository, and you're ready to deploy.
Deploy in 3 Steps
Step 1: Connect Your Repository
- Go to console.outplane.com
- Sign in with your GitHub account
- Select your ASP.NET Core repository from the list
Out Plane detects the Dockerfile and configures the build process automatically.
Step 2: Configure Your Application
Configure the following settings in the create application form:
Build Method
Select how Out Plane should build your application:
- Dockerfile (Required for .NET): Uses the multi-stage Dockerfile above to build and package your application. This is the recommended and required approach for ASP.NET Core applications.
Basic Settings
- Port: Set to
8080 - Branch: Select
mainor your preferred branch - Region: Choose the region closest to your users (default: Nuremberg)
Environment Variables (Optional)
Add environment-specific configuration using the Add button or Raw Edit for bulk entry:
ASPNETCORE_ENVIRONMENT=ProductionFor more complex applications, you might add variables like database connection strings or API keys.
Step 3: Deploy
Click Deploy Application and watch the build process:
- Queued → Waiting for resources
- Building → Restoring NuGet packages and compiling your application
- Deploying → Starting the Kestrel web server
- Ready → Your app is live
Once the status shows Ready, your application is live. You can find your application URL at the top of the deployment page. Click the URL to open your ASP.NET Core app in a new tab. SSL is automatically configured.
Production Best Practices
Kestrel Configuration
Kestrel is the default web server for ASP.NET Core and is production-ready. Configure it for optimal performance:
var builder = WebApplication.CreateBuilder(args);
builder.WebHost.ConfigureKestrel(options =>
{
options.Limits.MaxConcurrentConnections = 1000;
options.Limits.MaxRequestBodySize = 10 * 1024 * 1024; // 10MB
options.Limits.RequestHeadersTimeout = TimeSpan.FromSeconds(30);
});There is no need for a reverse proxy like IIS or Nginx when deploying to Out Plane. Kestrel handles production traffic directly.
Health Checks
ASP.NET Core has built-in health check middleware. Use it for comprehensive health monitoring:
builder.Services.AddHealthChecks()
.AddCheck("self", () => HealthCheckResult.Healthy())
.AddNpgSql(builder.Configuration.GetConnectionString("DefaultConnection")!);
var app = builder.Build();
app.MapHealthChecks("/health", new HealthCheckOptions
{
ResponseWriter = async (context, report) =>
{
context.Response.ContentType = "application/json";
var result = new
{
Status = report.Status.ToString(),
Checks = report.Entries.Select(e => new
{
Name = e.Key,
Status = e.Value.Status.ToString(),
Duration = e.Value.Duration.TotalMilliseconds
})
};
await context.Response.WriteAsJsonAsync(result);
}
});Install the PostgreSQL health check package:
dotnet add package AspNetCore.HealthChecks.NpgSqlOut Plane uses this endpoint to verify your application is ready to receive traffic.
Logging with Serilog
Replace the default logger with Serilog for structured, production-grade logging:
dotnet add package Serilog.AspNetCore
dotnet add package Serilog.Sinks.Consoleusing Serilog;
var builder = WebApplication.CreateBuilder(args);
builder.Host.UseSerilog((context, config) =>
{
config
.ReadFrom.Configuration(context.Configuration)
.WriteTo.Console(outputTemplate:
"[{Timestamp:HH:mm:ss} {Level:u3}] {Message:lj}{NewLine}{Exception}");
});
var app = builder.Build();
app.UseSerilogRequestLogging();Structured logs make it easier to filter and search in Out Plane's log viewer.
Response Compression
Enable response compression to reduce bandwidth and improve response times:
builder.Services.AddResponseCompression(options =>
{
options.EnableForHttps = true;
});
var app = builder.Build();
app.UseResponseCompression();This compresses JSON responses and static content using gzip and Brotli automatically.
CORS Configuration
If your API serves a frontend on a different domain, configure CORS:
builder.Services.AddCors(options =>
{
options.AddPolicy("AllowFrontend", policy =>
{
policy.WithOrigins("https://yourfrontend.com")
.AllowAnyHeader()
.AllowAnyMethod();
});
});
var app = builder.Build();
app.UseCors("AllowFrontend");Connecting a Database
Most ASP.NET Core applications need a database. Out Plane provides managed PostgreSQL:
- Go to Databases in the sidebar
- Click Create Database
- Select PostgreSQL version and region
- Copy the connection URL
Add the connection URL as an environment variable:
DATABASE_URL=Host=host;Port=5432;Database=database;Username=user;Password=passwordUse Entity Framework Core to connect to PostgreSQL:
dotnet add package Npgsql.EntityFrameworkCore.PostgreSQL
dotnet add package Microsoft.EntityFrameworkCore.DesignCreate a DbContext:
using Microsoft.EntityFrameworkCore;
public class AppDbContext : DbContext
{
public AppDbContext(DbContextOptions<AppDbContext> options) : base(options) { }
public DbSet<Item> Items => Set<Item>();
}
public class Item
{
public int Id { get; set; }
public string Name { get; set; } = string.Empty;
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
}Register the context in Program.cs:
var connectionString = Environment.GetEnvironmentVariable("DATABASE_URL")
?? builder.Configuration.GetConnectionString("DefaultConnection");
builder.Services.AddDbContext<AppDbContext>(options =>
options.UseNpgsql(connectionString));Run migrations before deploying:
dotnet ef migrations add InitialCreate
dotnet ef database updateFor production deployments, apply migrations at startup:
using (var scope = app.Services.CreateScope())
{
var db = scope.ServiceProvider.GetRequiredService<AppDbContext>();
db.Database.Migrate();
}Custom Domain Setup
Replace the default .outplane.app URL with your own domain:
- Navigate to Domains
- Click Map Domain
- Enter your domain (e.g.,
api.yourdomain.com) - Add the DNS records shown to your domain registrar
SSL certificates are automatically provisioned once DNS propagates.
Monitoring Your Application
After deployment, monitor your ASP.NET Core application:
- Logs: View real-time application logs including Kestrel request logs and Serilog output
- Metrics: Track CPU, memory, and network usage
- HTTP Logs: Analyze incoming requests, response times, and status codes
Access these from the sidebar in your application dashboard.
Troubleshooting
Application Won't Start — Port Binding
Check the port configuration. Make sure you set the port to 8080 in the application settings. Your Dockerfile must include ENV ASPNETCORE_URLS=http://+:8080 and EXPOSE 8080. Alternatively, set builder.WebHost.UseUrls("http://0.0.0.0:8080") in Program.cs.
Build Fails — SDK vs Runtime Image
Use the SDK image for building and the runtime image for running. The mcr.microsoft.com/dotnet/sdk:8.0 image contains the compiler and build tools. The mcr.microsoft.com/dotnet/aspnet:8.0-alpine image contains only the runtime. Do not use the SDK image as your final stage — it is over 700MB.
Missing Dependencies at Runtime
Verify all NuGet packages are restored during build. Make sure dotnet restore runs in your Dockerfile before dotnet publish. If you use native libraries, ensure they are available in the Alpine base image or switch to the Debian-based runtime image (mcr.microsoft.com/dotnet/aspnet:8.0).
Database Migration Errors
Run migrations before or during startup. If you see relation does not exist errors, your database schema is out of date. Either run dotnet ef database update locally against the production database or add automatic migration at startup as shown in the database section above.
Health Check Failures
Verify your health endpoint returns HTTP 200. Out Plane checks /health to determine if your application is ready. If the health check includes database checks, ensure the database connection string is correct and the database is accessible from your application.
Next Steps
Your ASP.NET Core application is now deployed and running in production. Here's what to explore next:
- Scale your application: Adjust instance types and auto-scaling settings for higher traffic
- Set up CI/CD: Enable automatic deployments on every git push
- Add monitoring: Integrate with external monitoring tools via Out Plane's metrics export
- Deploy microservices: Use Out Plane to deploy multiple .NET services with internal networking
Summary
Deploying an ASP.NET Core application to Out Plane takes three steps:
- Connect your GitHub repository
- Configure port (8080), environment variables, and Dockerfile build method
- Deploy and get your live URL with automatic HTTPS
No Windows Server, no IIS, no manual SSL setup, no infrastructure management. Just push your code and go live.
Ready to deploy your ASP.NET Core application? Get started with Out Plane and receive $20 in free credit. Pay only for what you use with per-second billing.