FROM node:22-slim AS builder WORKDIR /ghostfolio RUN apt-get update && apt-get install -y --no-install-suggests \ g++ \ git \ make \ openssl \ python3 \ && rm -rf /var/lib/apt/lists/* COPY ./.config .config/ COPY ./CHANGELOG.md CHANGELOG.md COPY ./LICENSE LICENSE COPY ./package.json package.json COPY ./package-lock.json package-lock.json COPY ./prisma/schema.prisma prisma/ RUN npm install COPY ./apps apps/ COPY ./libs libs/ COPY ./jest.config.ts jest.config.ts COPY ./jest.preset.js jest.preset.js COPY ./nx.json nx.json COPY ./replace.build.mjs replace.build.mjs COPY ./tsconfig.base.json tsconfig.base.json ENV NX_DAEMON=false RUN npm run build:production # Prepare dist with node_modules WORKDIR /ghostfolio/dist/apps/api COPY ./package-lock.json /ghostfolio/dist/apps/api/ RUN npm install RUN npm install @langfuse/otel @opentelemetry/sdk-node --save 2>/dev/null || true COPY .config /ghostfolio/dist/apps/api/.config/ COPY prisma /ghostfolio/dist/apps/api/prisma/ COPY package.json /ghostfolio/dist/apps/api/ RUN npm run database:generate-typings # Copy agent chat HTML and assets to dist RUN cp /ghostfolio/apps/api/src/app/agent/agent-chat.html /ghostfolio/dist/apps/api/ 2>/dev/null || true RUN mkdir -p /ghostfolio/dist/apps/api/assets && \ cp /ghostfolio/apps/api/src/assets/ghostfolio_squash.webm /ghostfolio/dist/apps/api/assets/ 2>/dev/null || true # Runtime image FROM node:22-slim ENV NODE_ENV=production ENV TZ=UTC RUN apt-get update && apt-get install -y --no-install-suggests \ curl \ openssl \ && rm -rf /var/lib/apt/lists/* COPY --chown=node:node --from=builder /ghostfolio/dist/apps /ghostfolio/apps/ COPY --chown=node:node ./docker/entrypoint-railway.sh /ghostfolio/entrypoint.sh RUN chmod +x /ghostfolio/entrypoint.sh WORKDIR /ghostfolio/apps/api EXPOSE ${PORT:-3333} USER node CMD [ "/ghostfolio/entrypoint.sh" ]