FROM ubuntu:noble # Allow the caller to specify the host UID/GID so files created by the # container match host ownership when volumes are mounted. Defaults to 1000. ARG HOST_UID=1000 ARG HOST_GID=1000 RUN apt-get -q update \ && DEBIAN_FRONTEND=noninteractive apt-get install --no-install-recommends -y \ ca-certificates curl gnupg \ curl \ nano \ && apt-get clean \ && rm -rf /var/lib/apt/lists/{apt,dpkg,cache,log} RUN mkdir -p /etc/apt/keyrings RUN curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg ENV NODE_MAJOR=22 RUN echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_$NODE_MAJOR.x nodistro main" | tee /etc/apt/sources.list.d/nodesource.list RUN apt-get -q update \ && DEBIAN_FRONTEND=noninteractive apt-get install --no-install-recommends -y \ nodejs \ && apt-get clean \ && rm -rf /var/lib/apt/lists/{apt,dpkg,cache,log} RUN apt-get -q update \ && DEBIAN_FRONTEND=noninteractive apt-get install --no-install-recommends -y \ sqlite3 \ && apt-get clean \ && rm -rf /var/lib/apt/lists/{apt,dpkg,cache,log} COPY server /server WORKDIR /server RUN npm install -s sqlite3 RUN npm install RUN npm run build # prepare client deps in the image so lint/type-check can run inside the container # copy client sources and install dependencies during the image build (container-first) COPY client /client WORKDIR /client ENV PUBLIC_URL="/ketr.ketran" ENV VITE_API_BASE="" # prefer npm ci when lockfile present, otherwise fall back to npm install #RUN rm -f package-lock.json #RUN npm install --legacy-peer-deps --no-audit --no-fund #RUN npm run build # return to server working dir for default run WORKDIR /server COPY /Dockerfile /Dockerfile COPY /.env /.env # Create a host-mapped user and group so container files are written with # the host UID/GID. Do this late in the build so earlier root-only build # steps are unaffected. Then ensure server and client directories are # owned by that user and switch to it for runtime. ## Create a group with the requested GID if it doesn't exist, otherwise reuse RUN if ! getent group ${HOST_GID} >/dev/null 2>&1; then \ groupadd -g ${HOST_GID} hostgroup; \ else \ EXISTING=$(getent group ${HOST_GID} | cut -d: -f1) && echo "Using existing group $EXISTING for GID ${HOST_GID}"; \ fi ## Create a user with the requested UID if it doesn't exist; if a user with ## that UID already exists, don't try to recreate it (we'll chown by numeric ## UID later). Create a home directory if missing. RUN if ! getent passwd ${HOST_UID} >/dev/null 2>&1; then \ useradd -m -u ${HOST_UID} -g ${HOST_GID} -s /bin/bash hostuser || true; \ else \ EXISTING_USER=$(getent passwd ${HOST_UID} | cut -d: -f1) && echo "Found existing user $EXISTING_USER with UID ${HOST_UID}"; \ mkdir -p /home/hostuser || true; \ fi ## Ensure runtime dirs are owned by the numeric UID:GID if hostuser/group ## weren't created, or by the names if they were. RUN chown -R ${HOST_UID}:${HOST_GID} /server || true RUN chown -R ${HOST_UID}:${HOST_GID} /client || true ENV HOME=/home/hostuser USER ${HOST_UID}:${HOST_GID} CMD ["npm", "start"]