From aa2b83e1f6b6c7a05bb4a405c547cb37b4da0a1b Mon Sep 17 00:00:00 2001 From: Doan Minh Tu Date: Wed, 11 Mar 2026 06:48:44 +0700 Subject: [PATCH 1/5] ci: add Docker build and publish workflow --- .github/workflows/docker-publish.yml | 65 ++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 .github/workflows/docker-publish.yml diff --git a/.github/workflows/docker-publish.yml b/.github/workflows/docker-publish.yml new file mode 100644 index 00000000..e37c10f9 --- /dev/null +++ b/.github/workflows/docker-publish.yml @@ -0,0 +1,65 @@ +name: Build and Push Docker Image + +on: + push: + branches: + - master + tags: + - 'v*' + paths: + - 'src/**' + - 'open-sse/**' + - 'public/**' + - 'package*.json' + - 'next.config.*' + - 'Dockerfile' + workflow_dispatch: + +concurrency: + group: docker-${{ github.ref }} + cancel-in-progress: true + +env: + REGISTRY: ghcr.io + IMAGE_NAME: ${{ github.repository }} + +jobs: + build-and-push: + runs-on: ubuntu-latest + permissions: + contents: read + packages: write + + steps: + - uses: actions/checkout@v4 + + - uses: docker/setup-buildx-action@v3 + + - name: Log in to Container Registry + uses: docker/login-action@v3 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Extract metadata + id: meta + uses: docker/metadata-action@v5 + with: + images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} + tags: | + type=sha,prefix= + type=semver,pattern={{version}} + type=semver,pattern={{major}}.{{minor}} + type=raw,value=latest,enable={{is_default_branch}} + + - name: Build and push + uses: docker/build-push-action@v6 + with: + context: . + push: true + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + cache-from: type=registry,ref=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:buildcache + cache-to: type=registry,ref=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:buildcache,mode=max + platforms: linux/amd64 From 91c1bc848ed6a7aca3c0d10e91daa25eb22e2e30 Mon Sep 17 00:00:00 2001 From: Doan Minh Tu Date: Wed, 11 Mar 2026 06:49:10 +0700 Subject: [PATCH 2/5] ci: harden Dockerfile and workflow security --- .github/dependabot.yml | 6 ++++++ .github/workflows/docker-publish.yml | 2 ++ Dockerfile | 6 +++++- 3 files changed, 13 insertions(+), 1 deletion(-) create mode 100644 .github/dependabot.yml diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 00000000..ca79ca5b --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,6 @@ +version: 2 +updates: + - package-ecosystem: github-actions + directory: / + schedule: + interval: weekly diff --git a/.github/workflows/docker-publish.yml b/.github/workflows/docker-publish.yml index e37c10f9..64f143ac 100644 --- a/.github/workflows/docker-publish.yml +++ b/.github/workflows/docker-publish.yml @@ -63,3 +63,5 @@ jobs: cache-from: type=registry,ref=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:buildcache cache-to: type=registry,ref=${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:buildcache,mode=max platforms: linux/amd64 + provenance: false + sbom: false diff --git a/Dockerfile b/Dockerfile index 5d2491cf..8901e172 100644 --- a/Dockerfile +++ b/Dockerfile @@ -5,6 +5,7 @@ COPY package*.json ./ RUN if [ -f package-lock.json ]; then npm ci --no-audit --no-fund; else npm install --no-audit --no-fund; fi COPY . ./ +ENV NEXT_TELEMETRY_DISABLED=1 RUN npm run build FROM node:20-alpine AS runner @@ -15,15 +16,18 @@ LABEL org.opencontainers.image.title="9router" ENV NODE_ENV=production ENV PORT=20128 ENV HOSTNAME=0.0.0.0 +ENV NEXT_TELEMETRY_DISABLED=1 # Runtime writable location for localDb when DATA_DIR is configured to /app/data -RUN mkdir -p /app/data +RUN mkdir -p /app/data && chown node:node /app/data COPY --from=builder /app/public ./public COPY --from=builder /app/.next/static ./.next/static COPY --from=builder /app/.next/standalone ./ COPY --from=builder /app/open-sse ./open-sse +USER node + EXPOSE 20128 CMD ["node", "server.js"] From 5fc77fbf8c988567b54064e1f09d5d58bf61a28e Mon Sep 17 00:00:00 2001 From: Doan Minh Tu Date: Wed, 11 Mar 2026 06:56:21 +0700 Subject: [PATCH 3/5] ci: trigger only on tag push, keep master trigger commented --- .github/workflows/docker-publish.yml | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/.github/workflows/docker-publish.yml b/.github/workflows/docker-publish.yml index 64f143ac..9bc8b42c 100644 --- a/.github/workflows/docker-publish.yml +++ b/.github/workflows/docker-publish.yml @@ -2,22 +2,25 @@ name: Build and Push Docker Image on: push: - branches: - - master tags: - 'v*' - paths: - - 'src/**' - - 'open-sse/**' - - 'public/**' - - 'package*.json' - - 'next.config.*' - - 'Dockerfile' + # Uncomment to also build on master pushes (rolling latest). + # Pair with concurrency + paths below to avoid excessive builds. + # branches: + # - master + # paths: + # - 'src/**' + # - 'open-sse/**' + # - 'public/**' + # - 'package*.json' + # - 'next.config.*' + # - 'Dockerfile' workflow_dispatch: -concurrency: - group: docker-${{ github.ref }} - cancel-in-progress: true +# Uncomment if re-enabling master push trigger. +# concurrency: +# group: docker-${{ github.ref }} +# cancel-in-progress: true env: REGISTRY: ghcr.io From 9c757ff7d2407acbf54de01532560842b00e04a6 Mon Sep 17 00:00:00 2001 From: Doan Minh Tu Date: Wed, 11 Mar 2026 08:24:48 +0700 Subject: [PATCH 4/5] fix(docker): move data dir chown after COPY to fix EACCES permission error --- Dockerfile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Dockerfile b/Dockerfile index 8901e172..511b979b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -18,14 +18,14 @@ ENV PORT=20128 ENV HOSTNAME=0.0.0.0 ENV NEXT_TELEMETRY_DISABLED=1 -# Runtime writable location for localDb when DATA_DIR is configured to /app/data -RUN mkdir -p /app/data && chown node:node /app/data - COPY --from=builder /app/public ./public COPY --from=builder /app/.next/static ./.next/static COPY --from=builder /app/.next/standalone ./ COPY --from=builder /app/open-sse ./open-sse +# Runtime writable location for localDb — must be AFTER COPY to avoid permission overwrite +RUN mkdir -p /app/data && chown node:node /app/data + USER node EXPOSE 20128 From 8c51edabcf3a2fdb17458ef9d837bf1aac596aeb Mon Sep 17 00:00:00 2001 From: Doan Minh Tu Date: Wed, 11 Mar 2026 08:33:04 +0700 Subject: [PATCH 5/5] fix(docker): use entrypoint to fix /app/data permissions on mounted volumes --- Dockerfile | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/Dockerfile b/Dockerfile index 511b979b..b5bcae14 100644 --- a/Dockerfile +++ b/Dockerfile @@ -23,11 +23,13 @@ COPY --from=builder /app/.next/static ./.next/static COPY --from=builder /app/.next/standalone ./ COPY --from=builder /app/open-sse ./open-sse -# Runtime writable location for localDb — must be AFTER COPY to avoid permission overwrite -RUN mkdir -p /app/data && chown node:node /app/data +RUN mkdir -p /app/data -USER node +# Fix permissions at runtime (handles mounted volumes) +RUN printf '#!/bin/sh\nchown -R node:node /app/data 2>/dev/null; exec su-exec node "$@"\n' > /entrypoint.sh && chmod +x /entrypoint.sh +RUN apk add --no-cache su-exec EXPOSE 20128 +ENTRYPOINT ["/entrypoint.sh"] CMD ["node", "server.js"]