Add Docker deployment design spec
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
e14e552388
commit
de82bc0d61
107
docs/superpowers/specs/2026-03-21-docker-deployment-design.md
Normal file
107
docs/superpowers/specs/2026-03-21-docker-deployment-design.md
Normal file
@ -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=<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:** `<host-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
|
||||||
Loading…
Reference in New Issue
Block a user