# --------------------------------------------------------------- CSS --- # Tailwind über die Standalone-Binärdatei - kein Node.js, kein npm. Das # Ergebnis ist eine einzige style.css; die Binärdatei bleibt in dieser # Stufe und landet nicht im fertigen Image. FROM debian:bookworm-slim AS css RUN apt-get update && apt-get install -y --no-install-recommends curl ca-certificates \ && rm -rf /var/lib/apt/lists/* WORKDIR /build ARG TAILWIND_VERSION=v3.4.17 RUN curl -sSLo /usr/local/bin/tailwindcss \ "https://github.com/tailwindlabs/tailwindcss/releases/download/${TAILWIND_VERSION}/tailwindcss-linux-x64" \ && chmod +x /usr/local/bin/tailwindcss COPY tailwind.config.js tailwind-input.css ./ COPY app/templates ./app/templates RUN tailwindcss -c tailwind.config.js -i tailwind-input.css -o /build/style.css --minify # ----------------------------------------------------------- Anwendung --- FROM python:3.11-slim # libheif wird von pillow-heif mitgeliefert; hier nur die Laufzeit-Bibliotheken, # die Pillow für JPEG/PNG/WebP braucht. RUN apt-get update && apt-get install -y --no-install-recommends \ curl \ && rm -rf /var/lib/apt/lists/* WORKDIR /app COPY requirements.txt ./ RUN pip install --no-cache-dir -r requirements.txt COPY alembic.ini ./ COPY alembic/ ./alembic/ COPY app/ ./app/ COPY --from=css /build/style.css ./app/static/style.css COPY docker-entrypoint.sh /usr/local/bin/kleiderboerse-entrypoint.sh RUN chmod +x /usr/local/bin/kleiderboerse-entrypoint.sh # Datenbank und Bilder liegen in Volumes, ausserhalb des Codes. ENV DATABASE_PATH=/data/kleiderboerse.sqlite \ UPLOAD_PATH=/uploads \ PYTHONUNBUFFERED=1 # Nicht als root laufen. Die beiden Verzeichnisse gehören dem Dienstbenutzer, # der Code dagegen root - so kann der Webdienst seinen eigenen Code nicht # überschreiben. RUN useradd --system --create-home --shell /usr/sbin/nologin kleider \ && mkdir -p /data /uploads \ && chown kleider:kleider /data /uploads USER kleider EXPOSE 8000 HEALTHCHECK --interval=30s --timeout=5s --start-period=20s --retries=3 \ CMD curl -fsS http://localhost:8000/health || exit 1 ENTRYPOINT ["kleiderboerse-entrypoint.sh"] # --proxy-headers: hinter einem Reverse-Proxy stünde sonst dessen IP in # jedem Rate-Limit, und ein einzelner Besucher sperrte alle anderen aus. # Ausserdem erkennt die App darüber, ob der Browser per HTTPS verbunden ist. CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000", \ "--proxy-headers", "--forwarded-allow-ips", "*"]