# # Dockerfile.node - nodejs Only # # This Dockerfile builds only the nodejs (Node.js app) without Django, frontend, or other PostHog components. # Use this for running standalone Node.js plugin server instances. # # # Build stage: Compile nodejs and dependencies # FROM ghcr.io/posthog/rust-node-container:bookworm_rust_1.91-node_24.22.1 AS nodejs-build # Compile and install system dependencies # Add Confluent's client repository for librdkafka 2.12.0 RUN apt-get update && \ apt-get install -y --no-install-recommends \ "wget" \ "gnupg" \ && \ mkdir -p /etc/apt/keyrings && \ wget -qO - https://packages.confluent.io/clients/deb/archive.key | gpg --dearmor -o /etc/apt/keyrings/confluent-clients.gpg && \ echo "deb [signed-by=/etc/apt/keyrings/confluent-clients.gpg] https://packages.confluent.io/clients/deb/ bookworm main" > /etc/apt/sources.list.d/confluent-clients.list && \ apt-get update && \ apt-get install -y --no-install-recommends --allow-downgrades \ "make" \ "g++" \ "gcc" \ "python3" \ "librdkafka1=2.12.0-1.cflt~deb12" \ "librdkafka++1=2.12.0-1.cflt~deb12" \ "librdkafka-dev=2.12.0-1.cflt~deb12" \ # libssl pinned to the 3.0 series (ABI-stable), not an exact version: Debian rotates # point releases out of the security archive, which breaks exact pins on uncached builds. "libssl-dev=3.0.*" \ "libssl3=3.0.*" \ "zlib1g-dev" \ && \ rm -rf /var/lib/apt/lists/* WORKDIR /code COPY turbo.json package.json pnpm-lock.yaml pnpm-workspace.yaml tsconfig.json ./ COPY ./bin/turbo ./bin/turbo COPY ./patches ./patches COPY ./rust ./rust COPY ./common/esbuilder/ ./common/esbuilder/ COPY ./common/plugin_transpiler/ ./common/plugin_transpiler/ COPY ./common/hogvm/typescript/ ./common/hogvm/typescript/ COPY ./nodejs/package.json ./nodejs/tsconfig.json ./nodejs/ COPY ./common/replay-shared/package.json ./common/replay-shared/ COPY ./common/replay-headless/package.json ./common/replay-headless/ SHELL ["/bin/bash", "-e", "-o", "pipefail", "-c"] # Use system librdkafka from Confluent (2.12.0) instead of bundled version ENV BUILD_LIBRDKAFKA=0 # Compile and install Node.js dependencies RUN --mount=type=cache,id=pnpm,target=/tmp/pnpm-store-v24 \ corepack enable && \ NODE_OPTIONS="--max-old-space-size=16384" CI=1 pnpm --filter=@posthog/nodejs... install --frozen-lockfile --store-dir /tmp/pnpm-store-v24 && \ NODE_OPTIONS="--max-old-space-size=16384" CI=1 pnpm --filter=@posthog/replay-headless... install --frozen-lockfile --store-dir /tmp/pnpm-store-v24 && \ NODE_OPTIONS="--max-old-space-size=16384" CI=1 pnpm --filter=@posthog/plugin-transpiler... install --frozen-lockfile --store-dir /tmp/pnpm-store-v24 && \ NODE_OPTIONS="--max-old-space-size=16384" bin/turbo --filter=@posthog/plugin-transpiler build # Build the nodejs services COPY ./nodejs/src/ ./nodejs/src/ COPY ./nodejs/tests/ ./nodejs/tests/ COPY ./nodejs/assets/ ./nodejs/assets/ COPY ./nodejs/bin/ ./nodejs/bin/ COPY ./common/replay-shared/src/ ./common/replay-shared/src/ COPY ./common/replay-shared/tsconfig.json ./common/replay-shared/ COPY ./common/replay-headless/src/ ./common/replay-headless/src/ COPY ./common/replay-headless/build.mjs ./common/replay-headless/ # Build the rust hogvm napi addon (shadow execution of transformations) RUN NODE_OPTIONS="--max-old-space-size=16384" bin/turbo --filter=@posthog/hogvm-node build # Build the session-replay anonymizer native addon RUN NODE_OPTIONS="--max-old-space-size=16384" bin/turbo --filter=@posthog/replay-anonymizer build # Build the v4 AI research native addon (the URL policy of the v4 image fetcher) RUN NODE_OPTIONS="--max-old-space-size=16384" bin/turbo --filter=@posthog/ai-research-v4-native build # Build replay-headless (dependency of nodejs rasterizer code) RUN NODE_OPTIONS="--max-old-space-size=16384" bin/turbo --filter=@posthog/replay-headless build # Then build the nodejs services RUN NODE_OPTIONS="--max-old-space-size=16384" bin/turbo --filter=@posthog/nodejs build # # Runtime stage: Minimal image with only nodejs runtime dependencies # FROM node:24.22.1-bookworm-slim WORKDIR /code SHELL ["/bin/bash", "-e", "-o", "pipefail", "-c"] # Install runtime dependencies # Add Confluent's client repository for librdkafka runtime RUN apt-get update && \ apt-get install -y --no-install-recommends \ "ca-certificates" \ "wget" \ "gnupg" \ && \ mkdir -p /etc/apt/keyrings && \ wget -qO - https://packages.confluent.io/clients/deb/archive.key | gpg --dearmor -o /etc/apt/keyrings/confluent-clients.gpg && \ echo "deb [signed-by=/etc/apt/keyrings/confluent-clients.gpg] https://packages.confluent.io/clients/deb/ bookworm main" > /etc/apt/sources.list.d/confluent-clients.list && \ apt-get update && \ apt-get install -y --no-install-recommends --allow-downgrades \ "librdkafka1=2.12.0-1.cflt~deb12" \ "librdkafka++1=2.12.0-1.cflt~deb12" \ # libssl pinned to the 3.0 series (ABI-stable), not an exact version: Debian rotates # point releases out of the security archive, which breaks exact pins on uncached builds. "libssl3=3.0.*" \ "curl" \ "gettext-base" \ "libjemalloc2" \ && \ rm -rf /var/lib/apt/lists/* # curl: Required by bin/nodejs startup script to fetch EC2 metadata when INJECT_EC2_CLIENT_RACK is set # gettext-base: Provides envsubst command used by bin/nodejs to substitute environment variables in Kafka client IDs # Install and use a non-root user RUN groupadd -g 10001 posthog && \ useradd -u 10001 -g posthog -m -d /home/posthog posthog && \ chown -R posthog:posthog /code USER posthog # Add the commit hash ARG COMMIT_HASH RUN echo ${COMMIT_HASH:-unknown} > /code/commit.txt # Add in the compiled nodejs & its runtime dependencies from the build stage COPY --from=nodejs-build --chown=posthog:posthog /code/rust/common/hogvm/node/package.json /code/rust/common/hogvm/node/package.json COPY --from=nodejs-build --chown=posthog:posthog /code/rust/common/hogvm/node/index.js /code/rust/common/hogvm/node/index.js COPY --from=nodejs-build --chown=posthog:posthog /code/rust/common/hogvm/node/index.node /code/rust/common/hogvm/node/index.node COPY --from=nodejs-build --chown=posthog:posthog /code/rust/replay-anonymizer-node/dist /code/rust/replay-anonymizer-node/dist COPY --from=nodejs-build --chown=posthog:posthog /code/rust/replay-anonymizer-node/package.json /code/rust/replay-anonymizer-node/package.json COPY --from=nodejs-build --chown=posthog:posthog /code/rust/replay-anonymizer-node/index.node /code/rust/replay-anonymizer-node/index.node COPY --from=nodejs-build --chown=posthog:posthog /code/rust/ai-research/replay-core-v4-node/dist /code/rust/ai-research/replay-core-v4-node/dist COPY --from=nodejs-build --chown=posthog:posthog /code/rust/ai-research/replay-core-v4-node/package.json /code/rust/ai-research/replay-core-v4-node/package.json COPY --from=nodejs-build --chown=posthog:posthog /code/rust/ai-research/replay-core-v4-node/index.node /code/rust/ai-research/replay-core-v4-node/index.node COPY --from=nodejs-build --chown=posthog:posthog /code/common/plugin_transpiler/dist /code/common/plugin_transpiler/dist COPY --from=nodejs-build --chown=posthog:posthog /code/common/plugin_transpiler/node_modules /code/common/plugin_transpiler/node_modules COPY --from=nodejs-build --chown=posthog:posthog /code/common/plugin_transpiler/package.json /code/common/plugin_transpiler/package.json COPY --from=nodejs-build --chown=posthog:posthog /code/common/hogvm/typescript/dist /code/common/hogvm/typescript/dist COPY --from=nodejs-build --chown=posthog:posthog /code/common/hogvm/typescript/node_modules /code/common/hogvm/typescript/node_modules COPY --from=nodejs-build --chown=posthog:posthog /code/common/hogvm/typescript/package.json /code/common/hogvm/typescript/package.json COPY --from=nodejs-build --chown=posthog:posthog /code/nodejs/dist /code/nodejs/dist COPY --from=nodejs-build --chown=posthog:posthog /code/node_modules /code/node_modules COPY --from=nodejs-build --chown=posthog:posthog /code/nodejs/node_modules /code/nodejs/node_modules COPY --from=nodejs-build --chown=posthog:posthog /code/nodejs/package.json /code/nodejs/package.json COPY --from=nodejs-build --chown=posthog:posthog /code/common/replay-headless/dist /code/common/replay-headless/dist COPY --from=nodejs-build --chown=posthog:posthog /code/common/replay-headless/package.json /code/common/replay-headless/package.json COPY --from=nodejs-build --chown=posthog:posthog /code/nodejs/assets /code/nodejs/assets COPY --from=nodejs-build --chown=posthog:posthog /code/nodejs/bin /code/nodejs/bin # Setup ENV ENV NODE_ENV=production \ BUILD_LIBRDKAFKA=0 # Expose the port from which we serve OpenMetrics data EXPOSE 8001 # Default command: run the nodejs services CMD ["node", "nodejs/dist/index.js"]