# syntax=docker/dockerfile:1.4
ARG NODE_VERSION=22
# Pin alpine version so libs are in sync between builder and runtime
ARG ALPINE_VERSION=3.23
# Hardened (distroless) runtime base. Override to point at your mirrored/
# entitled DHI registry. The tag must track NODE_VERSION/ALPINE_VERSION above.
ARG DHI_RUNTIME=dhi.io/node:${NODE_VERSION}-alpine${ALPINE_VERSION}
####################################################################################################
## Build Packages
FROM node:${NODE_VERSION}-alpine${ALPINE_VERSION} AS builder
RUN apk --no-cache add python3 py3-setuptools build-base
WORKDIR /directus
COPY package.json .
RUN corepack enable && corepack prepare
# Deploy as 'node' user to match pnpm setups in production image
# (see https://github.com/directus/directus/issues/23822)
RUN chown node:node .
USER node
ENV NODE_OPTIONS=--max-old-space-size=8192
COPY pnpm-lock.yaml .
RUN pnpm fetch
COPY --chown=node:node . .
RUN <<EOF
set -ex
pnpm install --recursive --offline --frozen-lockfile
npm_config_workspace_concurrency=2 pnpm run build
pnpm --filter directus deploy --legacy --prod dist
cd dist
# drop the prebuilds and recompile from source
argon2_dir=$(find node_modules -type d -name argon2 -exec test -f '{}/argon2.cjs' ';' -print | head -n1)
rm -rf "$argon2_dir/prebuilds"
( cd "$argon2_dir" && node "$(npm root -g)/npm/node_modules/node-gyp/bin/node-gyp.js" rebuild )
# fail the build if it didnt compile
test -f "$argon2_dir/build/Release/argon2.node"
# Regenerate package.json file with essential fields only
# (see https://github.com/directus/directus/issues/20338)
node -e '
const f = "package.json", {name, version, type, exports, bin} = require(`./${f}`), {packageManager} = require(`../${f}`);
fs.writeFileSync(f, JSON.stringify({name, version, type, exports, bin, packageManager}, null, 2));
'
mkdir -p database extensions uploads .pm2
EOF
####################################################################################################
## Create Production Image
# Docker Hardened Image (distroless): pre-patched, no shell, no package manager, runs as a non-root user by default
FROM ${DHI_RUNTIME} AS runtime
USER node
WORKDIR /directus
ENV \
DB_CLIENT="sqlite3" \
DB_FILENAME="/directus/database/database.sqlite" \
NODE_ENV="production" \
NPM_CONFIG_UPDATE_NOTIFIER="false" \
PM2_HOME="/directus/.pm2" \
PIDUSAGE_SILENT="true"
COPY --from=builder --chown=node:node /directus/ecosystem.config.cjs .
COPY --from=builder --chown=node:node /directus/dist .
COPY --chown=node:node docker-entrypoint.cjs .
EXPOSE 8055
# No shell in the hardened image run node directly
ENTRYPOINT ["node", "docker-entrypoint.cjs"]