ARG NODE_IMAGE=node:24-alpine@sha256:d32cdf619f63fe0471182d08996dd516c6275bb5fd31ae06e55a570bd9e1ad43
ARG RUST_IMAGE=rust:1.94.1-alpine@sha256:77237dd363a0b127bb5ef532c2d64c0deb380b738e43a9c4bdac73398d6d0a08
FROM ${RUST_IMAGE} AS finalize-fs-build
WORKDIR /src
COPY packages/finalize-fs/Cargo.toml packages/finalize-fs/Cargo.lock ./
COPY packages/finalize-fs/src ./src
RUN cargo build --release --locked
FROM ${NODE_IMAGE} AS deps
RUN apk add --no-cache python3 make g++
WORKDIR /app
COPY package.json pnpm-lock.yaml pnpm-workspace.yaml .npmrc ./
COPY packages/native-host/package.json ./packages/native-host/package.json
COPY scripts/postinstall.mjs ./scripts/postinstall.mjs
COPY scripts/fetch-engine.mjs ./scripts/fetch-engine.mjs
ENV MOTRIX_SKIP_ELECTRON_REBUILD=1 \
MOTRIX_SKIP_ENGINE_FETCH=1
RUN --mount=type=cache,id=motrix-pnpm-store,target=/pnpm/store \
corepack enable \
&& corepack prepare pnpm@12.15.0 --activate \
&& pnpm config set store-dir /pnpm/store \
&& pnpm install --frozen-lockfile
FROM ${NODE_IMAGE} AS full-root-production-deps
RUN apk add --no-cache python3 make g++
WORKDIR /app
COPY package.json pnpm-lock.yaml pnpm-workspace.yaml .npmrc ./
COPY packages/native-host/package.json ./packages/native-host/package.json
COPY scripts/postinstall.mjs ./scripts/postinstall.mjs
COPY scripts/fetch-engine.mjs ./scripts/fetch-engine.mjs
ENV CI=true \
MOTRIX_SKIP_ELECTRON_REBUILD=1 \
MOTRIX_SKIP_ENGINE_FETCH=1
RUN --mount=type=cache,id=motrix-pnpm-store,target=/pnpm/store \
corepack enable \
&& corepack prepare pnpm@12.15.0 --activate \
&& pnpm config set store-dir /pnpm/store \
&& pnpm install --prod --frozen-lockfile --ignore-scripts
FROM deps AS build
ARG TARGETARCH
ENV MOTRIX_SERVER_FINALIZE_FS_PREBUILT=1
WORKDIR /app
COPY --from=finalize-fs-build /src/target/release/motrix-finalize-fs /tmp/motrix-finalize-fs
COPY . .
RUN node node_modules/electron/install.js
RUN --mount=type=cache,id=motrix-builtins,target=/app/node_modules/.cache/motrix-builtins \
case "${TARGETARCH}" in \
amd64) engine_arch=x64 ;; \
arm64) engine_arch=arm64 ;; \
*) echo "unsupported Docker target architecture: ${TARGETARCH}" >&2; exit 2 ;; \
esac \
&& mkdir -p "packages/finalize-fs/dist/linux-${engine_arch}" \
&& install -m 0755 /tmp/motrix-finalize-fs "packages/finalize-fs/dist/linux-${engine_arch}/motrix-finalize-fs" \
&& node scripts/fetch-engine.mjs --platform linux --arch "${engine_arch}" \
&& pnpm run check:third-party-notices \
&& pnpm run build:server \
&& MOTRIX_FINALIZE_FS_TEST_BIN="packages/finalize-fs/dist/linux-${engine_arch}/motrix-finalize-fs" pnpm exec vitest run src/core/plugin/finalize/native-artifact-operations.integration.test.ts --reporter=verbose \
&& node scripts/stage-server-app.mjs --platform linux --arch "${TARGETARCH}" --libc musl --strict \
&& node scripts/verify-server-package.mjs --app-dir dist/server-app --platform linux --arch "${TARGETARCH}" --libc musl
FROM scratch AS server-size-report
COPY --from=build /app/release/size-reports/ /
FROM ${NODE_IMAGE} AS server-full-root-baseline
RUN apk add --no-cache ca-certificates \
&& rm -rf /usr/local/lib/node_modules/npm \
/usr/local/lib/node_modules/corepack \
/opt/yarn-v1.22.22 \
&& rm -f /usr/local/bin/npm /usr/local/bin/npx /usr/local/bin/corepack \
/usr/local/bin/pnpm /usr/local/bin/yarn /usr/local/bin/yarnpkg \
&& printf '%s\n' '#!/bin/sh' 'exec node /app/dist/server/motrix-admin.mjs "$@"' > /usr/local/bin/motrix-admin \
&& chmod 0755 /usr/local/bin/motrix-admin \
&& mkdir -p /data/home /data/tmp /downloads \
&& chown -R node:node /data /downloads
WORKDIR /app
COPY --from=build --chown=node:node /app/package.json ./package.json
COPY --from=build --chown=node:node /app/dist/server ./dist/server
COPY --from=build --chown=node:node /app/dist/core/plugin/host ./dist/core/plugin/host
COPY --from=build --chown=node:node /app/dist/renderer-web ./dist/renderer-web
COPY --from=build --chown=node:node /app/dist/server-app/bin/aria2c ./bin/aria2c
COPY --from=build --chown=node:node /app/dist/server-app/bin/motrix-finalize-fs ./bin/motrix-finalize-fs
COPY --from=full-root-production-deps --chown=node:node /app/node_modules ./node_modules
COPY --from=build --chown=node:node /app/extra/aria2.conf ./extra/aria2.conf
COPY --from=build --chown=node:node /app/dist/builtin-plugins ./builtin-plugins
COPY --from=build --chown=node:node /app/LICENSE ./LICENSE
COPY --from=build --chown=node:node /app/THIRD_PARTY_NOTICES.md ./THIRD_PARTY_NOTICES.md
COPY --from=build --chown=node:node /app/THIRD_PARTY_NOTICES.zh-CN.md ./THIRD_PARTY_NOTICES.zh-CN.md
COPY --from=build --chown=node:node /app/THIRD_PARTY_LICENSES ./THIRD_PARTY_LICENSES
COPY --from=build --chown=node:node /app/build/legal/THIRD_PARTY_DEPENDENCIES.md ./legal/THIRD_PARTY_DEPENDENCIES.md
COPY --from=build --chown=node:node /app/build/legal/THIRD_PARTY_LICENSES.txt ./legal/THIRD_PARTY_LICENSES.txt
COPY --from=build --chown=node:node /app/build/legal/sbom.spdx.json ./legal/sbom.spdx.json
ENV YARN_VERSION= \
PATH=/app/bin:${PATH} \
NODE_ENV=production \
MOTRIX_DATA_DIR=/data \
MOTRIX_TEMP_DIR=/data/tmp \
MOTRIX_PLUGIN_DIR=/data/plugins \
MOTRIX_EXTRA_DIR=/app/extra \
MOTRIX_ARIA2_BIN=/app/bin/aria2c \
MOTRIX_FINALIZE_FS_BIN=/app/bin/motrix-finalize-fs \
MOTRIX_DEFAULT_SAVE_DIR=/downloads \
MOTRIX_ALLOWED_SAVE_DIRS=/downloads \
MOTRIX_RENDERER_DIR=/app/dist/renderer-web \
MOTRIX_BUILTIN_PLUGIN_DIR=/app/builtin-plugins \
SSL_CERT_FILE=/etc/ssl/certs/ca-certificates.crt \
HOME=/data/home \
TMPDIR=/data/tmp \
PORT=8080
VOLUME ["/data", "/downloads"]
EXPOSE 8080 16801
USER node
STOPSIGNAL SIGTERM
HEALTHCHECK --interval=30s --timeout=5s --start-period=20s --retries=3 CMD ["node", "-e", "fetch('http://127.0.0.1:'+(process.env.PORT||'8080')+'/healthz').then(r=>{if(!r.ok)process.exit(1)}).catch(()=>process.exit(1))"]
CMD ["node", "dist/server/index.mjs"]
FROM ${NODE_IMAGE} AS runtime
ARG OCI_REVISION=unknown
ARG OCI_VERSION=0.0.0-local
RUN apk add --no-cache ca-certificates \
&& rm -rf /usr/local/lib/node_modules/npm \
/usr/local/lib/node_modules/corepack \
/opt/yarn-v1.22.22 \
&& rm -f /usr/local/bin/npm /usr/local/bin/npx /usr/local/bin/corepack \
/usr/local/bin/pnpm /usr/local/bin/yarn /usr/local/bin/yarnpkg \
&& printf '%s\n' '#!/bin/sh' 'exec node /app/dist/server/motrix-admin.mjs "$@"' > /usr/local/bin/motrix-admin \
&& chmod 0755 /usr/local/bin/motrix-admin \
&& mkdir -p /data/home /data/tmp /downloads \
&& chown -R node:node /data /downloads
WORKDIR /app
COPY --from=build --chown=node:node /app/dist/server-app/ ./
LABEL org.opencontainers.image.title="Motrix Server" \
org.opencontainers.image.description="Motrix Server web download manager for persistent NAS deployments" \
org.opencontainers.image.url="https://motrix.app" \
org.opencontainers.image.documentation="https://github.com/agalwood/Motrix/blob/main/docs/docker-server.md" \
org.opencontainers.image.source="https://github.com/agalwood/Motrix" \
org.opencontainers.image.revision="${OCI_REVISION}" \
org.opencontainers.image.version="${OCI_VERSION}" \
org.opencontainers.image.licenses="MIT"
ENV YARN_VERSION= \
PATH=/app/bin:${PATH} \
NODE_ENV=production \
MOTRIX_DATA_DIR=/data \
MOTRIX_TEMP_DIR=/data/tmp \
MOTRIX_PLUGIN_DIR=/data/plugins \
MOTRIX_EXTRA_DIR=/app/extra \
MOTRIX_ARIA2_BIN=/app/bin/aria2c \
MOTRIX_FINALIZE_FS_BIN=/app/bin/motrix-finalize-fs \
MOTRIX_DEFAULT_SAVE_DIR=/downloads \
MOTRIX_ALLOWED_SAVE_DIRS=/downloads \
MOTRIX_RENDERER_DIR=/app/dist/renderer-web \
MOTRIX_BUILTIN_PLUGIN_DIR=/app/builtin-plugins \
SSL_CERT_FILE=/etc/ssl/certs/ca-certificates.crt \
HOME=/data/home \
TMPDIR=/data/tmp \
PORT=8080
VOLUME ["/data", "/downloads"]
EXPOSE 8080 16801
USER node
STOPSIGNAL SIGTERM
HEALTHCHECK --interval=30s --timeout=5s --start-period=20s --retries=3 CMD ["node", "-e", "fetch('http://127.0.0.1:'+(process.env.PORT||'8080')+'/healthz').then(r=>{if(!r.ok)process.exit(1)}).catch(()=>process.exit(1))"]
CMD ["node", "dist/server/index.mjs"]