From 95946a4349273ce96ddc60076e8d8e0455734881 Mon Sep 17 00:00:00 2001 From: tleininger Date: Sun, 20 Sep 2026 23:00:47 +0200 Subject: [PATCH] Add Docker setup and fix proxy config for containerized deployment - Program.cs: remove UseHsts/UseHttpsRedirection (NPM terminates TLS, would loop behind the proxy, plan.md AE-4), add UseForwardedHeaders with emptied known networks/proxies. Uses KnownIPNetworks (net10). - Dockerfile: SDK build stage, chiseled aspnet runtime on port 8080. - .dockerignore: keep build output, git and docs out of the image. - compose.yaml: temporary test setup (builds from source, exposes 5000:8080) for the first run on Unraid without NPM or registry. - .gitignore: exclude .idea/ (Rider project files). Co-Authored-By: Claude Opus 4.8 --- .dockerignore | 22 ++++++++++++++++++++++ .gitignore | 3 ++- Dockerfile | 22 ++++++++++++++++++++++ Elternbeirat.Web/Program.cs | 21 +++++++++++++++++---- compose.yaml | 24 ++++++++++++++++++++++++ 5 files changed, 87 insertions(+), 5 deletions(-) create mode 100644 .dockerignore create mode 100644 Dockerfile create mode 100644 compose.yaml diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..c6a6ce6 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,22 @@ +# Build-Ausgaben (werden im Container frisch erzeugt) +**/bin/ +**/obj/ +**/out/ + +# IDE- und Tooling-Kram +.vs/ +.idea/ +.vscode/ + +# Versionskontrolle und Doku, im Image nicht benoetigt +.git/ +.gitea/ +.gitignore +.gitattributes +docs/ +*.md + +# Docker-Dateien selbst +Dockerfile +.dockerignore +compose.yaml diff --git a/.gitignore b/.gitignore index add57be..f400df3 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,5 @@ bin/ obj/ /packages/ riderModule.iml -/_ReSharper.Caches/ \ No newline at end of file +/_ReSharper.Caches/ +.idea/ \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..2ed2661 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,22 @@ +# syntax=docker/dockerfile:1 + +# --- Build-Stufe: SDK-Image kompiliert und published die App --- +FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build +WORKDIR /src + +# Zuerst nur die csproj kopieren und restoren, damit der NuGet-Restore-Layer +# gecacht bleibt, solange sich die Abhaengigkeiten nicht aendern. +COPY Elternbeirat.Web/Elternbeirat.Web.csproj Elternbeirat.Web/ +RUN dotnet restore Elternbeirat.Web/Elternbeirat.Web.csproj + +# Dann der restliche Quellcode. +COPY . . +RUN dotnet publish Elternbeirat.Web/Elternbeirat.Web.csproj -c Release -o /app + +# --- Runtime-Stufe: schlankes chiseled-Image, laeuft als non-root (UID 1654), +# hoert auf Port 8080, enthaelt keine Shell (kein HEALTHCHECK mit curl/sh). --- +FROM mcr.microsoft.com/dotnet/aspnet:10.0-noble-chiseled AS runtime +WORKDIR /app +COPY --from=build /app . +EXPOSE 8080 +ENTRYPOINT ["dotnet", "Elternbeirat.Web.dll"] diff --git a/Elternbeirat.Web/Program.cs b/Elternbeirat.Web/Program.cs index 9176337..9bdcf2f 100644 --- a/Elternbeirat.Web/Program.cs +++ b/Elternbeirat.Web/Program.cs @@ -1,4 +1,5 @@ using Elternbeirat.Web.Components; +using Microsoft.AspNetCore.HttpOverrides; var builder = WebApplication.CreateBuilder(args); @@ -7,20 +8,32 @@ builder.Services.AddRazorComponents(); var app = builder.Build(); +// NPM terminiert TLS und ist der einzige Weg zum Container (kein Port-Mapping +// im Produktivbetrieb, siehe plan.md AE-4). Ohne UseForwardedHeaders sieht die +// App jede Anfrage als HTTP und mit der Proxy-IP statt der Client-IP. +// KnownNetworks/KnownProxies bewusst geleert, weil ausschliesslich NPM den +// Container erreicht. +app.UseForwardedHeaders(new ForwardedHeadersOptions +{ + ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto, + KnownIPNetworks = { }, + KnownProxies = { } +}); + // Configure the HTTP request pipeline. if (!app.Environment.IsDevelopment()) { app.UseExceptionHandler("/Error", createScopeForErrors: true); - // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts. - app.UseHsts(); + // Kein UseHsts() und kein UseHttpsRedirection(): NPM setzt HSTS und + // terminiert TLS. Beides hier wuerde hinter dem Proxy eine + // Redirect-Schleife erzeugen (plan.md AE-4). } app.UseStatusCodePagesWithReExecute("/not-found", createScopeForStatusCodePages: true); -app.UseHttpsRedirection(); app.UseAntiforgery(); app.MapStaticAssets(); app.MapRazorComponents(); -app.Run(); \ No newline at end of file +app.Run(); diff --git a/compose.yaml b/compose.yaml new file mode 100644 index 0000000..8ed255e --- /dev/null +++ b/compose.yaml @@ -0,0 +1,24 @@ +# TEST-Setup fuer den ersten Lauf auf Unraid (ohne NPM, ohne Registry). +# +# Weicht bewusst vom Produktiv-Setup in plan.md Abschnitt 8 ab: +# - Das Image wird hier direkt aus dem Quellcode gebaut (build:), statt aus +# der Gitea-Registry gezogen. Spart Registry + Token fuer den ersten Test. +# - Es gibt ein Port-Mapping (5000 aussen -> 8080 innen), damit die App im +# lokalen Netz unter http://:5000 erreichbar ist. Im Produktiv- +# betrieb entfaellt das Mapping; dort ist nur NPM der Weg zum Container. +# +# Sobald NPM steht, wird diese Datei durch das Produktiv-compose ersetzt. + +services: + eb-web: + build: + context: . + dockerfile: Dockerfile + image: elternbeirat-web:test + container_name: eb-web + restart: unless-stopped + environment: + ASPNETCORE_URLS: http://+:8080 + TZ: Europe/Berlin + ports: + - "5000:8080" # TEST-Zugang, im Produktivbetrieb entfernen