Skip to content

Deployment

Valerio edited this page Apr 28, 2026 · 3 revisions

Deployment

UncannyPrompt is packaged as one WebApp container plus SQL Server. The development reference is docker-compose.yml; production can start from docker-compose.prod.example.yml, which uses the pre-built WebApp image from GHCR.

Topology

Browser / API caller
  -> reverse proxy / TLS termination
  -> UncannyPrompt.WebApp
  -> SQL Server

The MVP has no background worker and no external search engine. All application behavior runs in the WebApp process.

Development Docker Compose

Bring the stack up:

docker compose up --build -d
docker compose logs -f webapp

Services:

Service Purpose
webapp ASP.NET Core Razor Pages and API host
sqlserver SQL Server database

Compose reads .env from the repository root. See Configuration for the key naming convention.

The Compose project name is defined by:

COMPOSE_PROJECT_NAME=uncannyprompt
DOTNET_ENVIRONMENT=Development
ASPNETCORE_URLS=http://+:8080

This keeps generated container, network, and volume names stable across local folders, and makes the runtime environment and WebApp container listener explicit.

Production Docker Compose

The production example is intentionally a starting point, not a mandatory topology.

cp docker-compose.prod.example.yml docker-compose.yml

The real production docker-compose.yml should stay local to the server. The example differs from the development stack in a few important ways:

Concern Development Production example
WebApp image built locally from infra/Dockerfile.webapp pulled from ghcr.io/ryadel/uncannyprompt-webapp:latest
Restart policy developer-controlled restart: unless-stopped
SQL Server port configurable host bind bound to 127.0.0.1
Data Protection keys container-local unless configured persisted in the dataprotection-keys volume

Standard production startup:

docker compose pull
docker compose up -d

Application-only rollout after CI publishes a new image:

docker compose pull webapp
docker compose up -d --no-deps --remove-orphans webapp
docker image prune -f

The same routine is wrapped by infra/deploy.sh. First-time bootstrap or full stack refresh is wrapped by infra/bootstrap.sh.

See CI/CD for the full build-and-pull flow.

Container image

infra/Dockerfile.webapp builds and publishes src/UncannyPrompt.WebApp/UncannyPrompt.WebApp.csproj using a multi-stage .NET 10 image.

The runtime container listens on:

http://+:8080

The published host port is configured by:

Docker__WebAppPort=8080

Reverse proxy

In production, terminate TLS in front of the WebApp with a reverse proxy or platform ingress.

Recommended controls:

  • terminate HTTPS before traffic reaches the app;
  • set DOTNET_ENVIRONMENT=Production;
  • preserve X-Forwarded-Proto and X-Forwarded-For if hosted behind a proxy;
  • restrict direct access to SQL Server from outside the private network.

The app already enables HTTPS redirect and HSTS outside development.

Production configuration checklist

  • Use production-grade SQL Server credentials, and prefer a dedicated application login when connecting to a shared or managed SQL Server instance.
  • Store Database:Password, Security:SecretEncryptionKey, Security:ApiKeyHashKey, and provider client secrets in a secret manager or orchestrator-level environment variables.
  • Set complete provider settings only for the sign-in methods you want enabled.
  • Use real Entra ID redirect URLs matching Authentication:EntraId:CallbackPath.
  • Rotate API/hash/encryption keys using an explicit migration plan when existing protected data exists.
  • Database:ApplyMigrationsOnStartup=false; apply EF migrations out-of-band before deploying new application versions.
  • Keep .env out of production images and source control.
  • Keep the production docker-compose.yml server-local. Commit only docker-compose.prod.example.yml.
  • Persist Data Protection keys if more than one WebApp instance exists, or when container replacement must not invalidate cookies.

Scaling

webapp can be scaled horizontally behind a load balancer, but production deployments must account for:

Concern Requirement
Cookie/session protection shared ASP.NET Data Protection key ring for multiple instances
Database concurrency SQL Server sized for listing/search/audit workload
Public links shared database is enough; tokens are stateless from the WebApp perspective
Rate limiting current fixed-window limiters are per-process; use an external limiter for strict cluster-wide limits

Backup and recovery

SQL Server is the system of record. Back up:

  • full database backups;
  • transaction logs for point-in-time restore;
  • migration history;
  • operational .env/secret inventory outside source control.

The most important tables for recovery validation are prompts, versions, variables, share grants, public links, users, memberships, and audit events.

Rolling deployments

Recommended flow:

  1. Let GitHub Actions build and publish the WebApp image.
  2. Apply EF migrations against the production database.
  3. Deploy the new WebApp version.
  4. Verify /health.
  5. Check logs for migration/configuration/authentication errors.

Avoid running schema-changing migrations automatically at startup in production unless the deployment platform guarantees singleton startup and rollback behavior.

Clone this wiki locally