From fbcfdd10741d2513d36e11eebfd22051496a0210 Mon Sep 17 00:00:00 2001 From: Jason T Alborough Date: Mon, 23 Feb 2026 13:00:45 -0500 Subject: [PATCH 1/3] feat: add Dockerfile and .dockerignore for container deployments Multi-stage build: builder stage compiles TypeScript, runtime stage has only production dependencies. Non-root user (UID 1000) for K8s securityContext compatibility. Default port 4801 and host 0.0.0.0 set via env vars (requires the RELAYPLANE_PROXY_PORT/HOST support from the cli-env-vars PR). --- .dockerignore | 13 +++++++++++++ Dockerfile | 23 +++++++++++++++++++++++ 2 files changed, 36 insertions(+) create mode 100644 .dockerignore create mode 100644 Dockerfile diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..74bc3d4 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,13 @@ +node_modules +dist +.git +.github +__tests__ +coverage +*.tsbuildinfo +.env* +.claude +foundation +CLAUDE.md +.foundation-* +vitest.config.ts diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..f4a88bf --- /dev/null +++ b/Dockerfile @@ -0,0 +1,23 @@ +FROM node:18-alpine AS builder +WORKDIR /app +COPY package.json package-lock.json* ./ +RUN npm ci --include=optional +COPY tsconfig.json ./ +COPY src/ ./src/ +RUN npm run build + +FROM node:18-alpine +WORKDIR /app +ENV NODE_ENV=production +RUN addgroup -g 1000 relayplane && \ + adduser -u 1000 -G relayplane -s /bin/sh -D relayplane +COPY package.json package-lock.json* ./ +RUN npm ci --omit=dev --include=optional && npm cache clean --force +COPY --from=builder /app/dist/ ./dist/ +RUN mkdir -p /home/relayplane/.relayplane && \ + chown -R relayplane:relayplane /home/relayplane +USER relayplane +EXPOSE 4801 +ENV RELAYPLANE_PROXY_HOST=0.0.0.0 +ENV RELAYPLANE_PROXY_PORT=4801 +ENTRYPOINT ["node", "dist/cli.js"] From dde9da5fe3ef62b57420262915d12e0f65610a00 Mon Sep 17 00:00:00 2001 From: Jason T Alborough Date: Mon, 23 Feb 2026 13:05:07 -0500 Subject: [PATCH 2/3] fix: use existing node user instead of creating custom user node:18-alpine already has a node user/group at UID/GID 1000. --- Dockerfile | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/Dockerfile b/Dockerfile index f4a88bf..ad681ae 100644 --- a/Dockerfile +++ b/Dockerfile @@ -9,14 +9,12 @@ RUN npm run build FROM node:18-alpine WORKDIR /app ENV NODE_ENV=production -RUN addgroup -g 1000 relayplane && \ - adduser -u 1000 -G relayplane -s /bin/sh -D relayplane COPY package.json package-lock.json* ./ RUN npm ci --omit=dev --include=optional && npm cache clean --force COPY --from=builder /app/dist/ ./dist/ -RUN mkdir -p /home/relayplane/.relayplane && \ - chown -R relayplane:relayplane /home/relayplane -USER relayplane +RUN mkdir -p /home/node/.relayplane && \ + chown -R node:node /home/node/.relayplane +USER node EXPOSE 4801 ENV RELAYPLANE_PROXY_HOST=0.0.0.0 ENV RELAYPLANE_PROXY_PORT=4801 From 688d3fbd11a6737b05b2c74f91a622dd4537bac0 Mon Sep 17 00:00:00 2001 From: Jason T Alborough Date: Mon, 23 Feb 2026 13:07:29 -0500 Subject: [PATCH 3/3] fix: handle missing package-lock.json in Dockerfile Fall back to npm install when no lockfile is present. --- Dockerfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index ad681ae..1374b82 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,7 +1,7 @@ FROM node:18-alpine AS builder WORKDIR /app COPY package.json package-lock.json* ./ -RUN npm ci --include=optional +RUN if [ -f package-lock.json ]; then npm ci --include=optional; else npm install --include=optional; fi COPY tsconfig.json ./ COPY src/ ./src/ RUN npm run build @@ -10,7 +10,7 @@ FROM node:18-alpine WORKDIR /app ENV NODE_ENV=production COPY package.json package-lock.json* ./ -RUN npm ci --omit=dev --include=optional && npm cache clean --force +RUN if [ -f package-lock.json ]; then npm ci --omit=dev --include=optional; else npm install --omit=dev --include=optional; fi && npm cache clean --force COPY --from=builder /app/dist/ ./dist/ RUN mkdir -p /home/node/.relayplane && \ chown -R node:node /home/node/.relayplane