Files
LaunchPad/apps/backend/Dockerfile

91 lines
4.3 KiB
Docker

# syntax=docker/dockerfile:1
FROM node:20-alpine AS base
RUN corepack enable
WORKDIR /app
# ---- deps: gesamten Workspace-Kontext installieren -------------------------
FROM base AS deps
COPY pnpm-workspace.yaml package.json pnpm-lock.yaml* tsconfig.base.json ./
COPY packages/shared/package.json packages/shared/package.json
COPY packages/ui/package.json packages/ui/package.json
COPY apps/backend/package.json apps/backend/package.json
COPY apps/frontend/package.json apps/frontend/package.json
# better-sqlite3 braucht Build-Tools für den nativen Modulbau
RUN apk add --no-cache python3 make g++
RUN pnpm install --frozen-lockfile || pnpm install
# ---- build: Backend + Shared bauen ------------------------------------------
FROM deps AS build
COPY packages/shared packages/shared
COPY apps/backend apps/backend
RUN pnpm --filter @launchpad/shared build
RUN pnpm --filter @launchpad/backend build
# nur Production-Dependencies fürs Runtime-Image behalten
RUN pnpm deploy --filter @launchpad/backend --prod /app/deploy
# ---- runtime: schlankes Laufzeit-Image --------------------------------------
FROM node:20-alpine AS runtime
WORKDIR /app
ENV NODE_ENV=production
ENV DATABASE_PATH=/data/launchpad.db
ENV PORT=3001
ENV HOST=0.0.0.0
# node:dns/promises (lookup/reverse, siehe scanner/dns.ts) läuft NICHT über
# normales nicht-blockierendes I/O, sondern über getaddrinfo() im
# Betriebssystem - Node schickt das über den libuv-Threadpool ab, der
# standardmäßig nur 4 Threads hat. Beim Sammel-Scan mit bis zu 10 parallel
# gescannten Geräten (siehe routes/scan.ts CONCURRENT_DEVICES) und je bis zu
# 4 DNS-Abfragen pro Gerät reichte das nicht annähernd und führte zu einem
# Rückstau, der wie ein hängender Sammel-Scan aussah (siehe Bugreport - Scan
# blieb nach erfolgreichem masscan-/httpx-Vorabscan minutenlang in der
# eigentlichen Geräte-Schleife stehen). MUSS hier als Umgebungsvariable
# gesetzt werden, nicht im JS-Code selbst: das Projekt läuft als natives ESM
# ("type": "module"), dort werden alle import-Anweisungen VOR jeglichem
# sonstigen Code im Modul ausgeführt (auch wenn dieser Code textuell davor
# steht) - ein Setzen von process.env.UV_THREADPOOL_SIZE am Dateianfang von
# index.ts käme damit zu spät.
ENV UV_THREADPOOL_SIZE=32
# iputils-ping stellt einen "echten" ping-Befehl mit ICMP-Unterstützung
# bereit (nicht nur die BusyBox-Variante) - für den optionalen Live-Status-
# Heartbeat (siehe src/liveStatus.ts, standardmäßig deaktiviert).
# masscan beschleunigt den vollständigen Portscan (1-65535, siehe
# scanner/masscan.ts) erheblich gegenüber reinem TCP-Connect-Scanning - wird
# automatisch genutzt, falls vorhanden, sonst fällt der Scanner auf die
# eingebaute (langsamere, aber ohne Zusatzrechte auskommende) Methode zurück.
RUN apk add --no-cache iputils-ping masscan
# httpx (ProjectDiscovery) prüft eine Liste offener Ports und liefert NUR
# die, die tatsächlich HTTP/HTTPS sprechen, inkl. Status/Titel/Server-Header
# in einem einzigen, hochparallelen Durchlauf (siehe scanner/httpx.ts) -
# deutlich schneller als eigenes Protokoll-Raten pro Port, und verhindert,
# dass Nicht-Web-Ports (SSH, SMB, NFS, ...) überhaupt erst per HTTP
# angesprochen werden. Kein Alpine-Paket vorhanden, daher als
# Binary-Release von GitHub geladen. Bei Fehlschlag (z. B. kein
# Internetzugang beim Bauen des Images) läuft der Build trotzdem durch -
# der Scanner erkennt ein fehlendes httpx zur Laufzeit automatisch und
# fällt auf die eingebaute Methode zurück.
RUN apk add --no-cache --virtual .httpx-build curl unzip && \
( \
HTTPX_URL=$(curl -fsSL https://api.github.com/repos/projectdiscovery/httpx/releases/latest \
| grep -o 'https://[^"]*httpx_[0-9][^"]*_linux_amd64\.zip' | head -n1) && \
test -n "$HTTPX_URL" && \
curl -fsSL "$HTTPX_URL" -o /tmp/httpx.zip && \
unzip -o /tmp/httpx.zip -d /usr/local/bin httpx && \
chmod +x /usr/local/bin/httpx \
|| echo "httpx-Installation fehlgeschlagen - Scanner nutzt automatisch die eingebaute Methode" \
) && \
rm -f /tmp/httpx.zip && \
apk del .httpx-build
COPY --from=build /app/deploy/ ./
COPY --from=build /app/apps/backend/dist ./dist
COPY --from=build /app/packages/shared/dist ./node_modules/@launchpad/shared/dist
RUN mkdir -p /data
VOLUME ["/data"]
EXPOSE 3001
CMD ["node", "dist/index.js"]