chadtmiller.com/pds.js
An atproto PDS in JavaScript, for Cloudflare Workers and Node
0
0
# pds.js as a single container.
#
# Built from workspace source rather than from the published packages, so the
# image always matches the commit it was built from and can be built before a
# release reaches npm.
FROM node:22-slim AS builder
# corepack resolves the pnpm version from package.json's packageManager field,
# and prompts before downloading it — which would hang a non-interactive build.
ENV COREPACK_ENABLE_DOWNLOAD_PROMPT=0
RUN corepack enable
WORKDIR /app
# better-sqlite3 publishes prebuilds for common platforms, but falls back to
# compiling from source when there is no match for the target.
RUN apt-get update \
&& apt-get install -y --no-install-recommends python3 make g++ \
&& rm -rf /var/lib/apt/lists/*
# Manifests first, so dependency resolution caches independently of source
# edits. pnpm checks the whole workspace against the lockfile, so every
# member's manifest has to be present even though most go unused here.
COPY pnpm-lock.yaml pnpm-workspace.yaml package.json ./
COPY docker/package.json docker/
COPY packages/blobs-deno/package.json packages/blobs-deno/
COPY packages/blobs-fs/package.json packages/blobs-fs/
COPY packages/blobs-s3/package.json packages/blobs-s3/
COPY packages/cloudflare/package.json packages/cloudflare/
COPY packages/core/package.json packages/core/
COPY packages/deno/package.json packages/deno/
COPY packages/lexicon-resolver/package.json packages/lexicon-resolver/
COPY packages/node/package.json packages/node/
COPY packages/readonly/package.json packages/readonly/
COPY packages/spaces/package.json packages/spaces/
COPY packages/storage-sqlite/package.json packages/storage-sqlite/
COPY examples/cloudflare/package.json examples/cloudflare/
COPY examples/deno/package.json examples/deno/
COPY examples/node/package.json examples/node/
COPY examples/runclub/package.json examples/runclub/
# better-sqlite3 needs its install script to run. The repo allows that in
# .npmrc, but that file is also where npm auth tokens live, so it is passed
# explicitly here rather than copied into a layer.
RUN printf 'only-built-dependencies[]=better-sqlite3\n' > .npmrc \
&& pnpm install --frozen-lockfile --prod --filter pds-container...
# Source last: editing it invalidates only this layer.
COPY packages packages
COPY docker/server.js docker/
FROM node:22-slim AS runtime
WORKDIR /app
# Runs unprivileged. node:22-slim ships a "node" user for exactly this.
RUN mkdir -p /data && chown node:node /data
USER node
COPY --from=builder --chown=node:node /app /app
ENV NODE_ENV=production
ENV PDS_DB_PATH=/data/pds.db
ENV PDS_BLOBS_DIR=/data/blobs
ENV PORT=3000
# PDS_HOSTNAME and JWT_SECRET are deliberately unset — the entrypoint exits
# rather than inventing values for them.
VOLUME /data
EXPOSE 3000
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD node -e "fetch('http://127.0.0.1:'+(process.env.PORT||3000)+'/xrpc/_health').then(r=>process.exit(r.ok?0:1),()=>process.exit(1))"
CMD ["node", "docker/server.js"]