# syntax=docker/dockerfile:1 # # One image, two roles. RUN_MODE (web|worker) selects the binary at the entrypoint. # Build context is the repo root (see docker-compose.yml: context: ..). # Base images are pulled through Soroush's Nexus Docker proxy group (mirror.soroushasadi.com), # reachable from Iran. To build against public registries instead, replace the mirror prefixes # with docker.io/library (node) and mcr.microsoft.com (dotnet). # ---- Stage 1: build the React/Vite SPA ---- FROM mirror.soroushasadi.com/node:22-bookworm-slim AS client WORKDIR /client COPY client/package.json client/package-lock.json ./ RUN npm ci COPY client/ ./ RUN npm run build # ---- Stage 2: restore + publish BOTH hosts into /app ---- FROM mirror.soroushasadi.com/dotnet/sdk:10.0 AS build WORKDIR /src COPY Directory.Build.props Directory.Packages.props nuget.config global.json ./ COPY src/ ./src/ RUN dotnet restore src/Hosts/TeamUp.Web/TeamUp.Web.csproj RUN dotnet restore src/Hosts/TeamUp.Worker/TeamUp.Worker.csproj # Skip the web project's npm client target (-p:BuildClient=false) — the SPA is built in stage 1. RUN dotnet publish src/Hosts/TeamUp.Web/TeamUp.Web.csproj -c Release -o /app --no-restore -p:BuildClient=false RUN dotnet publish src/Hosts/TeamUp.Worker/TeamUp.Worker.csproj -c Release -o /app --no-restore # Drop the built SPA into the served wwwroot. COPY --from=client /client/dist /app/wwwroot # ---- Stage 3: runtime ---- # aspnet:10.0 (Ubuntu Noble) has a shell so the entrypoint can branch on RUN_MODE, and avoids any # tag-availability risk. For prod you can switch to a chiseled tag and select the role via the # container command/args instead (chiseled images have no shell). FROM mirror.soroushasadi.com/dotnet/aspnet:10.0 AS final WORKDIR /app COPY --from=build /app ./ COPY docker/entrypoint.sh /app/entrypoint.sh RUN chmod +x /app/entrypoint.sh ENV RUN_MODE=web \ ASPNETCORE_HTTP_PORTS=8080 EXPOSE 8080 USER $APP_UID ENTRYPOINT ["/app/entrypoint.sh"]