Dockerfile
Rama main · réplica de lectura del repositorio original.
# syntax=docker/dockerfile:1
#
# Indy, as one image with one port.
#
# deps npm ci against the lockfile
# build the <art-*> primitives, vendored mermaid, next build (standalone)
# extras the packages a compiled artifact may import, from docker/extras
# collab the document server and its dependencies, from the root lockfile
# runtime the app, the document server and the proxy that fronts them both
#
# The extras stage exists because Next's output tracing keeps only the files the
# server itself imports. An artifact's bundle needs whole packages: react-dom's
# traced copy has no client.js, and chart.js, d3 and lucide-react are not traced
# at all. esbuild resolves them at publish time from INDY_BUILD_MODULES. Tailwind
# is there too, with its native scanner, for artifacts that import tailwindcss.
#
# /artifact-kit holds the shadcn components artifacts import as "@/components/ui".
# It sits away from /app so that nothing under it can find the app's own copy
# of React: an artifact must bundle exactly one.
FROM node:24-bookworm-slim AS deps
WORKDIR /src
COPY package.json package-lock.json ./
COPY app/package.json app/package.json
COPY collab/package.json collab/package.json
COPY packages/primitives/package.json packages/primitives/package.json
RUN npm ci --no-audit --no-fund
FROM deps AS build
WORKDIR /src
ENV NEXT_TELEMETRY_DISABLED=1
COPY . .
RUN npm run build:primitives \
&& cd app \
&& node scripts/build-vendor.mjs \
&& npx next build
FROM node:24-bookworm-slim AS extras
WORKDIR /extras
# Pinned with a lockfile; the versions match app/package.json, which
# app/test/deploy.test.ts checks.
COPY docker/extras/package.json docker/extras/package-lock.json ./
RUN npm ci --no-audit --no-fund --omit=dev
FROM node:24-bookworm-slim AS collab
WORKDIR /src
# The document server's dependencies, from the root lockfile like everything
# else, then gathered into one folder beside its server.
COPY package.json package-lock.json ./
COPY app/package.json app/package.json
COPY collab/package.json collab/package.json
COPY packages/primitives/package.json packages/primitives/package.json
RUN npm ci --omit=dev --workspace collab --include-workspace-root=false --no-audit --no-fund \
&& rm -f node_modules/collab \
&& mkdir -p /collab/node_modules \
&& cp -a node_modules/. /collab/node_modules/ \
&& if [ -d collab/node_modules ]; then cp -a collab/node_modules/. /collab/node_modules/; fi \
&& cp collab/package.json /collab/
COPY collab/server.mjs /collab/
FROM node:24-bookworm-slim AS runtime
# The source label links the image on ghcr.io to its repository, which is
# where the package page, its README and its visibility come from.
LABEL org.opencontainers.image.source="https://github.com/liamdmcgarrigle/indy-artifacts" \
org.opencontainers.image.title="Indy" \
org.opencontainers.image.description="A self-hosted place for coding agents to publish pages you read, edit, comment on and share." \
org.opencontainers.image.licenses="AGPL-3.0-or-later"
ENV NODE_ENV=production \
NEXT_TELEMETRY_DISABLED=1 \
PORT=1936 \
INDY_DATA=/data \
INDY_TMP=/data/tmp \
INDY_BUILD_MODULES=/artifact-modules/node_modules:/app/node_modules \
INDY_ARTIFACT_KIT=/artifact-kit \
INDY_APP_ENTRY=/app/app/server.js \
INDY_COLLAB_ENTRY=/app/collab/server.mjs
WORKDIR /app
# The standalone output mirrors the repo, so the server is at app/server.js.
COPY --from=build /src/app/.next/standalone ./
COPY --from=build /src/app/.next/static ./app/.next/static
COPY --from=build /src/app/public ./app/public
COPY --from=extras /extras/node_modules /artifact-modules/node_modules
COPY --from=build /src/app/src/components/ui /artifact-kit/components/ui
COPY --from=build /src/app/src/lib/utils.ts /artifact-kit/lib/utils.ts
COPY --from=collab /collab ./collab
COPY start.mjs proxy.mjs ./
# The node image's own user (uid 1000) owns the data folder. A named volume
# picks that ownership up on first use.
RUN mkdir -p /data/tmp && chown -R node:node /data
USER node
VOLUME /data
EXPOSE 1936
HEALTHCHECK --interval=30s --timeout=5s --start-period=40s --retries=3 \
CMD node -e "fetch('http://127.0.0.1:'+(process.env.PORT||1936)+'/api/health').then(r=>process.exit(r.ok?0:1),()=>process.exit(1))"
CMD ["node", "/app/start.mjs"]