4.3 KiB
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-webexposes port 3100 to host — NPM points herebudgetapp-webnginx proxies/api/→http://budgetapp-api:8080over internal Docker networkbudgetapp-apiexposes 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=ProductionConnectionStrings__MainDatabase— injected from.envvia 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.htmlfor 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
# 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