-
Notifications
You must be signed in to change notification settings - Fork 0
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. In production it can be:
- a container owned by the production Compose file
- a managed SQL Server instance
- an externally maintained shared SQL Server
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
v
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.
Unlike some larger deployments, the current workflow does not SSH into the server. The intended operating model is:
- GitHub Actions builds and publishes the WebApp image.
- The production server pulls the image.
- The production server restarts the WebApp container through Docker Compose.
This keeps deployment credentials out of GitHub Actions and matches the current repository setup.
| File | Purpose |
|---|---|
.github/workflows/deploy.yml |
Builds and pushes the WebApp image to GHCR |
infra/Dockerfile.webapp |
Multi-stage .NET build for UncannyPrompt.WebApp
|
infra/deploy.sh |
Routine production rollout of the WebApp container only |
infra/bootstrap.sh |
First bootstrap or full stack refresh |
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 |
src/UncannyPrompt.WebApp/appsettings.json |
Runtime defaults, including ReverseProxy forwarded-header settings |
The default production topology is intentionally small:
Browser
-> Nginx / reverse proxy / TLS termination
-> UncannyPrompt.WebApp
-> SQL Server
The production example in docker-compose.prod.example.yml is a convenient baseline, not a mandatory final shape. You can keep SQL Server in the same Compose project, or omit it and point Database__Host / Database__Port to a centralized SQL Server.
This section describes a generic Ubuntu-based flow. Exact details depend on whether SQL Server is local to the same host or provided externally.
- Ubuntu 22.04 LTS or later
- Docker Engine and Docker Compose plugin installed
- A DNS record pointed at the server IP
- A GitHub account able to pull the published GHCR package, if the package is private
If needed, verify Docker Compose is available:
docker compose versionCreate the deployment directory on the server:
mkdir -p /var/www/uncannyprompt
cd /var/www/uncannypromptCreate the real production Compose file from the example:
cp docker-compose.prod.example.yml docker-compose.ymlCreate a production .env with real values. Do not commit this file.
Important production values include:
DOTNET_ENVIRONMENT=Production-
Database__Host,Database__Port,Database__Name,Database__Username,Database__Password -
Database__TrustServerCertificate=falsewhen production SQL Server uses a valid certificate -
Database__ApplyMigrationsOnStartup=falseif migrations are applied out-of-band - provider credentials under
Authentication__Google__*,Authentication__EntraId__*,Authentication__GitHub__* -
SeedOptions__AdminUsers__0__*for the first platform admin, when needed
If the GHCR package is private, authenticate the server before pulling:
echo "<github-token>" | docker login ghcr.io -u <github-user> --password-stdinThen bootstrap the stack:
docker compose pull
docker compose up -d
docker compose logs -f webappEquivalent helper:
./infra/bootstrap.sh /var/www/uncannypromptInstall Nginx and Certbot:
sudo apt install -y nginx certbot python3-certbot-nginxCreate /etc/nginx/sites-available/uncannyprompt:
server {
server_name uncannyprompt.com;
location / {
proxy_pass http://localhost:8080;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection keep-alive;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_cache_bypass $http_upgrade;
client_max_body_size 10m;
}
}Enable the site and request the TLS certificate:
sudo ln -s /etc/nginx/sites-available/uncannyprompt /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx
sudo certbot --nginx -d uncannyprompt.comThe repository currently supports one deployment mode directly:
Standard application deploy after a new image has been published:
cd /var/www/uncannyprompt
docker compose pull webapp
docker compose up -d --no-deps --remove-orphans webapp
docker image prune -fEquivalent helper:
./infra/deploy.sh /var/www/uncannypromptFirst bootstrap or full stack refresh:
cd /var/www/uncannyprompt
docker compose pull
docker compose up -d --remove-orphans
docker image prune -fIf you later want GitHub Actions to SSH into the server and run these commands automatically, that can be added as a future extension, but it is not part of the current workflow.
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 the server-local docker-compose.yml if they publish under a different owner.
Recommended flow:
- Let GitHub Actions build and publish the WebApp image.
- Apply EF migrations against the production database.
- Pull and deploy the new WebApp version.
- Verify
/health. - Check logs for migration, configuration, and authentication errors.
Avoid running schema-changing migrations automatically at startup in production unless the deployment platform guarantees singleton startup and controlled rollback behavior.
| Symptom | Check |
|---|---|
docker pull returns unauthorized
|
The GHCR package is private or the server is not logged in |
| WebApp exits immediately | Inspect docker compose logs webapp and verify .env values |
| Database connection fails | Check Database__Host, Database__Port, credentials, SQL Server reachability, and certificate settings |
| Login provider missing | Provider client id/secret/tenant settings are incomplete |
Google login returns redirect_uri_mismatch
|
Verify the public callback URL is https://<domain>/signin-google and register that exact URI in Google Cloud Console |
| 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 |