Dockerfile
Rama main · réplica de lectura del repositorio original.
# nextrmnl as a single container.
#
# Two stages: the interface is built first, then only the finished files go into the image. Node and
# node_modules stay out; at runtime FastAPI serves the built files itself.
# --- Stage 1: build the interface ------------------------------------------------------------------
#
# --platform=$BUILDPLATFORM: the image is built for amd64 and arm64. Without it this stage would run under
# emulation too, and "npm ci" under emulated ARM is very slow. Only /build/dist moves on from here.
FROM --platform=$BUILDPLATFORM node:22-alpine AS interface
WORKDIR /build
COPY frontend/package.json frontend/package-lock.json ./
RUN npm ci
COPY frontend/ ./
RUN npm run build
# --- Stage 2: runtime ------------------------------------------------------------------------------
FROM python:3.13-slim
ENV PYTHONUNBUFFERED=1 \
PYTHONDONTWRITEBYTECODE=1 \
NEXTRMNL_DATA_DIR=/data \
NEXTRMNL_FRONTEND_DIST=/app/static
WORKDIR /app
# curl for the healthcheck, gosu to drop root at start.
RUN apt-get update \
&& apt-get install -y --no-install-recommends curl gosu \
&& rm -rf /var/lib/apt/lists/*
COPY backend/requirements.txt ./
RUN pip install --no-cache-dir -r requirements.txt
COPY backend/app ./app
COPY --from=interface /build/dist ./static
# The user nextrmnl runs as. The container starts as root and drops the rights in the entrypoint.
RUN useradd --system --create-home --uid 1000 nextrmnl \
&& mkdir -p /data \
&& chown -R nextrmnl:nextrmnl /data /app
COPY docker/entrypoint.sh /entrypoint.sh
# Strips Windows line endings: checked out on Windows the script would not start otherwise.
RUN sed -i 's/\r$//' /entrypoint.sh && chmod +x /entrypoint.sh
VOLUME ["/data"]
EXPOSE 8000
HEALTHCHECK --interval=30s --timeout=5s --start-period=20s --retries=3 \
CMD curl -fsS "http://127.0.0.1:${NEXTRMNL_PORT:-8000}/api/health" || exit 1
# One worker: SQLite, the open vaults live in this process, and a WebSocket session belongs to one process.
ENTRYPOINT ["/entrypoint.sh"]
# --no-proxy-headers: which proxies may speak for a sender, and say https, is decided by NEXTRMNL_TRUSTED_PROXIES
# inside the app and by nothing else (uvicorn on its own would believe 127.0.0.1), so that nobody is trusted
# from the start and nobody can dodge the sign-in brake with a made-up X-Forwarded-For.
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--workers", "1", "--no-proxy-headers"]