################## First Stage - Creating base ######################### # Created a variable to hold our node base image ARG NODE_IMAGE=node:22-trixie-slim FROM $NODE_IMAGE AS base # Install dumb-init and ClamAV, and perform ClamAV database update RUN apt-get update \ && apt-get install -y --no-install-recommends \ dumb-init \ clamav \ clamav-daemon \ clamdscan \ ca-certificates \ && rm -rf /var/lib/apt/lists/* \ # Creating folders and changing ownerships && mkdir -p /home/node/app \ && mkdir -p /var/lib/clamav \ && mkdir /usr/local/share/clamav \ && mkdir /var/run/clamav \ && mkdir -p /var/log/clamav \ && mkdir -p /tmp/clamav-logs \ # Set ownership and permissions && chown node:node /home/node/app \ # && chown -R node:clamav /var/lib/clamav /usr/local/share/clamav /etc/clamav /var/run/clamav \ && chown -R node:clamav /var/lib/clamav /usr/local/share/clamav /etc/clamav /var/run/clamav /var/log/clamav \ && chown -R node:clamav /etc/clamav \ && chmod 755 /tmp/clamav-logs \ && chmod 750 /var/run/clamav \ && chmod 755 /var/lib/clamav \ && chmod 755 /var/log/clamav \ # Add node user to clamav group and allow sudo for clamav commands && usermod -a -G clamav node # && chmod 666 /var/run/clamav/clamd.socket # Make directories group-writable so node (as member of clamav group) can access them # && chmod 750 /var/run/clamav /var/lib/clamav /var/log/clamav /tmp/clamav-logs # Configure ClamAV - copy config files before switching user # COPY --chown=node:clamav ./*.conf /etc/clamav/ COPY --chown=node:clamav ./*.conf /etc/clamav/ # Setting the working directory WORKDIR /home/node/app # Changing the current active user to "node" # Download initial ClamAV database as root before switching users USER node RUN freshclam --quiet || echo "Initial database download failed - will retry at runtime" # Copy entrypoint script COPY --chown=node:clamav docker-entrypoint.sh /home/node/app/docker-entrypoint.sh RUN chmod +x /home/node/app/docker-entrypoint.sh ENV TZ="Europe/Vienna" ################## Second Stage - Installing dependencies ########## # In this stage, we will start installing dependencies FROM base AS dependencies # We copy all package.* files to the working directory COPY --chown=node:node ./package*.json ./ # We run NPM CI to install the exact versions of dependencies RUN npm ci # Lastly, we copy all the files with active user COPY --chown=node:node . . ################## Third Stage - Building Stage ##################### # In this stage, we will start building dependencies FROM dependencies AS build ENV NODE_ENV=production # We run "node ace build" to build the app (dist folder) for production RUN node ace build --ignore-ts-errors # RUN node ace build --production ################## Final Stage - Production ######################### # In this final stage, we will start running the application FROM base AS production # Here, we include all the required environment variables # ENV NODE_ENV=production # ENV PORT=$PORT # ENV HOST=0.0.0.0 # Copy package.* to the working directory with active user COPY --chown=node:node ./package*.json ./ # We run NPM CI to install the exact versions of production dependencies RUN npm ci --omit=dev # Copy files to the working directory from the build folder the user COPY --chown=node:node --from=build /home/node/app/build . # Expose port # EXPOSE 3310 EXPOSE 3333 ENTRYPOINT ["/home/node/app/docker-entrypoint.sh"] # Run the command to start the server using "dumb-init" CMD [ "dumb-init", "node", "bin/server.js" ]