From de82bc0d612ec861e081d8ed5a20fff986088a09 Mon Sep 17 00:00:00 2001 From: Martin Svrcina Date: Sat, 21 Mar 2026 02:24:42 +0100 Subject: [PATCH] Add Docker deployment design spec Co-Authored-By: Claude Sonnet 4.6 --- .../2026-03-21-docker-deployment-design.md | 107 ++++++++++++++++++ 1 file changed, 107 insertions(+) create mode 100644 docs/superpowers/specs/2026-03-21-docker-deployment-design.md diff --git a/docs/superpowers/specs/2026-03-21-docker-deployment-design.md b/docs/superpowers/specs/2026-03-21-docker-deployment-design.md new file mode 100644 index 0000000..7067d74 --- /dev/null +++ b/docs/superpowers/specs/2026-03-21-docker-deployment-design.md @@ -0,0 +1,107 @@ +# Docker Deployment Design + +**Date:** 2026-03-21 +**Project:** BudgetApp + +## Overview + +Deploy BudgetApp to a home server running Nginx Proxy Manager (NPM) and an existing MySQL instance. Two Docker containers are orchestrated via docker-compose: one for the .NET 8 API and one for the Vue 3 frontend served by nginx. + +## Architecture + +``` +┌─────────────────────────────────────────────┐ +│ docker-compose.yml │ +│ │ +│ ┌──────────────────┐ ┌──────────────────┐ │ +│ │ budgetapp-web │ │ budgetapp-api │ │ +│ │ (nginx + Vue) │──▶ (.NET 8 API) │ │ +│ │ port 3100:80 │ │ port 8080:8080 │ │ +│ └──────────────────┘ └──────────────────┘ │ +│ internal network: budgetapp │ +└─────────────────────────────────────────────┘ + │ │ + ▼ ▼ + NPM proxy host seth.local MySQL + (one entry) (existing) +``` + +- `budgetapp-web` exposes **port 3100** to host — NPM points here +- `budgetapp-web` nginx proxies `/api/` → `http://budgetapp-api:8080` over internal Docker network +- `budgetapp-api` exposes **port 8080** (optional, for direct access/debugging) +- Both containers share a Docker bridge network named `budgetapp` +- API connects to the existing MySQL at `seth.local` + +## Files to Create + +| File | Purpose | +|------|---------| +| `Dockerfile.api` | Multi-stage .NET 8 build — solution root as context | +| `Dockerfile.web` | Multi-stage Node/Vite build + nginx runtime | +| `docker-compose.yml` | Wires containers, network, port mappings, env vars | +| `nginx.web.conf` | nginx config — serves static files, proxies `/api/` to API container | +| `.env` | Gitignored secrets file — DB connection string | + +## Files to Modify + +| File | Change | +|------|--------| +| `appsettings.json` | Connection string already cleared; env var override `ConnectionStrings__MainDatabase` used at runtime | +| `.gitignore` | Add `.env` entry (already present) | + +## Container Details + +### budgetapp-api + +- **Base images:** `mcr.microsoft.com/dotnet/sdk:8.0` (build) → `mcr.microsoft.com/dotnet/aspnet:8.0` (runtime) +- **Build context:** Solution root (required — API references sibling projects) +- **Publish target:** `BudgetApp.Api/BudgetApp.Api.csproj` +- **Runtime port:** 8080 +- **Environment variables:** + - `ASPNETCORE_ENVIRONMENT=Production` + - `ConnectionStrings__MainDatabase` — injected from `.env` via docker-compose + +### budgetapp-web + +- **Base images:** `node:20-alpine` (build) → `nginx:alpine` (runtime) +- **Build context:** `BudgetApp.Web/` +- **Build output:** `dist/` copied into nginx image +- **Runtime port:** 80 (mapped to host port 3100) +- **API routing:** nginx proxies `location /api/` → `http://budgetapp-api:8080/` +- **SPA routing:** `try_files $uri $uri/ /index.html` for Vue Router + +## Secrets Management + +A `.env` file at the solution root (gitignored) holds the DB connection string: + +``` +DB_CONNECTION=Server=seth.local;User Id=budget;Password=;Database=budget +``` + +docker-compose passes this as the `ConnectionStrings__MainDatabase` environment variable to the API container. ASP.NET Core's built-in environment variable configuration provider resolves double-underscores as nested keys, so no code changes are required. + +## Build & Deploy + +```bash +# Build and start both containers +docker-compose up -d --build + +# View logs +docker-compose logs -f +``` + +## NPM Setup (Manual) + +After containers are running, add one proxy host in Nginx Proxy Manager: +- **Domain:** `budget.yourdomain.com` (or local DNS name) +- **Forward hostname/IP:** `` +- **Forward port:** `3100` + +No second proxy host needed — API traffic is routed internally by the web container's nginx. + +## What Is NOT Changing + +- No changes to application code +- No changes to EF Core migrations (database already exists) +- No changes to JWT auth configuration +- Vue frontend API calls use relative `/api/` paths — no build-time URL baking needed