# 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