Skip to content
Valerio edited this page Apr 27, 2026 · 3 revisions

CI/CD

UncannyPrompt ships with a GitHub Actions pipeline that builds the WebApp container image and pushes it to the GitHub Container Registry (ghcr.io).

The pipeline publishes only the application image:

ghcr.io/<owner>/uncannyprompt-webapp

SQL Server is not built or published by this pipeline. It can run as a container from the production Compose file, as a managed database, or as an externally maintained SQL Server instance.

Pipeline overview

The workflow is defined in .github/workflows/deploy.yml and triggers on every push to main, or manually from the GitHub Actions tab.

Developer machine
  -> git push main
  -> GitHub Actions
  -> docker build
  -> ghcr.io/<owner>/uncannyprompt-webapp:latest

The workflow also publishes immutable sha-* tags. The latest tag is emitted only for the default branch.

Key files

File Purpose
.github/workflows/deploy.yml Builds and pushes the WebApp image to GHCR
Dockerfile Multi-stage .NET build for UncannyPrompt.WebApp
docker-compose.prod.example.yml Production Compose starting point using the pre-built GHCR image
docker-compose.yml Development Compose stack that builds locally
.env.example Template for runtime configuration

Production deployment model

The intended deployment model is simple:

  1. GitHub Actions builds and publishes the WebApp image.
  2. The production server pulls the image.
  3. The server restarts the WebApp container through Docker Compose.

The workflow does not SSH into the server. This keeps deployment credentials out of GitHub Actions and matches the current operating model: build in CI, pull from the server.

First production setup

On the server:

mkdir -p /var/www/uncannyprompt
cd /var/www/uncannyprompt

Copy docker-compose.prod.example.yml from the repository and save it as the real production Compose file:

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

Create a production .env with real values. Do not commit this file.

If the GHCR package is private, authenticate the server before pulling:

echo "<github-token>" | docker login ghcr.io -u <github-user> --password-stdin

Then start the stack:

docker compose -f docker-compose.prod.yml pull
docker compose -f docker-compose.prod.yml up -d

Subsequent deployments

After a new image has been published:

cd /var/www/uncannyprompt
docker compose -f docker-compose.prod.yml pull webapp
docker compose -f docker-compose.prod.yml up -d --no-deps --remove-orphans webapp
docker image prune -f

If the Compose file also owns SQL Server and you need a full stack refresh:

docker compose -f docker-compose.prod.yml pull
docker compose -f docker-compose.prod.yml up -d --remove-orphans
docker image prune -f

Image naming

The workflow lowercases the repository owner before composing the GHCR image name. For the Ryadel repository, the production example currently points to:

ghcr.io/ryadel/uncannyprompt-webapp:latest

Forks or private deployments should update docker-compose.prod.yml if they publish under a different owner.

Troubleshooting

Symptom Check
docker pull returns unauthorized The GHCR package is private or the server is not logged in
WebApp exits immediately Inspect docker compose -f docker-compose.prod.yml logs webapp and verify .env values
Database connection fails Check Database__Host, Database__Port, credentials, and SQL Server reachability
Login provider missing Provider client id/secret/tenant settings are incomplete
Entra login callback fails Verify Authentication__EntraId__CallbackPath and the app registration reply URL
New migrations are not applied Run EF migrations out-of-band or explicitly enable startup migrations only for controlled environments

Clone this wiki locally