Update Docker deployment spec with reviewer fixes
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
de82bc0d61
commit
256b8e0ce7
@ -27,10 +27,11 @@ Deploy BudgetApp to a home server running Nginx Proxy Manager (NPM) and an exist
|
||||
```
|
||||
|
||||
- `budgetapp-web` exposes **port 3100** to host — NPM points here
|
||||
- `budgetapp-web` nginx proxies `/api/` → `http://budgetapp-api:8080` over internal Docker network
|
||||
- `budgetapp-web` nginx proxies `/api/` → `http://budgetapp-api:8080/` over internal Docker network. Note: the `/api/` prefix is stripped before forwarding (both `location` and `proxy_pass` end with `/`), so the backend must not expect `/api/` in its routes.
|
||||
- `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`
|
||||
- `budgetapp-web` has `depends_on: budgetapp-api` (`condition: service_started`) — nginx will retry failed upstream connections, so waiting for the process to start is sufficient without requiring a full health-check gate
|
||||
|
||||
## Files to Create
|
||||
|
||||
@ -41,13 +42,34 @@ Deploy BudgetApp to a home server running Nginx Proxy Manager (NPM) and an exist
|
||||
| `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 |
|
||||
| `.dockerignore` | Excludes `node_modules/`, `dist/`, `bin/`, `obj/`, `docs/` from build context |
|
||||
|
||||
## 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) |
|
||||
| `appsettings.json` | Connection string already cleared; env var override used at runtime |
|
||||
| `BudgetApp.Api/Program.cs` | Remove or guard `UseHttpsRedirection()` — see below |
|
||||
| `BudgetApp.Web/src/backend/ApiConnector.ts` | Change hardcoded `https://localhost:7244/api/Transactions` to relative path `/api/Transactions` |
|
||||
|
||||
## Required Application Code Changes
|
||||
|
||||
### 1. `ApiConnector.ts` — Relative API URL
|
||||
|
||||
Currently `ApiConnector.ts` hardcodes `https://localhost:7244/api/Transactions`. In Docker this would be baked into the Vite bundle and the browser would try to call `localhost:7244` instead of going through nginx. Change to a relative path `/api/Transactions` so all API calls go through nginx's proxy.
|
||||
|
||||
Any future frontend calls to other endpoints (e.g. `UploadController` at `api/Upload/csv`) must also use relative paths following the same pattern.
|
||||
|
||||
### 2. `Program.cs` — Disable HTTPS Redirection in Production
|
||||
|
||||
`app.UseHttpsRedirection()` is currently active unconditionally. Inside Docker, TLS is terminated at NPM — the API container receives plain HTTP on port 8080. With HTTPS redirection active, nginx's proxy call to `http://budgetapp-api:8080` would receive a 307 redirect and fail. Guard or remove the middleware:
|
||||
|
||||
```csharp
|
||||
if (!app.Environment.IsProduction())
|
||||
{
|
||||
app.UseHttpsRedirection();
|
||||
}
|
||||
```
|
||||
|
||||
## Container Details
|
||||
|
||||
@ -56,10 +78,12 @@ Deploy BudgetApp to a home server running Nginx Proxy Manager (NPM) and an exist
|
||||
- **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
|
||||
- **Runtime port:** 8080 (the `aspnet:8.0` image defaults to port 8080; no `ASPNETCORE_URLS` override required)
|
||||
- **Health check:** `GET /ping` (existing endpoint returns `{ok: true}`)
|
||||
- **Environment variables:**
|
||||
- `ASPNETCORE_ENVIRONMENT=Production`
|
||||
- `ConnectionStrings__MainDatabase` — injected from `.env` via docker-compose
|
||||
- **Note:** Swagger UI is disabled in Production (gated behind `IsDevelopment()` in `Program.cs`). Access `/swagger` by temporarily setting `ASPNETCORE_ENVIRONMENT=Development` if needed.
|
||||
|
||||
### budgetapp-web
|
||||
|
||||
@ -67,27 +91,39 @@ Deploy BudgetApp to a home server running Nginx Proxy Manager (NPM) and an exist
|
||||
- **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/`
|
||||
- **API routing:** nginx proxies `location /api/` → `http://budgetapp-api:8080/` (prefix stripped)
|
||||
- **SPA routing:** `try_files $uri $uri/ /index.html` for Vue Router
|
||||
- **Depends on:** `budgetapp-api`
|
||||
|
||||
## Secrets Management
|
||||
|
||||
A `.env` file at the solution root (gitignored) holds the DB connection string:
|
||||
A `.env` file at the solution root (gitignored) holds the DB connection string using the exact ASP.NET Core env var key format to avoid any mapping indirection in docker-compose:
|
||||
|
||||
```
|
||||
DB_CONNECTION=Server=seth.local;User Id=budget;Password=<password>;Database=budget
|
||||
ConnectionStrings__MainDatabase=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.
|
||||
docker-compose passes this directly as the environment variable to the API container. ASP.NET Core's built-in env var configuration provider resolves double-underscores as nested keys automatically.
|
||||
|
||||
## docker-compose Environment Block (API service)
|
||||
|
||||
```yaml
|
||||
environment:
|
||||
ASPNETCORE_ENVIRONMENT: Production
|
||||
ConnectionStrings__MainDatabase: ${ConnectionStrings__MainDatabase}
|
||||
```
|
||||
|
||||
## Build & Deploy
|
||||
|
||||
```bash
|
||||
# Build and start both containers
|
||||
# On the server, in the project directory
|
||||
docker-compose up -d --build
|
||||
|
||||
# View logs
|
||||
docker-compose logs -f
|
||||
|
||||
# Restart after code changes
|
||||
docker-compose up -d --build
|
||||
```
|
||||
|
||||
## NPM Setup (Manual)
|
||||
@ -99,9 +135,7 @@ After containers are running, add one proxy host in Nginx Proxy Manager:
|
||||
|
||||
No second proxy host needed — API traffic is routed internally by the web container's nginx.
|
||||
|
||||
## What Is NOT Changing
|
||||
## Notes
|
||||
|
||||
- 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
|
||||
- **CORS:** The API has an unconditional `AllowAll` CORS policy. Since all browser traffic reaches the API through nginx's internal proxy, the browser never makes a direct cross-origin request to the API — CORS does not apply to the primary flow. Tightening the CORS policy will have no effect on security in this deployment.
|
||||
- **`.env` is already covered by `.gitignore`** — the root `.gitignore` already includes `.env`, so no additional entry is needed.
|
||||
|
||||
Loading…
Reference in New Issue
Block a user