FROM alpine:3.20 RUN apk add --no-cache \ bash \ docker-cli \ git \ nodejs \ npm \ openssh-client \ gzip WORKDIR /app # Install script dependencies at /app/node_modules. Node ESM walks up from # the importing file (/app/scripts/*.js) and finds node_modules at /app. # (NODE_PATH is intentionally NOT used: ESM resolution ignores it.) COPY scripts/package*.json ./ RUN npm install --omit=dev # Bake the scripts into the image rather than bind-mounting them. DokPloy # rm-rf's the host code dir on every redeploy, which would orphan a bind # mount in the long-running cron container. Baking forces a rebuild + # recreate whenever scripts change, so the cron always sees current code. COPY scripts/ /app/scripts/ COPY cron/crontab /etc/crontabs/root COPY cron/entrypoint.sh /entrypoint.sh RUN chmod +x /entrypoint.sh ENTRYPOINT ["/entrypoint.sh"] CMD ["crond", "-f", "-l", "2"]