Guides
ASP.NET Core and SQL Server
Running an ASP.NET Core app (API, MVC, Razor Pages, Blazor Server) on Meghly with SQL Server or another database — from preparing the project to migrations and SSMS.
What runs
Microsoft.NET.Sdk.Webprojects: Web API, MVC, Razor Pages, Blazor Server.- .NET 10, 9 and 8 — the version comes from the
.csproj's<TargetFramework>(such asnet10.0). Use .NET 10 for new apps; on .NET 8/9 the panel warns you, as Microsoft's support is ending. - A
Microsoft.NET.Sdk.Workerproject (background service) in the same solution runs as a separateworkerprocess. - Test projects (xUnit, NUnit, MSTest) are left out of the build.
Old ASP.NET MVC 5 / .NET Framework (net48, packages.config, web.config-style .csproj) runs only on Windows, so Meghly turns it away with a clear message. It has to be moved to ASP.NET Core first.
Preparing the project
Connection string
Meghly gives the database connection as ConnectionStrings__Default, so name it Default in your code:
builder.Services.AddDbContext<AppDbContext>(o =>
o.UseSqlServer(builder.Configuration.GetConnectionString("Default")));For PostgreSQL use UseNpgsql, for MySQL/MariaDB UseMySql — the name is still Default. A connection string for your own PC in appsettings.json does no harm; the environment's value takes its place.
No migrations at start-up
Remove context.Database.Migrate() and EnsureCreated(). The running app gets the runtime login, which cannot create tables. Migrations run before every deploy, in the release (see below).
Health check
By default Meghly expects a 2xx or 3xx answer on / (a redirect to the login page is fine). Your own is better:
builder.Services.AddHealthChecks();
app.MapHealthChecks("/healthz");Then put /healthz in the app's General → Health check.
HTTPS and the visitor's IP
The app runs behind Meghly's router. Meghly sets ASPNETCORE_FORWARDEDHEADERS_ENABLED=true itself, so the app knows the request came over HTTPS and from which IP. app.UseHttpsRedirection() does no harm.
Data Protection keys
Login cookies and antiforgery tokens are protected by keys kept inside the container by default, and the container's file system is read-only. Unless the keys are kept somewhere, everyone is logged out after every deploy and forms show "antiforgery token" errors. Do one of these:
- Keep them in the database (better): the
Microsoft.AspNetCore.DataProtection.EntityFrameworkCorepackage, aDbSet<DataProtectionKey>in your DbContext, a migration, then:csharpbuilder.Services.AddDataProtection().PersistKeysToDbContext<AppDbContext>(); - Keep them on a volume: add a volume on the app's Files & backups page (such as
/app/keys), thenPersistKeysToFileSystem(new DirectoryInfo("/app/keys")).
File uploads
wwwroot/uploads cannot be written to directly. Add a volume at that path in Files & backups (such as /app/wwwroot/uploads), and uploads survive deploys.
Creating the database and the app
- In the panel, Apps → New app → a Git repository or a zip.
- In What is it? choose ASP.NET Core, the version and the Framework (ASP.NET Core API or ASP.NET Core MVC).
- Tick It needs a database; to change the engine, Advanced → Database engine → SQL Server (or PostgreSQL, MySQL, MariaDB).
- Add the variables you need (such as
ASPNETCORE_ENVIRONMENT=Production, API keys). - Deploy. The Detect step shows what it found, such as "ASP.NET Core 10.0 · EF Core migrations found".
SQL Server connections are always encrypted; the certificate is the server's own, so the string Meghly gives has TrustServerCertificate=True — use that one. Everything about databases: Databases.
Migrations: two ways
Pick one, not both.
(a) EF Core migrations. With Microsoft.EntityFrameworkCore.Design (or .Tools) in the web project, the build makes a migration bundle by itself. Before every deploy it runs with the migration login and applies only the migrations not yet applied. You only create migrations and commit them:
dotnet ef migrations add AddOrdersThe bundle runs your Program.cs to build the DbContext, and the release gets all the app's variables — so what start-up needs is there in the release too.
(b) SQL scripts. .sql files in a db/migrations/ folder at the repository's root: 0001_create_orders.sql, 0002_add_index.sql … They run in name order, each once. GO splits batches. The whole script runs in one transaction — on any error nothing is kept and the deploy does not happen. Changing a script that has already run stops the release; add a new script instead.
Connecting with SSMS
SQL Server's port is open only to your app by default. To connect from SSMS or Azure Data Studio:
- In the panel, Databases → choose the database → Remote Access → আমার IP যোগ করো (add my IP), or your office's IP / network → Save allowlist. Up to 20, public IPs only.
- In SSMS:
- Server name:
<host>,<port>as the panel shows it (a comma between). - Authentication: SQL Server Authentication, the migration login (to change the schema).
- Encryption: Mandatory, and tick Trust server certificate.
- Server name:
- When done, remove the IP — the port closes again.
Bringing an old database with a .bak
- On the old SQL Server, take a full backup without encryption:sql
BACKUP DATABASE [MyShop] TO DISK = N'C:\backup\MyShop.bak' WITH COPY_ONLY, CHECKSUM, INIT; - In the panel, Databases → the database → Import .bak file → choose the file → Import .bak.
- Meghly checks that the backup is not from a newer SQL Server than this one (2025), is not encrypted or TDE, has no FILESTREAM, and fits your plan.
The restore replaces your database — the data in it now is lost. The old server's logins (such as sa) do not come along; the app runs with Meghly's runtime login.
The other way round, Download export gives a verified .bak.
When something goes wrong
| What you see | Cause and fix |
|---|---|
| Build: "ASP.NET MVC 5 / .NET Framework" | A Windows-only project — move it to ASP.NET Core. |
| Build: "targets .NET 7" | Set <TargetFramework>net10.0</TargetFramework>. |
Release: CREATE TABLE permission denied | The app runs migrations itself — remove Migrate() / EnsureCreated(). |
| The deploy stops at the health check | Check the app listens on PORT and / (or your path) answers 2xx/3xx; start-up exceptions are in Logs. |
| Everyone is logged out after each deploy | Keep the Data Protection keys (see above). |
certificate chain error | Use the connection string Meghly gives (TrustServerCertificate=True). |
| SSMS: timeout | Check Remote Access has your current IP — home IPs change often. |