From 73bf5f3fbe04fc67d2c20f10eae6d8ae0bba9b49 Mon Sep 17 00:00:00 2001 From: Kyle Affolder Date: Wed, 5 Feb 2025 14:03:46 -0500 Subject: [PATCH 01/26] refactor(docker): improve build w/ multistage * Switch to multi-stage build pattern for smaller image size * Add support for both Alpine and Debian variants via build args * Change default image base to `node:23-slim` instead of using `node:23` (no need for full Debian base present in `node:23` since now prioritization is given to production-ready builds) * Improve caching with --mount for npm dependencies * Separate build and runtime dependencies * Remove unnecessary Node.js packages in final stage * Fix permissions on uploads/database directories * Add proper scoping for build arguments * Set NODE_ENV=production for better performance This change reduces the final image size and improves build caching while adding flexibility to choose between Alpine and Debian base images. Original: ~1.2GB New Alpine: ~350MB New Debian: ~450MB --- Dockerfile | 135 +++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 104 insertions(+), 31 deletions(-) diff --git a/Dockerfile b/Dockerfile index 7822902..4e53405 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,52 +1,125 @@ -FROM node:23 +# syntax=docker/dockerfile:1 -# Install necessary packages including tzdata for timezone setting +# Global build arguments +ARG NODE_ALPINE_VERSION=23-alpine +ARG NODE_DEBIAN_VERSION=23-slim +ARG VARIANT=debian + +#==========================================================# +# STAGE 1: BUILD STAGE # +#==========================================================# + +FROM node:${NODE_DEBIAN_VERSION} AS builder-debian RUN apt-get update && apt-get install -y \ - build-essential \ - libnode108 \ - nodejs \ - python3 \ - sqlite3 \ - libsqlite3-dev \ - make \ - node-gyp \ - g++ \ - tzdata \ - iputils-ping && \ + build-essential \ + python3 \ + sqlite3 \ + libsqlite3-dev \ + make \ + node-gyp \ + g++ \ + tzdata \ + iputils-ping && \ rm -rf /var/lib/apt/lists/* -# Set the timezone environment variable and the application environment -ARG KENER_BASE_PATH= -ENV TZ=Etc/UTC -ENV KENER_BASE_PATH=${KENER_BASE_PATH} +FROM node:${NODE_ALPINE_VERSION} AS builder-alpine +RUN apk add --no-cache \ + build-base \ + python3 \ + py3-pip \ + make \ + g++ \ + sqlite \ + sqlite-dev \ + tzdata \ + iputils + +FROM builder-${VARIANT} AS builder + +# Set timezone and application environment +ARG KENER_BASE_PATH +ENV TZ=Etc/UTC \ + KENER_BASE_PATH=${KENER_BASE_PATH} \ + VITE_BUILD_ENV=production # Set the working directory WORKDIR /app -# Copy package files and install dependencies +# Copy package files for dependency installation COPY package*.json ./ -RUN npm install && npm cache clean --force -# Copy the rest of the application code +# Install all dependencies, including `devDependencies` (cache enabled for faster builds) +RUN --mount=type=cache,target=/root/.npm \ + npm ci && \ + npm cache clean --force + +# Copy application source code COPY . . -# remove dir src/routes/(docs) -RUN rm -rf src/routes/\(docs\) +# Remove docs directory and ensure required directories exist +RUN rm -rf src/routes/\(docs\) && \ + mkdir -p uploads database && \ + chmod -R 755 uploads database -# Ensure /app/uploads and /app/database have rw permissions -RUN mkdir -p /app/uploads /app/database && \ - chmod -R 777 /app/uploads /app/database +# Build the application and remove `devDependencies` +RUN npm run build && \ + npm prune --omit=dev -# Build the application -RUN npm run build +#==========================================================# +# STAGE 2: PRODUCTION STAGE # +#==========================================================# -# Argument for the port +FROM node:${NODE_DEBIAN_VERSION} AS final-debian +RUN apt-get update && apt-get install -y \ + sqlite3 \ + tzdata \ + iputils-ping && \ + rm -rf /var/lib/apt/lists/* + +FROM node:${NODE_ALPINE_VERSION} AS final-alpine +RUN apk add --no-cache sqlite tzdata iputils + +FROM final-${VARIANT} AS final + +# Set the working directory +WORKDIR /app + +# Copy package files and necessary build artifacts from builder stage +COPY --from=builder /app/package.json /app/package-lock.json ./ +COPY --from=builder \ + /app/src/lib/i18n \ + /app/src/lib/locales \ + /app/src/lib/server \ + /app/src/lib/boringOne.js \ + /app/src/lib/clientTools.js \ + /app/src/lib/color.js \ + /app/src/lib/index.js \ + /app/src/lib/site.js \ + ./src/lib/ +COPY --from=builder \ + /app/build \ + /app/uploads \ + /app/database \ + /app/node_modules \ + /app/migrations \ + /app/seeds \ + /app/static \ + /app/embed.html \ + /app/knexfile.js \ + /app/main.js \ + /app/openapi.json \ + /app/openapi.yaml \ + /app/sitemap.js.bk \ + /app/utils.js \ + ./ + +# Set environment variables ARG PORT=3000 -# Set the environment variable for the port -ENV PORT=$PORT +ENV PORT=$PORT \ + NODE_ENV=production # Expose the application port EXPOSE $PORT -# Set the command to run the application +# Run the application CMD ["node", "main"] \ No newline at end of file From fdad329148cdc974190ad1db5ae959b1271e0e3e Mon Sep 17 00:00:00 2001 From: Kyle Affolder Date: Wed, 5 Feb 2025 18:37:10 -0500 Subject: [PATCH 02/26] update(docker): simplified variable name --- Dockerfile | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Dockerfile b/Dockerfile index 4e53405..a5c7873 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,15 +1,15 @@ # syntax=docker/dockerfile:1 # Global build arguments -ARG NODE_ALPINE_VERSION=23-alpine -ARG NODE_DEBIAN_VERSION=23-slim +ARG ALPINE_VERSION=23-alpine +ARG DEBIAN_VERSION=23-slim ARG VARIANT=debian #==========================================================# # STAGE 1: BUILD STAGE # #==========================================================# -FROM node:${NODE_DEBIAN_VERSION} AS builder-debian +FROM node:${DEBIAN_VERSION} AS builder-debian RUN apt-get update && apt-get install -y \ build-essential \ python3 \ @@ -22,7 +22,7 @@ RUN apt-get update && apt-get install -y \ iputils-ping && \ rm -rf /var/lib/apt/lists/* -FROM node:${NODE_ALPINE_VERSION} AS builder-alpine +FROM node:${ALPINE_VERSION} AS builder-alpine RUN apk add --no-cache \ build-base \ python3 \ @@ -69,14 +69,14 @@ RUN npm run build && \ # STAGE 2: PRODUCTION STAGE # #==========================================================# -FROM node:${NODE_DEBIAN_VERSION} AS final-debian +FROM node:${DEBIAN_VERSION} AS final-debian RUN apt-get update && apt-get install -y \ sqlite3 \ tzdata \ iputils-ping && \ rm -rf /var/lib/apt/lists/* -FROM node:${NODE_ALPINE_VERSION} AS final-alpine +FROM node:${ALPINE_VERSION} AS final-alpine RUN apk add --no-cache sqlite tzdata iputils FROM final-${VARIANT} AS final From 13366284c63cf873221ae27d6d49bc283718abb1 Mon Sep 17 00:00:00 2001 From: Kyle Affolder Date: Wed, 5 Feb 2025 21:03:18 -0500 Subject: [PATCH 03/26] add(docker): docker-specific README badges --- README.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 9b6ee32..cd9d1f8 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,12 @@

GitHub Repo stars Awesome status page - Docker Kener +

+ +

+ Docker Kener + Docker Image Size + Docker Image Size

From 7176c3d4f446d8b4d7268cc8af18421c21048636 Mon Sep 17 00:00:00 2001 From: Kyle Affolder Date: Wed, 5 Feb 2025 22:24:09 -0500 Subject: [PATCH 04/26] refactor(gha): update gh publish image workflow MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Streamlined the GitHub `publishImage.yml` workflow with the following functionality: * Handle both Alpine and Debian variants through matrix strategy * Push to both Docker Hub and GitHub Container Registry * Add comprehensive tagging strategy, handling both branches (aka release version, e.g. 1.0.0), semantic versions (major.minor and major), and latest versions (`latest` and `alpine`) * Add security aspects (cosign signing, proper permissions) * Add better caching and multi-platform build settings With this revised workflow, the following Docker image variants will be built for every successful release. As an example, if the release version is “3.0.9”, then the following Docker image variants will be built: Debian variants (default): - `kener:3.0.9` (Semver of current release) - `kener:latest` (Latest Debian release, ’latest’ label points to 3.0.9) - `kener:3.0` (major.minor version, major.minor ‘3.0’ label points to 3.0.9) - `kener:3` (major version, major ‘3’ label points to 3.0.9) Alpine variants (smallest filesize): - `kener:3.0.9-alpine` (Semver of current release) - `kener:alpine` (Latest Alpine release, ‘alpine’ label points to 3.0.9) - `kener:3.0-alpine` (major.minor version, major.minor ‘3.0-alpine’ label points to 3.0.9) - `kener:3-alpine` (major version, major ‘3-alpine’ label points to 3.0.9) --- .github/workflows/publishImage.yml | 121 ++++++++++++++++++++++------- 1 file changed, 92 insertions(+), 29 deletions(-) diff --git a/.github/workflows/publishImage.yml b/.github/workflows/publishImage.yml index 246d530..ba7da12 100644 --- a/.github/workflows/publishImage.yml +++ b/.github/workflows/publishImage.yml @@ -1,5 +1,5 @@ --- -name: Publish Docker image to Dockerhub and GHCR +name: Publish Docker image to Docker Hub and GitHub Container Registry on: push: branches: @@ -7,55 +7,118 @@ on: tags: - "*.*.*" paths-ignore: - - '**/*.md' - - 'docs/**' + - '**/*.md' + - 'docs/**' + +env: + # Registry URLs + DOCKERHUB_REGISTRY: docker.io + GITHUB_REGISTRY: ghcr.io + + # Docker Hub image name (using Docker Hub username) + DOCKERHUB_IMAGE_NAME: ${{ secrets.DOCKER_USERNAME }}/${{ github.event.repository.name }} + # GitHub image name (formatted as `account/repo`) + GITHUB_IMAGE_NAME: ${{ github.repository }} + + ALPINE_VERSION: "23-alpine" + DEBIAN_VERSION: "23-slim" + jobs: - push_to_registry: - name: Push Docker image to Docker Hub + build_and_push_to_registries: + name: Push Docker images to Docker Hub and GitHub Container Registry + strategy: + matrix: + variant: [alpine, debian] runs-on: ubuntu-latest - if: ${{ vars.DOCKERHUB_IMAGE_NAME != '' || vars.GHCR_IMAGE_NAME != '' }} permissions: - packages: write contents: read + packages: write + # This is used to complete the identity challenge with sigstore/fulcio when running outside of PRs. + id-token: write + steps: - name: Check out the repo - uses: actions/checkout@v2 + uses: actions/checkout@v4.4.2 + + # Install the cosign tool (except on PR) + # https://github.com/sigstore/cosign-installer + - name: Install cosign + if: github.event_name != 'pull_request' + uses: sigstore/cosign-installer@v3.8.0 + with: + cosign-release: 'v2.2.4' + + # Set up BuildKit Docker container builder to be able to build multi-platform images and export cache + # https://github.com/docker/setup-buildx-action + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3.8.0 + + # Log in to Docker Hub (except on PR) - name: Log in to Docker Hub - if: ${{ github.event_name != 'pull_request' && vars.DOCKERHUB_IMAGE_NAME != '' - }} - uses: docker/login-action@v2 + if: github.event_name != 'pull_request' + uses: docker/login-action@v3.3.0 with: username: ${{ secrets.DOCKER_USERNAME }} password: ${{ secrets.DOCKER_PASSWORD }} - - name: Login to GitHub Container Registry - if: ${{ github.event_name != 'pull_request' && vars.GHCR_IMAGE_NAME != '' }} - uses: docker/login-action@v2 + + # Log in to GitHub Container Registry (except on PR) + - name: Log in to GitHub Container Registry + if: github.event_name != 'pull_request' + uses: docker/login-action@v3.3.0 with: - registry: ghcr.io + registry: ${{ env.GITHUB_REGISTRY }} username: ${{ github.repository_owner }} password: ${{ secrets.GITHUB_TOKEN }} - - name: Extract metadata (tags, labels) for Docker + + # Combined metadata extraction for both registries + - name: Extract Docker metadata id: meta - uses: docker/metadata-action@v3 + uses: docker/metadata-action@v5.6.1 with: images: | - ${{ vars.DOCKERHUB_IMAGE_NAME }} - ${{ vars.GHCR_IMAGE_NAME }} + ${{ env.DOCKERHUB_IMAGE_NAME }} + ${{ env.GITHUB_REGISTRY }}/${{ env.GITHUB_IMAGE_NAME }} tags: | - type=raw,value=latest,enable=${{ endsWith(github.ref, 'main') }} - type=ref,event=branch,enable=${{ !endsWith(github.ref, 'main') }} - type=semver,pattern={{version}} - flavor: | - latest=false + # Tag branches as type=ref,event=branch + # For Alpine variant, add suffix + type=ref,event=branch,suffix=-${{ matrix.variant }},enable=${{ matrix.variant == 'alpine' }} + type=ref,event=branch,enable=${{ matrix.variant == 'debian' }} + # Tag matrix.variant (Alpine) releases as version (1.0.0), major.minor (1.0), major (1), and matrix.variant (alpine) + type=semver,pattern={{version}},suffix=-${{ matrix.variant }},enable=${{ matrix.variant == 'alpine' }} + type=semver,pattern={{major}}.{{minor}},suffix=-${{ matrix.variant }},enable=${{ matrix.variant == 'alpine' }} + type=semver,pattern={{major}},suffix=-${{ matrix.variant }},enable=${{ matrix.variant == 'alpine' }} + type=raw,value=${{ matrix.variant }},enable=${{ matrix.variant == 'alpine' && github.ref == 'refs/heads/main' }} + # Tag default (Debian) releases as version (1.0.0), major.minor (1.0), major (1), and latest + type=semver,pattern={{version}},enable=${{ matrix.variant == 'debian' }} + type=semver,pattern={{major}}.{{minor}},enable=${{ matrix.variant == 'debian' }} + type=semver,pattern={{major}},enable=${{ matrix.variant == 'debian' }} + type=raw,value=latest,enable=${{ matrix.variant == 'debian' && github.ref == 'refs/heads/main' }} + - name: Set up QEMU - uses: docker/setup-qemu-action@v2 - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v2 + uses: docker/setup-qemu-action@v3.3.0 + + # Build and push Docker image with Buildx to both registries (don't push on PR) - name: Build and push Docker image - uses: docker/build-push-action@v4 + id: build-and-push + uses: docker/build-push-action@v6.13.0 with: context: . - push: ${{ github.event_name != 'pull_request' && !env.ACT}} + push: ${{ github.event_name != 'pull_request' }} tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} + build-args: | + VARIANT=${{ matrix.variant }} + ALPINE_VERSION=${{ env.ALPINE_VERSION }} + DEBIAN_VERSION=${{ env.DEBIAN_VERSION }} platforms: linux/amd64,linux/arm64 + cache-from: type=gha + cache-to: type=gha,mode=max + + # Sign the resulting Docker image digests + - name: Sign the published Docker images + if: ${{ github.event_name != 'pull_request' }} + env: + TAGS: ${{ steps.meta.outputs.tags }} + DIGEST: ${{ steps.build-and-push.outputs.digest }} + run: | + echo "${TAGS}" | xargs -I {} cosign sign --yes {}@${DIGEST} From 52a8cca3e86b8351a31f2d2c438cd98581de007d Mon Sep 17 00:00:00 2001 From: Kyle Affolder Date: Fri, 7 Feb 2025 13:06:17 -0500 Subject: [PATCH 05/26] fix(docker): broken build & run as non-root user --- Dockerfile | 48 ++++++++++++++++++++---------------------------- 1 file changed, 20 insertions(+), 28 deletions(-) diff --git a/Dockerfile b/Dockerfile index a5c7873..3bdb7f0 100644 --- a/Dockerfile +++ b/Dockerfile @@ -81,37 +81,29 @@ RUN apk add --no-cache sqlite tzdata iputils FROM final-${VARIANT} AS final +# Use a non-root user (recommended for security) +USER node + # Set the working directory WORKDIR /app -# Copy package files and necessary build artifacts from builder stage -COPY --from=builder /app/package.json /app/package-lock.json ./ -COPY --from=builder \ - /app/src/lib/i18n \ - /app/src/lib/locales \ - /app/src/lib/server \ - /app/src/lib/boringOne.js \ - /app/src/lib/clientTools.js \ - /app/src/lib/color.js \ - /app/src/lib/index.js \ - /app/src/lib/site.js \ - ./src/lib/ -COPY --from=builder \ - /app/build \ - /app/uploads \ - /app/database \ - /app/node_modules \ - /app/migrations \ - /app/seeds \ - /app/static \ - /app/embed.html \ - /app/knexfile.js \ - /app/main.js \ - /app/openapi.json \ - /app/openapi.yaml \ - /app/sitemap.js.bk \ - /app/utils.js \ - ./ +# Copy package files build artifacts, and necessary files from builder stage +COPY --chown=node:node --from=builder /app/package*.json ./ +COPY --chown=node:node --from=builder /app/src/lib/ ./src/lib/ +COPY --chown=node:node --from=builder /app/build ./build +COPY --chown=node:node --from=builder /app/uploads ./uploads +COPY --chown=node:node --from=builder /app/database ./database +COPY --chown=node:node --from=builder /app/node_modules ./node_modules +COPY --chown=node:node --from=builder /app/migrations ./migrations +COPY --chown=node:node --from=builder /app/seeds ./seeds +COPY --chown=node:node --from=builder /app/static ./static +COPY --chown=node:node --from=builder /app/embed.html ./embed.html +COPY --chown=node:node --from=builder /app/knexfile.js ./knexfile.js +COPY --chown=node:node --from=builder /app/main.js ./main.js +COPY --chown=node:node --from=builder /app/openapi.json ./openapi.json +COPY --chown=node:node --from=builder /app/openapi.yaml ./openapi.yaml +COPY --chown=node:node --from=builder /app/sitemap.js.bk ./sitemap.js.bk +COPY --chown=node:node --from=builder /app/utils.js ./utils.js # Set environment variables ARG PORT=3000 From 1dd05fee508eeeb0c0ddd262dde535561f23a43e Mon Sep 17 00:00:00 2001 From: Kyle Affolder Date: Fri, 7 Feb 2025 14:58:33 -0500 Subject: [PATCH 06/26] update: tweaked ordering of env variables --- .github/workflows/publishImage.yml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/.github/workflows/publishImage.yml b/.github/workflows/publishImage.yml index ba7da12..2613a97 100644 --- a/.github/workflows/publishImage.yml +++ b/.github/workflows/publishImage.yml @@ -11,18 +11,16 @@ on: - 'docs/**' env: + ALPINE_VERSION: "23-alpine" + DEBIAN_VERSION: "23-slim" # Registry URLs DOCKERHUB_REGISTRY: docker.io GITHUB_REGISTRY: ghcr.io - # Docker Hub image name (using Docker Hub username) DOCKERHUB_IMAGE_NAME: ${{ secrets.DOCKER_USERNAME }}/${{ github.event.repository.name }} # GitHub image name (formatted as `account/repo`) GITHUB_IMAGE_NAME: ${{ github.repository }} - ALPINE_VERSION: "23-alpine" - DEBIAN_VERSION: "23-slim" - jobs: build_and_push_to_registries: name: Push Docker images to Docker Hub and GitHub Container Registry From d349a7591e3001f86ef11ffd07884e4f08679117 Mon Sep 17 00:00:00 2001 From: Kyle Affolder Date: Sat, 8 Feb 2025 00:04:19 -0500 Subject: [PATCH 07/26] update(docker): ver. pinning, healthcheck, etc. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * add: version pinning (better stability) * remove: unnecessary KENER_BASE_PATH env. variable * update: reduce permissions of /uploads and /database directories * add: `entrypoint.sh` file * add: properly map container timezone and localtime * add: container healthcheck * change: restrict to non-root “node” user --- Dockerfile | 93 +++++++++++++++++++++++++++++++----------------------- 1 file changed, 53 insertions(+), 40 deletions(-) diff --git a/Dockerfile b/Dockerfile index 3bdb7f0..48803e8 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,8 +1,8 @@ # syntax=docker/dockerfile:1 # Global build arguments -ARG ALPINE_VERSION=23-alpine -ARG DEBIAN_VERSION=23-slim +ARG ALPINE_VERSION=23.7.0-alpine3.21 +ARG DEBIAN_VERSION=23.7.0-bookworm-slim ARG VARIANT=debian #==========================================================# @@ -11,37 +11,31 @@ ARG VARIANT=debian FROM node:${DEBIAN_VERSION} AS builder-debian RUN apt-get update && apt-get install -y \ - build-essential \ - python3 \ - sqlite3 \ - libsqlite3-dev \ - make \ - node-gyp \ - g++ \ - tzdata \ - iputils-ping && \ + build-essential=12.9 \ + python3=3.11.2-1+b1 \ + sqlite3=3.40.1-2+deb12u1 \ + libsqlite3-dev=3.40.1-2+deb12u1 \ + make=4.3-4.1 \ + node-gyp=9.3.0-2 \ + g++=4:12.2.0-3 \ + tzdata=2024b-0+deb12u1 \ + iputils-ping=3:20221126-1+deb12u1 && \ rm -rf /var/lib/apt/lists/* FROM node:${ALPINE_VERSION} AS builder-alpine -RUN apk add --no-cache \ - build-base \ - python3 \ - py3-pip \ - make \ - g++ \ - sqlite \ - sqlite-dev \ - tzdata \ - iputils +RUN apk add --no-cache --update \ + build-base=0.5-r3 \ + python3=3.12.9-r0 \ + py3-pip=24.3.1-r0 \ + make=4.4.1-r2 \ + g++=14.2.0-r4 \ + sqlite=3.48.0-r0 \ + sqlite-dev=3.48.0-r0 \ + tzdata=2024b-r1 \ + iputils=20240905-r0 FROM builder-${VARIANT} AS builder -# Set timezone and application environment -ARG KENER_BASE_PATH -ENV TZ=Etc/UTC \ - KENER_BASE_PATH=${KENER_BASE_PATH} \ - VITE_BUILD_ENV=production - # Set the working directory WORKDIR /app @@ -59,9 +53,10 @@ COPY . . # Remove docs directory and ensure required directories exist RUN rm -rf src/routes/\(docs\) && \ mkdir -p uploads database && \ - chmod -R 755 uploads database + chmod -R 750 uploads database # Build the application and remove `devDependencies` +ENV VITE_BUILD_ENV=production RUN npm run build && \ npm prune --omit=dev @@ -70,19 +65,28 @@ RUN npm run build && \ #==========================================================# FROM node:${DEBIAN_VERSION} AS final-debian -RUN apt-get update && apt-get install -y \ - sqlite3 \ - tzdata \ - iputils-ping && \ +RUN apt-get update && apt-get install --no-install-recommends -y \ + iputils-ping=3:20221126-1+deb12u1 \ + sqlite3=3.40.1-2+deb12u1 \ + tzdata=2024b-0+deb12u1 \ + wget=1.21.3-1+b1 && \ rm -rf /var/lib/apt/lists/* FROM node:${ALPINE_VERSION} AS final-alpine -RUN apk add --no-cache sqlite tzdata iputils +RUN apk add --no-cache --update \ + iputils=20240905-r0 \ + sqlite=3.48.0-r0 \ + tzdata=2024b-r1 FROM final-${VARIANT} AS final -# Use a non-root user (recommended for security) -USER node +ARG PORT=3000 \ + USERNAME=node + +# Set environment variables +ENV NODE_ENV=production \ + PORT=$PORT \ + TZ=Etc/UTC # Set the working directory WORKDIR /app @@ -98,6 +102,7 @@ COPY --chown=node:node --from=builder /app/migrations ./migrations COPY --chown=node:node --from=builder /app/seeds ./seeds COPY --chown=node:node --from=builder /app/static ./static COPY --chown=node:node --from=builder /app/embed.html ./embed.html +COPY --chown=node:node --from=builder /app/entrypoint.sh ./entrypoint.sh COPY --chown=node:node --from=builder /app/knexfile.js ./knexfile.js COPY --chown=node:node --from=builder /app/main.js ./main.js COPY --chown=node:node --from=builder /app/openapi.json ./openapi.json @@ -105,13 +110,21 @@ COPY --chown=node:node --from=builder /app/openapi.yaml ./openapi.yaml COPY --chown=node:node --from=builder /app/sitemap.js.bk ./sitemap.js.bk COPY --chown=node:node --from=builder /app/utils.js ./utils.js -# Set environment variables -ARG PORT=3000 -ENV PORT=$PORT \ - NODE_ENV=production +# Ensure necessary directories are writable +VOLUME ["/uploads", "/database"] + +# Set container timezone and make entrypoint script executable +RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone && \ + chmod +x ./entrypoint.sh # Expose the application port EXPOSE $PORT -# Run the application +HEALTHCHECK --interval=30s --timeout=5s --retries=3 \ + CMD wget --method=HEAD --quiet --spider http://localhost:$PORT || exit 1 + +# Use a non-root user (recommended for security) +USER $USERNAME + +ENTRYPOINT ["/app/entrypoint.sh"] CMD ["node", "main"] \ No newline at end of file From 1e77253a631eff986a3742c5a8387a36dbdf2a1d Mon Sep 17 00:00:00 2001 From: Kyle Affolder Date: Sat, 8 Feb 2025 02:12:31 -0500 Subject: [PATCH 08/26] update(docker): healthcheck port & path + cleanup --- .dockerignore | 3 +++ Dockerfile | 12 +++++++++--- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/.dockerignore b/.dockerignore index 6b107d1..f838579 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,4 +1,7 @@ node_modules +.git +.github +.vscode dist build .env diff --git a/Dockerfile b/Dockerfile index 48803e8..54545a0 100644 --- a/Dockerfile +++ b/Dockerfile @@ -36,6 +36,10 @@ RUN apk add --no-cache --update \ FROM builder-${VARIANT} AS builder +# Set environment variables +ENV NPM_CONFIG_LOGLEVEL=error \ + VITE_BUILD_ENV=production + # Set the working directory WORKDIR /app @@ -56,7 +60,6 @@ RUN rm -rf src/routes/\(docs\) && \ chmod -R 750 uploads database # Build the application and remove `devDependencies` -ENV VITE_BUILD_ENV=production RUN npm run build && \ npm prune --omit=dev @@ -84,7 +87,10 @@ ARG PORT=3000 \ USERNAME=node # Set environment variables -ENV NODE_ENV=production \ +ENV HEALTHCHECK_PORT=$PORT \ + HEALTHCHECK_PATH= \ + NODE_ENV=production \ + NPM_CONFIG_LOGLEVEL=error \ PORT=$PORT \ TZ=Etc/UTC @@ -121,7 +127,7 @@ RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone & EXPOSE $PORT HEALTHCHECK --interval=30s --timeout=5s --retries=3 \ - CMD wget --method=HEAD --quiet --spider http://localhost:$PORT || exit 1 + CMD wget --quiet --spider http://localhost:$HEALTHCHECK_PORT$HEALTHCHECK_PATH || exit 1 # Use a non-root user (recommended for security) USER $USERNAME From 43673e33495b67b1f2399486712483e1fbbb1d4c Mon Sep 17 00:00:00 2001 From: Kyle Affolder Date: Sat, 8 Feb 2025 04:08:45 -0500 Subject: [PATCH 09/26] add(workflow): allow admin to manually build --- .github/workflows/publishImage.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/publishImage.yml b/.github/workflows/publishImage.yml index 2613a97..a6680aa 100644 --- a/.github/workflows/publishImage.yml +++ b/.github/workflows/publishImage.yml @@ -9,14 +9,14 @@ on: paths-ignore: - '**/*.md' - 'docs/**' + workflow_dispatch: # Allows manual execution env: ALPINE_VERSION: "23-alpine" DEBIAN_VERSION: "23-slim" # Registry URLs DOCKERHUB_REGISTRY: docker.io - GITHUB_REGISTRY: ghcr.io - # Docker Hub image name (using Docker Hub username) + GITHUB_REGISTRY: ghcr.io # Docker Hub image name (using Docker Hub username) DOCKERHUB_IMAGE_NAME: ${{ secrets.DOCKER_USERNAME }}/${{ github.event.repository.name }} # GitHub image name (formatted as `account/repo`) GITHUB_IMAGE_NAME: ${{ github.repository }} From 13dec43ef3e4e4209c69a0386a6f6ccb8db57ad7 Mon Sep 17 00:00:00 2001 From: Kyle Affolder Date: Sat, 8 Feb 2025 04:12:50 -0500 Subject: [PATCH 10/26] update(docker): expanded docker readme section MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Expanded upon existing Docker README section. * Created table which will contains version placeholder variables that will be replaced by new GitHub workflow job: “update_readme”. Job automatically runs after new images have been built & pushed to container registries. --- .github/workflows/publishImage.yml | 46 +++++++++++++++++- README.md | 75 +++++++++++++++++++++++++++++- 2 files changed, 118 insertions(+), 3 deletions(-) diff --git a/.github/workflows/publishImage.yml b/.github/workflows/publishImage.yml index a6680aa..3961832 100644 --- a/.github/workflows/publishImage.yml +++ b/.github/workflows/publishImage.yml @@ -16,7 +16,8 @@ env: DEBIAN_VERSION: "23-slim" # Registry URLs DOCKERHUB_REGISTRY: docker.io - GITHUB_REGISTRY: ghcr.io # Docker Hub image name (using Docker Hub username) + GITHUB_REGISTRY: ghcr.io + # Docker Hub image name (using Docker Hub username) DOCKERHUB_IMAGE_NAME: ${{ secrets.DOCKER_USERNAME }}/${{ github.event.repository.name }} # GitHub image name (formatted as `account/repo`) GITHUB_IMAGE_NAME: ${{ github.repository }} @@ -120,3 +121,46 @@ jobs: DIGEST: ${{ steps.build-and-push.outputs.digest }} run: | echo "${TAGS}" | xargs -I {} cosign sign --yes {}@${DIGEST} + + update_readme: + needs: build_and_push_to_registries # Runs only after build_and_push_to_registries completes successfully + name: Update README with release versions + runs-on: ubuntu-latest + + steps: + - name: Checkout Repository + uses: actions/checkout@v4.4.2 + + - name: Extract Release Versions + id: meta + uses: docker/metadata-action@v5.6.1 + with: + images: rajnandan1/kener + tags: | + type=semver,pattern={{version}} + type=semver,pattern={{major}}.{{minor}} + type=semver,pattern={{major}} + + - name: Set Environment Variables + run: | + echo "KENER_SEMVER_VERSION=${{ steps.meta.outputs.version }}" >> $GITHUB_ENV + echo "KENER_MAJOR_MINOR_VERSION=${{ steps.meta.outputs.major }}.${{ steps.meta.outputs.minor }}" >> $GITHUB_ENV + echo "KENER_MAJOR_VERSION=${{ steps.meta.outputs.major }}" >> $GITHUB_ENV + + - name: Safetly Update README.md + run: | + KENER_SEMVER_VERSION_ESCAPED=$(printf '%s\n' "${{ env.KENER_SEMVER_VERSION }}" | sed 's/[&/\]/\\&/g') + KENER_MAJOR_MINOR_VERSION_ESCAPED=$(printf '%s\n' "${{ env.KENER_MAJOR_MINOR_VERSION }}" | sed 's/[&/\]/\\&/g') + KENER_MAJOR_VERSION_ESCAPED=$(printf '%s\n' "${{ env.KENER_MAJOR_VERSION }}" | sed 's/[&/\]/\\&/g') + + sed -i "s/KENER_SEMVER_VERSION_PLACEHOLDER/${KENER_SEMVER_VERSION_ESCAPED}/g" README.md + sed -i "s/KENER_MAJOR_MINOR_VERSION_PLACEHOLDER/${KENER_MAJOR_MINOR_VERSION_ESCAPED}/g" README.md + sed -i "s/KENER_MAJOR_VERSION_PLACEHOLDER/${KENER_MAJOR_VERSION_ESCAPED}/g" README.md + + - name: Commit and Push Changes + run: | + git config --global user.name 'github-actions' + git config --global user.email 'github-actions@github.com' + git add README.md + git commit -m "Update README with latest versions: ${{ env.KENER_SEMVER_VERSION }}" || exit 0 + git push \ No newline at end of file diff --git a/README.md b/README.md index cd9d1f8..f314897 100644 --- a/README.md +++ b/README.md @@ -59,8 +59,79 @@ npm run dev ### Docker -The latest image is available on DockerHub at [`rajnandan1/kener:latest`](https://hub.docker.com/r/rajnandan1/kener/tags?page=1&ordering=last_updated&name=latest). -Download and use the sample [docker-compose.yml](https://github.com/rajnandan1/kener/blob/main/docker-compose.yml). +Official Docker images for **Kener** are available on [Docker Hub](https://hub.docker.com/r/rajnandan1/kener). Multiple versions are maintained to support different use cases. + +![Docker Image Version (latest semver)](https://img.shields.io/docker/v/rajnandan1/kener?sort=semver&label=Latest%20Stable%20Release) + +#### Available Tags + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Image TagDescription
+ Debian + Debian 12 (Bookwork Slim) w/ Node.js v23.7.0  (default) +
latestLatest stable release (aka KENER_SEMVER_VERSION_PLACEHOLDER)
KENER_SEMVER_VERSION_PLACEHOLDERSpecific release version
KENER_MAJOR_MINOR_VERSION_PLACEHOLDERMajor-minor version tag pointing to the latest patch (KENER_SEMVER_VERSION_PLACEHOLDER) release within that minor version (KENER_MAJOR_MINOR_VERSION_PLACEHOLDER.x)
KENER_MAJOR_VERSION_PLACEHOLDERMajor version tag pointing to the latest stable (KENER_SEMVER_VERSION_PLACEHOLDER) release within that major version (KENER_MAJOR_VERSION_PLACEHOLDER.x.x)
+ Alpine Linux + Alpine Linux 3.21 w/ Node.js v23.7.0  (smallest image size) +
alpineLatest stable release (aka KENER_SEMVER_VERSION_PLACEHOLDER)
KENER_SEMVER_VERSION_PLACEHOLDER-alpineSpecific release version
KENER_MAJOR_MINOR_VERSION_PLACEHOLDER-alpineMajor-minor version tag pointing to the latest patch (KENER_SEMVER_VERSION_PLACEHOLDER) release within that minor version (KENER_MAJOR_MINOR_VERSION_PLACEHOLDER.x)
KENER_MAJOR_VERSION_PLACEHOLDER-alpineMajor version tag pointing to the latest stable (KENER_SEMVER_VERSION_PLACEHOLDER) release within that major version (KENER_MAJOR_VERSION_PLACEHOLDER.x.x)
+ +#### Usage + +Pull the latest stable version: + +```sh +docker pull rajnandan1/kener:latest +``` + +Or use the smaller, Alpine-based variant: + +```sh +docker pull rajnandan1/kener:alpine +``` + +For a production setup, refer to the sample [docker-compose.yml](https://github.com/rajnandan1/kener/blob/main/docker-compose.yml). +This keeps things clean, structured, and easy to read while preserving all the details. Let me know if you want any refinements! 🚀 ### One Click From ec7351272fbc08de1e03f24ee3050a259acdbb8d Mon Sep 17 00:00:00 2001 From: Kyle Affolder Date: Sat, 8 Feb 2025 04:13:47 -0500 Subject: [PATCH 11/26] add(docker): missing `entrypoint.sh` file --- entrypoint.sh | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 entrypoint.sh diff --git a/entrypoint.sh b/entrypoint.sh new file mode 100644 index 0000000..432e624 --- /dev/null +++ b/entrypoint.sh @@ -0,0 +1,8 @@ +#!/bin/sh +set -e + +# Automatically set PUBLIC_WHITE_LABEL based on WHITE_LABEL +export PUBLIC_WHITE_LABEL="${WHITE_LABEL}" + +# Replace shell with the given command (from CMD or runtime args) +exec "$@" \ No newline at end of file From 2a338baa26006547ce5b1d66d566e53b0125e3ee Mon Sep 17 00:00:00 2001 From: Kyle Affolder Date: Sat, 8 Feb 2025 04:17:16 -0500 Subject: [PATCH 12/26] fix(README): remove broken icons that were added --- README.md | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index f314897..ac88b83 100644 --- a/README.md +++ b/README.md @@ -71,10 +71,7 @@ Official Docker images for **Kener** are available on [Docker Hub](https://hub.d Description - - Debian - Debian 12 (Bookwork Slim) w/ Node.js v23.7.0  (default) - + Debian 12 (Bookwork Slim) w/ Node.js v23.7.0  (default) latest @@ -93,10 +90,7 @@ Official Docker images for **Kener** are available on [Docker Hub](https://hub.d Major version tag pointing to the latest stable (KENER_SEMVER_VERSION_PLACEHOLDER) release within that major version (KENER_MAJOR_VERSION_PLACEHOLDER.x.x) - - Alpine Linux - Alpine Linux 3.21 w/ Node.js v23.7.0  (smallest image size) - + Alpine Linux 3.21 w/ Node.js v23.7.0  (smallest image size) alpine From 820eeb0aaceb382d1ed3b864294129f6265f1207 Mon Sep 17 00:00:00 2001 From: Kyle Affolder Date: Sat, 8 Feb 2025 04:18:27 -0500 Subject: [PATCH 13/26] fix(README): table subheading alignment --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index ac88b83..06c8568 100644 --- a/README.md +++ b/README.md @@ -71,7 +71,7 @@ Official Docker images for **Kener** are available on [Docker Hub](https://hub.d Description - Debian 12 (Bookwork Slim) w/ Node.js v23.7.0  (default) + Debian 12 (Bookwork Slim) w/ Node.js v23.7.0  (default) latest @@ -90,7 +90,7 @@ Official Docker images for **Kener** are available on [Docker Hub](https://hub.d Major version tag pointing to the latest stable (KENER_SEMVER_VERSION_PLACEHOLDER) release within that major version (KENER_MAJOR_VERSION_PLACEHOLDER.x.x) - Alpine Linux 3.21 w/ Node.js v23.7.0  (smallest image size) + Alpine Linux 3.21 w/ Node.js v23.7.0  (smallest image size) alpine From 654c07a364e9f7fdcee4d2da753b0a08a1f061eb Mon Sep 17 00:00:00 2001 From: Kyle Affolder Date: Sat, 8 Feb 2025 04:19:34 -0500 Subject: [PATCH 14/26] fix(README): table subheading alignment --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 06c8568..7110983 100644 --- a/README.md +++ b/README.md @@ -71,7 +71,7 @@ Official Docker images for **Kener** are available on [Docker Hub](https://hub.d Description - Debian 12 (Bookwork Slim) w/ Node.js v23.7.0  (default) + Debian 12 (Bookwork Slim) w/ Node.js v23.7.0  (default) latest @@ -90,7 +90,7 @@ Official Docker images for **Kener** are available on [Docker Hub](https://hub.d Major version tag pointing to the latest stable (KENER_SEMVER_VERSION_PLACEHOLDER) release within that major version (KENER_MAJOR_VERSION_PLACEHOLDER.x.x) - Alpine Linux 3.21 w/ Node.js v23.7.0  (smallest image size) + Alpine Linux 3.21 w/ Node.js v23.7.0  (smallest image size) alpine From e923f4d6501e66221620c537e0834eeecc4cb598 Mon Sep 17 00:00:00 2001 From: Kyle Affolder Date: Sat, 8 Feb 2025 04:48:30 -0500 Subject: [PATCH 15/26] =?UTF-8?q?update(README):=20proofread=20and=20polis?= =?UTF-8?q?hed=20=E2=98=BA=EF=B8=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 83 ++++++++++++++++++++++++++++--------------------------- 1 file changed, 43 insertions(+), 40 deletions(-) diff --git a/README.md b/README.md index 7110983..ba058ef 100644 --- a/README.md +++ b/README.md @@ -35,13 +35,19 @@ ## What is Kener? -Kener is status page system built with Sveltekit and NodeJS. It does not try to replace the Datadogs and Atlassian of the world. It tries to help some who wants to come up with a status page that looks nice and minimum overhead, in a modern way. +**Kener** is a sleek and lightweight status page system built with **SvelteKit** and **NodeJS**. It’s not here to replace heavyweights like Datadog or Atlassian but rather to offer a simple, modern, and hassle-free way to set up a great-looking status page with minimal effort. -It is carefully crafted to be easy to use and customize. +Designed with **ease of use** and **customization in mind**, Kener provides all the essential features you’d expect from a status page—without unnecessary complexity. -It comes with all the basic asks for a status page. It is open-source and free to use. +### Why Kener? -Kener name is derived from the word "Kene" which means "how is it going" in Assamese, then .ing because it was a cheaply available domain. +✅  Minimal overhead – Set up quickly with a clean, modern UI
+✅  Customizable – Easily tailor it to match your brand
+✅  Open-source & free – Because great tools should be accessible to everyone + +### What's in a Name? + +“Kener” is inspired by the Assamese word _“Kene”_, meaning _“how’s it going?”_. The _‘.ing’_ was added because, well… the domain was available. 😄 ## Installation @@ -125,7 +131,7 @@ docker pull rajnandan1/kener:alpine ``` For a production setup, refer to the sample [docker-compose.yml](https://github.com/rajnandan1/kener/blob/main/docker-compose.yml). -This keeps things clean, structured, and easy to read while preserving all the details. Let me know if you want any refinements! 🚀 +This keeps things clean, structured, and easy to read while preserving all the details. ### One Click @@ -135,44 +141,41 @@ This keeps things clean, structured, and easy to read while preserving all the d Here are some of the features that you get out of the box. Please read the documentation to know how to use them. -### Monitoring and Tracking +### 📊 Monitoring and Tracking -- Advanced application performance monitoring tools -- Real-time network monitor software capabilities -- Polls HTTP endpoint or Push data to monitor using Rest APIs -- Adjusts Timezones for visitors -- Categorize Monitors into different Sections -- Cron-based scheduling for monitors. Minimum per minute -- Construct complex API Polls - Chain, Secrets etc -- Supports a Default Status for Monitors -- Supports base path for hosting in k8s -- Pre-built docker image for easy deployment -- Automatically adjusts timezones for visitors +- Advanced **application performance monitoring** tools +- **Real-time network monitoring** capabilities +- Supports **polling HTTP endpoints** or **pushing data** via REST APIs +- **Timezone auto-adjustment** for visitors +- Organize monitors into **custom sections** +- **Cron-based scheduling** (minimum: **every minute**) +- **Create complex API polls** (chaining, secrets, etc.) +- Set a **default status** for monitors +- Supports **base path hosting in Kubernetes (k8s)** +- **Pre-built Docker images** for easy deployment -### Customization and Branding +### 🎨 Customization and Branding -- Customizable status page -- Badge generation for status and uptime of Monitors -- Support for custom domains -- Embed Monitor as an iframe or widget -- Light + Dark Theme -- Internationalization support -- Beautifully Crafted Status Page +- Fully **customizable status page** +- **Badge generation** for status and uptime tracking +- Support for **custom domains** +- Embed monitors as **iframes or widgets** +- **Light & Dark Mode** +- **Internationalization (i18n) support** +- **Sleek, beautifully crafted UI** -### Incident Management +### 🚨 Incident Management -- Incident Management -- Incident Communication -- Comprehensive APIs for Incident Management +- **Incident tracking & communication** tools +- **Comprehensive APIs** for incident management -### User Experience and Design +### 🧑‍💻 User Experience and Design -- Good Accessibility Score -- Easy installation and setup -- User-friendly interface -- Responsive design for various devices -- Auto SEO and Social Media ready -- Server Side Rendering +- **Accessible & user-friendly interface** +- **Quick & easy installation** +- **Responsive design** for all devices +- **Auto SEO & Social Media ready** +- **Server-Side Rendering (SSR) for better performance**

@@ -180,24 +183,24 @@ Here are some of the features that you get out of the box. Please read the docum
-## Technologies used +## Technologies Used - [SvelteKit](https://kit.svelte.dev/) - [shadcn-svelte](https://www.shadcn-svelte.com/) ## Support Me -If you are using Kener and want to support me, you can do so by sponsoring me on GitHub or buying me a coffee. +If you’re enjoying Kener and want to support its development, consider sponsoring me on GitHub or treating me to a coffee. Your support helps keep the project growing! 🚀 [Sponsor Me Using Github](https://github.com/sponsors/rajnandan1) -[Buy Me a Coffee](https://www.buymeacoffee.com/rajnandan1) +☕ [Buy Me a Coffee](https://www.buymeacoffee.com/rajnandan1) ![image](https://badges.pufler.dev/visits/rajnandan1/kener) ## Contributing -If you want to contribute to Kener, please read the [Contributing Guide](https://github.com/rajnandan1/kener/blob/main/.github/CONTRIBUTING.md). +If you want to contribute to Kener, please read the [Contribution Guide](https://github.com/rajnandan1/kener/blob/main/.github/CONTRIBUTING.md). ## Star History From c00aae5566ea7fc9a6cece9166e65123a04e7766 Mon Sep 17 00:00:00 2001 From: Kyle Affolder Date: Sat, 8 Feb 2025 04:50:06 -0500 Subject: [PATCH 16/26] update(README): adjusted emoji spacing --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index ba058ef..782932f 100644 --- a/README.md +++ b/README.md @@ -141,7 +141,7 @@ This keeps things clean, structured, and easy to read while preserving all the d Here are some of the features that you get out of the box. Please read the documentation to know how to use them. -### 📊 Monitoring and Tracking +### 📊  Monitoring and Tracking - Advanced **application performance monitoring** tools - **Real-time network monitoring** capabilities @@ -154,7 +154,7 @@ Here are some of the features that you get out of the box. Please read the docum - Supports **base path hosting in Kubernetes (k8s)** - **Pre-built Docker images** for easy deployment -### 🎨 Customization and Branding +### 🎨  Customization and Branding - Fully **customizable status page** - **Badge generation** for status and uptime tracking @@ -164,12 +164,12 @@ Here are some of the features that you get out of the box. Please read the docum - **Internationalization (i18n) support** - **Sleek, beautifully crafted UI** -### 🚨 Incident Management +### 🚨  Incident Management - **Incident tracking & communication** tools - **Comprehensive APIs** for incident management -### 🧑‍💻 User Experience and Design +### 🧑‍💻  User Experience and Design - **Accessible & user-friendly interface** - **Quick & easy installation** @@ -194,7 +194,7 @@ If you’re enjoying Kener and want to support its development, consider sponsor [Sponsor Me Using Github](https://github.com/sponsors/rajnandan1) -☕ [Buy Me a Coffee](https://www.buymeacoffee.com/rajnandan1) +☕  [Buy Me a Coffee](https://www.buymeacoffee.com/rajnandan1) ![image](https://badges.pufler.dev/visits/rajnandan1/kener) From d03a8fd7a4ee254c58df5270d89698f7bd6e5750 Mon Sep 17 00:00:00 2001 From: Kyle Affolder Date: Sat, 8 Feb 2025 04:52:17 -0500 Subject: [PATCH 17/26] update(README): fix typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 782932f..37b4069 100644 --- a/README.md +++ b/README.md @@ -47,7 +47,7 @@ Designed with **ease of use** and **customization in mind**, Kener provides all ### What's in a Name? -“Kener” is inspired by the Assamese word _“Kene”_, meaning _“how’s it going?”_. The _‘.ing’_ was added because, well… the domain was available. 😄 +“Kener” is inspired by the Assamese word _“Kene”_, meaning _“how’s it going?”_. The _‘.ing’_ was added because, well… that domain was available. 😄 ## Installation From d0ea8551b652801a21e7724cca271c630ee323bd Mon Sep 17 00:00:00 2001 From: Kyle Affolder Date: Sat, 8 Feb 2025 13:56:11 -0500 Subject: [PATCH 18/26] update(docker): add TODO comments for future work --- Dockerfile | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Dockerfile b/Dockerfile index 54545a0..9300498 100644 --- a/Dockerfile +++ b/Dockerfile @@ -54,6 +54,7 @@ RUN --mount=type=cache,target=/root/.npm \ # Copy application source code COPY . . +# TODO: Reevaluate permissions... # Remove docs directory and ensure required directories exist RUN rm -rf src/routes/\(docs\) && \ mkdir -p uploads database && \ @@ -67,6 +68,7 @@ RUN npm run build && \ # STAGE 2: PRODUCTION STAGE # #==========================================================# +# TODO: Confirm with @rajnandan1 which of these packages are necessary for the Debian (default), production build FROM node:${DEBIAN_VERSION} AS final-debian RUN apt-get update && apt-get install --no-install-recommends -y \ iputils-ping=3:20221126-1+deb12u1 \ @@ -75,6 +77,7 @@ RUN apt-get update && apt-get install --no-install-recommends -y \ wget=1.21.3-1+b1 && \ rm -rf /var/lib/apt/lists/* +# TODO: Confirm with @rajnandan1 which of these packages are necessary for the Alpine Linux, production build FROM node:${ALPINE_VERSION} AS final-alpine RUN apk add --no-cache --update \ iputils=20240905-r0 \ @@ -97,12 +100,14 @@ ENV HEALTHCHECK_PORT=$PORT \ # Set the working directory WORKDIR /app +# TODO: Confirm with @rajnandan1 which files/directories are absolutely necessary for production build # Copy package files build artifacts, and necessary files from builder stage COPY --chown=node:node --from=builder /app/package*.json ./ COPY --chown=node:node --from=builder /app/src/lib/ ./src/lib/ COPY --chown=node:node --from=builder /app/build ./build COPY --chown=node:node --from=builder /app/uploads ./uploads COPY --chown=node:node --from=builder /app/database ./database +# TODO: Consider changing from copying `node_modules` to instead letting `npm ci --omit=dev` handle production dependencies. Right now, copying `node_modules` is leading to a smaller image, whereas letting `npm ci` handle the install in final image is slightly faster, but leads to larger image size. IMO, having a slightly longer build time (e.g. ~10 sec.) is better in the end to have a smaller image. COPY --chown=node:node --from=builder /app/node_modules ./node_modules COPY --chown=node:node --from=builder /app/migrations ./migrations COPY --chown=node:node --from=builder /app/seeds ./seeds @@ -126,9 +131,11 @@ RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone & # Expose the application port EXPOSE $PORT +# TODO: Consider switching to lighter-weight `nc` (Netcat) command-line utility (would remove `wget` in Debian build, however, it's already pretty small, so probably doesn't matter as `wget` is more powerful) HEALTHCHECK --interval=30s --timeout=5s --retries=3 \ CMD wget --quiet --spider http://localhost:$HEALTHCHECK_PORT$HEALTHCHECK_PATH || exit 1 +# TODO: Revisit letting user define $PUID & $PGID overrides as well as `addgroup -g $PGID newgroup && adduser -D -G newgroup -u $PUID node` functionality # Use a non-root user (recommended for security) USER $USERNAME From 9bbe665984ffcd82efcd1f86390efc387fc3f054 Mon Sep 17 00:00:00 2001 From: Kyle Affolder Date: Sat, 8 Feb 2025 14:22:16 -0500 Subject: [PATCH 19/26] update(docker): add TODO comments for future work --- Dockerfile | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/Dockerfile b/Dockerfile index 9300498..eb2d8bc 100644 --- a/Dockerfile +++ b/Dockerfile @@ -54,10 +54,11 @@ RUN --mount=type=cache,target=/root/.npm \ # Copy application source code COPY . . -# TODO: Reevaluate permissions... +# TODO: Reevaluate permissions (possibly reduce?)... # Remove docs directory and ensure required directories exist RUN rm -rf src/routes/\(docs\) && \ mkdir -p uploads database && \ + # TODO: Consider changing below to `chmod -R u-rwX,g=rX,o= uploads database` chmod -R 750 uploads database # Build the application and remove `devDependencies` @@ -65,11 +66,11 @@ RUN npm run build && \ npm prune --omit=dev #==========================================================# -# STAGE 2: PRODUCTION STAGE # +# STAGE 2: PRODUCTION/FINAL STAGE # #==========================================================# -# TODO: Confirm with @rajnandan1 which of these packages are necessary for the Debian (default), production build FROM node:${DEBIAN_VERSION} AS final-debian +# TODO: Confirm with @rajnandan1 which of these packages are necessary for the Debian (default), final stage RUN apt-get update && apt-get install --no-install-recommends -y \ iputils-ping=3:20221126-1+deb12u1 \ sqlite3=3.40.1-2+deb12u1 \ @@ -77,8 +78,8 @@ RUN apt-get update && apt-get install --no-install-recommends -y \ wget=1.21.3-1+b1 && \ rm -rf /var/lib/apt/lists/* -# TODO: Confirm with @rajnandan1 which of these packages are necessary for the Alpine Linux, production build FROM node:${ALPINE_VERSION} AS final-alpine +# TODO: Confirm with @rajnandan1 which of these packages are necessary for the Alpine Linux, final stage RUN apk add --no-cache --update \ iputils=20240905-r0 \ sqlite=3.48.0-r0 \ @@ -127,6 +128,12 @@ VOLUME ["/uploads", "/database"] # Set container timezone and make entrypoint script executable RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone && \ chmod +x ./entrypoint.sh + # TODO: To improve security, consider dropping unnecessary capabilities instead of granting image all network capabilities of host. (Maybe `setcap cap_net_raw+p /usr/bin/ping`, etc.) Could also drop all and then grant only the capabilities that are explicitly needed. Some examples are commented out below... + # setcap cap_net_bind_service=+ep /usr/local/bin/node + # setcap cap_net_bind_service=+ep /usr/bin/ping + # setcap cap_net_bind_service=+ep /usr/bin/ping6 + # setcap cap_net_bind_service=+ep /usr/bin/tracepath + # setcap cap_net_bind_service=+ep /usr/bin/clockdiff # Expose the application port EXPOSE $PORT @@ -135,7 +142,7 @@ EXPOSE $PORT HEALTHCHECK --interval=30s --timeout=5s --retries=3 \ CMD wget --quiet --spider http://localhost:$HEALTHCHECK_PORT$HEALTHCHECK_PATH || exit 1 -# TODO: Revisit letting user define $PUID & $PGID overrides as well as `addgroup -g $PGID newgroup && adduser -D -G newgroup -u $PUID node` functionality +# TODO: Revisit letting user define $PUID & $PGID overrides (e.g. `addgroup -g $PGID newgroup && adduser -D -G newgroup -u $PUID node`) as well as potentially ensure no root user exists. (Make sure no processes are running as root, first!) # Use a non-root user (recommended for security) USER $USERNAME From 974976bd90cfa5e117efd2f6c94a68e1e88abd6b Mon Sep 17 00:00:00 2001 From: Kyle Affolder Date: Sat, 8 Feb 2025 15:31:32 -0500 Subject: [PATCH 20/26] update(docker): expanded on existing examples --- .env.example | 32 +++++++++++++++------- docker-compose.yml | 67 +++++++++++++++++++++++++++++++++++----------- 2 files changed, 74 insertions(+), 25 deletions(-) diff --git a/.env.example b/.env.example index 518b920..fbfaca4 100644 --- a/.env.example +++ b/.env.example @@ -1,12 +1,26 @@ -KENER_SECRET_KEY=please_change_me -NODE_ENV=production -PORT=3000 -KENER_BASE_PATH="" -RESEND_API_KEY= -ORIGIN=http://localhost:3000 +TZ=Etc/UTC +KENER_SECRET_KEY=please_change_me_to_something_secure + +# For SQLite database... DATABASE_URL=sqlite://./database/kener.sqlite.db -TZ=UTC + +# For PostgreSQL database... +# DATABASE_URL=postgresql://db_user:db_password@localhost:5432/kener_db +# POSTGRES_PASSWORD=some_super_random_secure_password + +# For MySQL database... +# DATABASE_URL=mysql://db_user:db_password@127.0.0.1:3306/kener_db +# MYSQL_PASSWORD=some_super_random_secure_password + +KENER_BASE_PATH="" +ORIGIN=http://localhost:3000 + +RESEND_API_KEY="" RESEND_SENDER_EMAIL=Accounts -# DATABASE_URL=postgresql://myuser:mypassword@localhost:5432/mydatabase -# DATABASE_URL=mysql://root:password@127.0.0.1:3306/kener \ No newline at end of file +# Likely no need to change... +# NODE_ENV=production # already defined in container +# PORT=3000 # default port Kener service is exposed upon + +# Add the below variable if you would like to ‘white-label’ the product (aka. remove some of the attributions scattered throughout the app) +# WHITE_LABEL=true \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index 12b029b..039eddf 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,26 +1,61 @@ +# Docker Compose Configuration +# Description: This file sets up a multi-container environment for Kener (https://github.com/rajnandan1/kener). +# Last Updated: 2025-02-08 +# Docker Compose Version: 3.8 +# Notes: Ensure that you specify a random value for the `KENER_SECRET_KEY` environment variable before running `docker-compose up -d`. + version: '3.8' + services: kener: - image: rajnandan1/kener:latest + image: rajnandan1/kener:latest # Change to 'rajnandan1/kener:alpine' for an even smaller image! 😁🚀 container_name: kener - #env_file: .env #uncomment this, if you are using .env file + # env_file: custom.env # Uncomment this if you are needing to export environment variables from a custom environment file. By default, Docker will import any variables that exist in `.env` environment: - - TZ=Etc/UTC - - NODE_ENV=production - #- PORT=3000 - #- KENER_BASE_PATH= - #- RESEND_API_KEY= - #- ORIGIN= - #- KENER_SECRET_KEY= - #- RESEND_SENDER_EMAIL= - #- DATABASE_URL= + TZ: Etc/UTC + KENER_SECRET_KEY: replace_me_with_a_random_string # Keep private!! - best to define in `.env` file or through Docker Secret + # DATABASE_URL: custom_db_url # By default, a SQLite database is used - you may override the database url/type here + # RESEND_API_KEY: + # RESEND_SENDER_EMAIL: + ### You most likely will NOT need to change anything below this line. Be sure you know what you're doing!! (https://kener.ing/docs/deployment/#docker-environment-variables) - ### Most likely DO NOT need to change anything below this ### - - #- PORT=3000 Port app listens on IN CONTAINER + # PORT: 3000 # Port that app listens on in the container + # KENER_BASE_PATH: # By default, Kener runs at `/`. You may change this to be, e.g. `/status`, etc. Do NOT add a trailing slash!! (more info here: https://kener.ing/docs/deployment/#docker-environment-variables) + # ORIGIN: http://localhost:3000 + # NODE_ENV: production # This is already set to "production" by default within the container ports: - '3000:3000/tcp' volumes: - - '.:/app/database:rw' - - '.:/app/uploads:rw' + - data:/app/database # We suggest using a Docker named volume, which is more performant for databases + - $(pwd)/uploads:/app/uploads + # read_only: true # Uncommenting this fortifies security by marking the container's filesystem as read-only (aka no data can be written to the container's filesystem except for explicitly defined writable volumes and bind mounts, an exception has already been defined for `/database` and `/uploads`) + restart: unless-stopped + # depends_on: # <-- Uncomment if you would like to use PostgreSQL or MySQL + # - postgres # ...instead of SQLite + # - mysql # + + # Only use below section if you would like to utilize PostgreSQL instead of Kener's default SQLite database. (Don't forget to set `DATABASE_URL` in `kener` service to be: `DATABASE_URL=postgresql://db_user:db_password@localhost:5432/kener_db`) + postgres: + image: postgres:alpine + name: kener_db + environment: + POSTGRES_USER: user + POSTGRES_PASSWORD: some_super_random_secure_password # Best to define this in `.env` or via Docker Secret!! + POSTGRES_DB: kener_db + restart: unless-stopped + + # Only use below section if you would like to utilize MySQL instead of Kener's default SQLite database. (Don't forget to set `DATABASE_URL` in `kener` service to be: `DATABASE_URL=mysql://db_user:db_password@localhost:3306/kener_db`) + mysql: + image: mariadb:11 + name: kener_db + environment: + MYSQL_USER: user + MYSQL_PASSWORD: some_super_random_secure_password # Best to define this in `.env` or via Docker Secret!! + MYSQL_DATABASE: kener_db + MYSQL_RANDOM_ROOT_PASSWORD: true + restart: unless-stopped + +volumes: + data: + name: kener_db \ No newline at end of file From d552f541ac698a0599289d726e92c6b06120bd18 Mon Sep 17 00:00:00 2001 From: Kyle Affolder Date: Sun, 9 Feb 2025 00:35:59 -0500 Subject: [PATCH 21/26] fix(docker): remove unnecessary files from build --- Dockerfile | 4 ---- 1 file changed, 4 deletions(-) diff --git a/Dockerfile b/Dockerfile index eb2d8bc..5ed9872 100644 --- a/Dockerfile +++ b/Dockerfile @@ -103,7 +103,6 @@ WORKDIR /app # TODO: Confirm with @rajnandan1 which files/directories are absolutely necessary for production build # Copy package files build artifacts, and necessary files from builder stage -COPY --chown=node:node --from=builder /app/package*.json ./ COPY --chown=node:node --from=builder /app/src/lib/ ./src/lib/ COPY --chown=node:node --from=builder /app/build ./build COPY --chown=node:node --from=builder /app/uploads ./uploads @@ -113,14 +112,11 @@ COPY --chown=node:node --from=builder /app/node_modules ./node_modules COPY --chown=node:node --from=builder /app/migrations ./migrations COPY --chown=node:node --from=builder /app/seeds ./seeds COPY --chown=node:node --from=builder /app/static ./static -COPY --chown=node:node --from=builder /app/embed.html ./embed.html COPY --chown=node:node --from=builder /app/entrypoint.sh ./entrypoint.sh COPY --chown=node:node --from=builder /app/knexfile.js ./knexfile.js COPY --chown=node:node --from=builder /app/main.js ./main.js COPY --chown=node:node --from=builder /app/openapi.json ./openapi.json COPY --chown=node:node --from=builder /app/openapi.yaml ./openapi.yaml -COPY --chown=node:node --from=builder /app/sitemap.js.bk ./sitemap.js.bk -COPY --chown=node:node --from=builder /app/utils.js ./utils.js # Ensure necessary directories are writable VOLUME ["/uploads", "/database"] From f583ba49382c445ee2fa4a27ca2e473a9c069e54 Mon Sep 17 00:00:00 2001 From: Kyle Affolder Date: Sun, 9 Feb 2025 00:44:28 -0500 Subject: [PATCH 22/26] update(docker): README badge direct links add direct links to filtered image(s) on Docker Hub, based on whether Debian or Alpine Linux variant badges are clicked --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index e53155d..1940cfc 100644 --- a/README.md +++ b/README.md @@ -11,8 +11,8 @@

Docker Kener - Docker Image Size - Docker Image Size + Docker Image Size + Docker Image Size

From ff864fbaabe90ca7643797fd9eca25e383acfad3 Mon Sep 17 00:00:00 2001 From: Kyle Affolder Date: Sun, 9 Feb 2025 01:04:53 -0500 Subject: [PATCH 23/26] fix(README): restore accidentally removed tag Noticed when doing some cleanup, that you had two awesome tags, but they both point to different URLs/repos. I added back in the one I had inadvertently removed. --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 1940cfc..698a5bc 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,8 @@

GitHub Repo stars - Awesome self hosted + Awesome status page + Awesome self hosted

From eda98bacfc41d8a303e96974804969b5c469a052 Mon Sep 17 00:00:00 2001 From: Kyle Affolder Date: Mon, 10 Feb 2025 09:27:11 -0500 Subject: [PATCH 24/26] update(docker): temporarily remove README updating I caught an issue where the README will only auto-update listed Docker versions the first time. Commenting out for now (in case this PR gets merged before I have time to fix this). Will revisit this and fix this week. --- .github/workflows/publishImage.yml | 75 +++++++++++++++--------------- README.md | 5 +- 2 files changed, 41 insertions(+), 39 deletions(-) diff --git a/.github/workflows/publishImage.yml b/.github/workflows/publishImage.yml index 3961832..a82a71d 100644 --- a/.github/workflows/publishImage.yml +++ b/.github/workflows/publishImage.yml @@ -122,45 +122,46 @@ jobs: run: | echo "${TAGS}" | xargs -I {} cosign sign --yes {}@${DIGEST} - update_readme: - needs: build_and_push_to_registries # Runs only after build_and_push_to_registries completes successfully - name: Update README with release versions - runs-on: ubuntu-latest + # FIXME: Currently with this setup, job will only update versioning listed under README Docker section the FIRST time, but then once those inline placeholders are updated, future job runs will fail. Need to revisit with a more robust approach. Commenting out (for now) + # update_readme: + # needs: build_and_push_to_registries # Runs only after build_and_push_to_registries completes successfully + # name: Update README with release versions + # runs-on: ubuntu-latest - steps: - - name: Checkout Repository - uses: actions/checkout@v4.4.2 + # steps: + # - name: Checkout Repository + # uses: actions/checkout@v4.4.2 - - name: Extract Release Versions - id: meta - uses: docker/metadata-action@v5.6.1 - with: - images: rajnandan1/kener - tags: | - type=semver,pattern={{version}} - type=semver,pattern={{major}}.{{minor}} - type=semver,pattern={{major}} + # - name: Extract Release Versions + # id: meta + # uses: docker/metadata-action@v5.6.1 + # with: + # images: rajnandan1/kener + # tags: | + # type=semver,pattern={{version}} + # type=semver,pattern={{major}}.{{minor}} + # type=semver,pattern={{major}} - - name: Set Environment Variables - run: | - echo "KENER_SEMVER_VERSION=${{ steps.meta.outputs.version }}" >> $GITHUB_ENV - echo "KENER_MAJOR_MINOR_VERSION=${{ steps.meta.outputs.major }}.${{ steps.meta.outputs.minor }}" >> $GITHUB_ENV - echo "KENER_MAJOR_VERSION=${{ steps.meta.outputs.major }}" >> $GITHUB_ENV + # - name: Set Environment Variables + # run: | + # echo "KENER_SEMVER_VERSION=${{ steps.meta.outputs.version }}" >> $GITHUB_ENV + # echo "KENER_MAJOR_MINOR_VERSION=${{ steps.meta.outputs.major }}.${{ steps.meta.outputs.minor }}" >> $GITHUB_ENV + # echo "KENER_MAJOR_VERSION=${{ steps.meta.outputs.major }}" >> $GITHUB_ENV - - name: Safetly Update README.md - run: | - KENER_SEMVER_VERSION_ESCAPED=$(printf '%s\n' "${{ env.KENER_SEMVER_VERSION }}" | sed 's/[&/\]/\\&/g') - KENER_MAJOR_MINOR_VERSION_ESCAPED=$(printf '%s\n' "${{ env.KENER_MAJOR_MINOR_VERSION }}" | sed 's/[&/\]/\\&/g') - KENER_MAJOR_VERSION_ESCAPED=$(printf '%s\n' "${{ env.KENER_MAJOR_VERSION }}" | sed 's/[&/\]/\\&/g') - - sed -i "s/KENER_SEMVER_VERSION_PLACEHOLDER/${KENER_SEMVER_VERSION_ESCAPED}/g" README.md - sed -i "s/KENER_MAJOR_MINOR_VERSION_PLACEHOLDER/${KENER_MAJOR_MINOR_VERSION_ESCAPED}/g" README.md - sed -i "s/KENER_MAJOR_VERSION_PLACEHOLDER/${KENER_MAJOR_VERSION_ESCAPED}/g" README.md + # - name: Safetly Update README.md + # run: | + # KENER_SEMVER_VERSION_ESCAPED=$(printf '%s\n' "${{ env.KENER_SEMVER_VERSION }}" | sed 's/[&/\]/\\&/g') + # KENER_MAJOR_MINOR_VERSION_ESCAPED=$(printf '%s\n' "${{ env.KENER_MAJOR_MINOR_VERSION }}" | sed 's/[&/\]/\\&/g') + # KENER_MAJOR_VERSION_ESCAPED=$(printf '%s\n' "${{ env.KENER_MAJOR_VERSION }}" | sed 's/[&/\]/\\&/g') - - name: Commit and Push Changes - run: | - git config --global user.name 'github-actions' - git config --global user.email 'github-actions@github.com' - git add README.md - git commit -m "Update README with latest versions: ${{ env.KENER_SEMVER_VERSION }}" || exit 0 - git push \ No newline at end of file + # sed -i "s/KENER_SEMVER_VERSION_PLACEHOLDER/${KENER_SEMVER_VERSION_ESCAPED}/g" README.md + # sed -i "s/KENER_MAJOR_MINOR_VERSION_PLACEHOLDER/${KENER_MAJOR_MINOR_VERSION_ESCAPED}/g" README.md + # sed -i "s/KENER_MAJOR_VERSION_PLACEHOLDER/${KENER_MAJOR_VERSION_ESCAPED}/g" README.md + + # - name: Commit and Push Changes + # run: | + # git config --global user.name 'github-actions' + # git config --global user.email 'github-actions@github.com' + # git add README.md + # git commit -m "Update README with latest versions: ${{ env.KENER_SEMVER_VERSION }}" || exit 0 + # git push diff --git a/README.md b/README.md index 698a5bc..9db7101 100644 --- a/README.md +++ b/README.md @@ -81,7 +81,8 @@ Official Docker images for **Kener** are available on [Docker Hub](https://hub.d ![Docker Image Version (latest semver)](https://img.shields.io/docker/v/rajnandan1/kener?sort=semver&label=Latest%20Stable%20Release) -#### Available Tags + + #### Usage From 37a667daff614813ea7be4e6099899f7ed7f183d Mon Sep 17 00:00:00 2001 From: Kyle Affolder Date: Mon, 10 Feb 2025 11:21:22 -0500 Subject: [PATCH 25/26] fix(docker): dynamic README generation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 🔄 Automate README Generation via Mustache Templating - Use Mustache to dynamically generate `README.md` from `README.template.md`. - Populate README with environment variables (e.g., `KENER_BUILD_FULL_VERSION`). - Prevent direct edits to `README.md` by enforcing updates via the template. - Enhance GitHub Actions workflow to auto-generate and commit the README. - Add GitHub Action workflow (`protect-readme.yml`) to prevent others from direct updates to `README.md` via PR. --- .github/workflows/protect-readme.yml | 21 ++ .../{publishImage.yml => publish-images.yml} | 72 +++--- README.template.md | 217 ++++++++++++++++++ package.json | 2 + scripts/generate-readme.js | 31 +++ 5 files changed, 306 insertions(+), 37 deletions(-) create mode 100644 .github/workflows/protect-readme.yml rename .github/workflows/{publishImage.yml => publish-images.yml} (68%) create mode 100644 README.template.md create mode 100644 scripts/generate-readme.js diff --git a/.github/workflows/protect-readme.yml b/.github/workflows/protect-readme.yml new file mode 100644 index 0000000..9963dc7 --- /dev/null +++ b/.github/workflows/protect-readme.yml @@ -0,0 +1,21 @@ +name: Prevent Direct README Changes + +on: + pull_request: + paths: + - "README.md" + +jobs: + check-readme: + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4.4.2 + + - name: Detect direct README changes + run: | + if git diff --name-only origin/main | grep -q "README.md"; then + echo "❌ Direct modifications to README.md are not allowed!" + echo "Please update README.md.template instead." + exit 1 + fi diff --git a/.github/workflows/publishImage.yml b/.github/workflows/publish-images.yml similarity index 68% rename from .github/workflows/publishImage.yml rename to .github/workflows/publish-images.yml index a82a71d..1633cce 100644 --- a/.github/workflows/publishImage.yml +++ b/.github/workflows/publish-images.yml @@ -122,46 +122,44 @@ jobs: run: | echo "${TAGS}" | xargs -I {} cosign sign --yes {}@${DIGEST} - # FIXME: Currently with this setup, job will only update versioning listed under README Docker section the FIRST time, but then once those inline placeholders are updated, future job runs will fail. Need to revisit with a more robust approach. Commenting out (for now) - # update_readme: - # needs: build_and_push_to_registries # Runs only after build_and_push_to_registries completes successfully - # name: Update README with release versions - # runs-on: ubuntu-latest + generate_readme: + needs: build_and_push_to_registries # Runs only after build_and_push_to_registries completes successfully + name: Generate README from template + runs-on: ubuntu-latest - # steps: - # - name: Checkout Repository - # uses: actions/checkout@v4.4.2 + steps: + - name: Checkout Repository + uses: actions/checkout@v4.4.2 - # - name: Extract Release Versions - # id: meta - # uses: docker/metadata-action@v5.6.1 - # with: - # images: rajnandan1/kener - # tags: | - # type=semver,pattern={{version}} - # type=semver,pattern={{major}}.{{minor}} - # type=semver,pattern={{major}} + - name: Extract Release Versions + id: meta + uses: docker/metadata-action@v5.6.1 + with: + images: rajnandan1/kener + tags: | + type=semver,pattern={{version}} + type=semver,pattern={{major}}.{{minor}} + type=semver,pattern={{major}} - # - name: Set Environment Variables - # run: | - # echo "KENER_SEMVER_VERSION=${{ steps.meta.outputs.version }}" >> $GITHUB_ENV - # echo "KENER_MAJOR_MINOR_VERSION=${{ steps.meta.outputs.major }}.${{ steps.meta.outputs.minor }}" >> $GITHUB_ENV - # echo "KENER_MAJOR_VERSION=${{ steps.meta.outputs.major }}" >> $GITHUB_ENV + - name: Setup Node.js + uses: actions/setup-node@v4.2.0 + with: + node-version: "20" - # - name: Safetly Update README.md - # run: | - # KENER_SEMVER_VERSION_ESCAPED=$(printf '%s\n' "${{ env.KENER_SEMVER_VERSION }}" | sed 's/[&/\]/\\&/g') - # KENER_MAJOR_MINOR_VERSION_ESCAPED=$(printf '%s\n' "${{ env.KENER_MAJOR_MINOR_VERSION }}" | sed 's/[&/\]/\\&/g') - # KENER_MAJOR_VERSION_ESCAPED=$(printf '%s\n' "${{ env.KENER_MAJOR_VERSION }}" | sed 's/[&/\]/\\&/g') + - name: Install Dependencies + run: npm install mustache dotenv - # sed -i "s/KENER_SEMVER_VERSION_PLACEHOLDER/${KENER_SEMVER_VERSION_ESCAPED}/g" README.md - # sed -i "s/KENER_MAJOR_MINOR_VERSION_PLACEHOLDER/${KENER_MAJOR_MINOR_VERSION_ESCAPED}/g" README.md - # sed -i "s/KENER_MAJOR_VERSION_PLACEHOLDER/${KENER_MAJOR_VERSION_ESCAPED}/g" README.md + - name: Generate README.md + env: + KENER_BUILD_FULL_VERSION: ${{ steps.meta.outputs.tags[0] }} # e.g., 1.2.3 + KENER_BUILD_MAJOR_MINOR_VERSION: ${{ steps.meta.outputs.tags[1] }} # e.g., 1.2 + KENER_BUILD_MAJOR_VERSION: ${{ steps.meta.outputs.tags[2] }} # e.g., 1 + run: node scripts/generate-readme.js - # - name: Commit and Push Changes - # run: | - # git config --global user.name 'github-actions' - # git config --global user.email 'github-actions@github.com' - # git add README.md - # git commit -m "Update README with latest versions: ${{ env.KENER_SEMVER_VERSION }}" || exit 0 - # git push + - name: Commit and Push Changes + run: | + git config --global user.name 'github-actions' + git config --global user.email 'github-actions@github.com' + git add README.md + git commit -m "Auto-generate README.md with release versions" || echo "No changes to commit" + git push diff --git a/README.template.md b/README.template.md new file mode 100644 index 0000000..0737e18 --- /dev/null +++ b/README.template.md @@ -0,0 +1,217 @@ +# Kener - Stunning Status Pages + +

+ kener example illustration +

+ +

+ GitHub Repo stars + Awesome status page + Awesome self hosted +

+ +

+ Docker Kener + Docker Image Size + Docker Image Size +

+ +

+ GitHub Workflow Status + + GitHub issues +

+ +

+ + Kener on Product Hunt + +

+ +

+ + + 🔔 + + + + 🚀 + + + + 🚧 + +

+ +| [🌍 Live Server](https://kener.ing) | [🎉 Quick Start](https://kener.ing/docs/quick-start) | [🗄 Documentation](https://kener.ing/docs/home) | +| ----------------------------------- | ---------------------------------------------------- | ----------------------------------------------- | + +## What is Kener? + +**Kener** is a sleek and lightweight status page system built with **SvelteKit** and **NodeJS**. It’s not here to replace heavyweights like Datadog or Atlassian but rather to offer a simple, modern, and hassle-free way to set up a great-looking status page with minimal effort. + +Designed with **ease of use** and **customization in mind**, Kener provides all the essential features you’d expect from a status page—without unnecessary complexity. + +### Why Kener? + +✅  Minimal overhead – Set up quickly with a clean, modern UI
+✅  Customizable – Easily tailor it to match your brand
+✅  Open-source & free – Because great tools should be accessible to everyone + +### What's in a Name? + +“Kener” is inspired by the Assamese word _“Kene”_, meaning _“how’s it going?”_. The _‘.ing’_ was added because, well… that domain was available. 😄 + +## Installation + +### Manual + +```shell +# Clone the repository +git clone https://github.com/rajnandan1/kener.git +cd kener +npm install +cp .env.example .env +npm run dev +``` + +### Docker + +Official Docker images for **Kener** are available on [Docker Hub](https://hub.docker.com/r/rajnandan1/kener). Multiple versions are maintained to support different use cases. + +![Docker Image Version (latest semver)](https://img.shields.io/docker/v/rajnandan1/kener?sort=semver&label=Latest%20Stable%20Release) + +#### Available Tags + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Image TagDescription
Debian 12 (Bookwork Slim) w/ Node.js v23.7.0  (default)
latestLatest stable release (aka {{kener_full_version}})
{{kener_full_version}}Specific release version
{{kener_major_minor_version}}Major-minor version tag pointing to the latest patch ({{kener_full_version}}) release within that minor version ({{kener_major_minor_version}}.x)
{{kener_major_version}}Major version tag pointing to the latest stable ({{kener_full_version}}) release within that major version ({{kener_major_version}}.x.x)
Alpine Linux 3.21 w/ Node.js v23.7.0  (smallest image size)
alpineLatest stable release (aka {{kener_full_version}})
{{kener_full_version}}-alpineSpecific release version
{{kener_major_minor_version}}-alpineMajor-minor version tag pointing to the latest patch ({{kener_full_version}}) release within that minor version ({{kener_major_minor_version}}.x)
{{kener_major_version}}-alpineMajor version tag pointing to the latest stable ({{kener_full_version}}) release within that major version ({{kener_major_version}}.x.x)
+ +#### Usage + +Pull the latest stable version: + +```sh +docker pull rajnandan1/kener:latest +``` + +Or use the smaller, Alpine-based variant: + +```sh +docker pull rajnandan1/kener:alpine +``` + +For a production setup, refer to the sample [docker-compose.yml](https://github.com/rajnandan1/kener/blob/main/docker-compose.yml). +This keeps things clean, structured, and easy to read while preserving all the details. + +### One Click + +[![Deploy on Railway](https://railway.com/button.svg)](https://railway.com/template/spSvic?referralCode=1Pn7vs) + +## Features + +Here are some of the features that you get out of the box. Please read the documentation to know how to use them. + +### 📊  Monitoring and Tracking + +- Advanced **application performance monitoring** tools +- **Real-time network monitoring** capabilities +- Supports **polling HTTP endpoints** or **pushing data** via REST APIs +- **Timezone auto-adjustment** for visitors +- Organize monitors into **custom sections** +- **Cron-based scheduling** (minimum: **every minute**) +- **Create complex API polls** (chaining, secrets, etc.) +- Set a **default status** for monitors +- Supports **base path hosting in Kubernetes (k8s)** +- **Pre-built Docker images** for easy deployment + +### 🎨  Customization and Branding + +- Fully **customizable status page** +- **Badge generation** for status and uptime tracking +- Support for **custom domains** +- Embed monitors as **iframes or widgets** +- **Light & Dark Mode** +- **Internationalization (i18n) support** +- **Sleek, beautifully crafted UI** + +### 🚨  Incident Management + +- **Incident tracking & communication** tools +- **Comprehensive APIs** for incident management + +### 🧑‍💻  User Experience and Design + +- **Accessible & user-friendly interface** +- **Quick & easy installation** +- **Responsive design** for all devices +- **Auto SEO & Social Media ready** +- **Server-Side Rendering (SSR) for better performance** + +
+ Visitor Stats +
+ +## Technologies Used + +- [SvelteKit](https://kit.svelte.dev/) +- [shadcn-svelte](https://www.shadcn-svelte.com/) + +## Support Me + +If you’re enjoying Kener and want to support its development, consider sponsoring me on GitHub or treating me to a coffee. Your support helps keep the project growing! 🚀 + +[Sponsor Me Using Github](https://github.com/sponsors/rajnandan1) + +☕  [Buy Me a Coffee](https://www.buymeacoffee.com/rajnandan1) + +![image](https://badges.pufler.dev/visits/rajnandan1/kener) + +## Contributing + +If you want to contribute to Kener, please read the [Contribution Guide](https://github.com/rajnandan1/kener/blob/main/.github/CONTRIBUTING.md). + +## Star History + +[![Star History Chart](https://api.star-history.com/svg?repos=rajnandan1/kener&type=Date)](https://star-history.com/#rajnandan1/kener&Date) diff --git a/package.json b/package.json index 17c3eda..b2fcd10 100644 --- a/package.json +++ b/package.json @@ -37,6 +37,7 @@ "devschedule": "node src/lib/server/startup.js", "schedule": "node src/lib/server/startup.js", "development": "vite dev", + "generate-readme": "node scripts/generate-readme.js", "dev": "npm-run-all --parallel devschedule development", "prettify": "prettier --write .", "start": "node main.js" @@ -51,6 +52,7 @@ "concurrently": "^8.2.2", "cross-env": "^7.0.3", "date-picker-svelte": "^2.15.1", + "mustache": "^4.2.0", "postcss": "^8.4.24", "postcss-load-config": "^4.0.1", "prettier": "^3.2.5", diff --git a/scripts/generate-readme.js b/scripts/generate-readme.js new file mode 100644 index 0000000..af1c1be --- /dev/null +++ b/scripts/generate-readme.js @@ -0,0 +1,31 @@ +import fs from "fs"; +import Mustache from "mustache"; +import dotenv from "dotenv"; +import { fileURLToPath } from "url"; +import path from "path"; + +// Load environment variables from .env file +dotenv.config(); + +// Resolve paths correctly in ES modules +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); + +// Load the template +const templatePath = path.resolve(__dirname, "../README.template.md"); +const template = fs.readFileSync(templatePath, "utf-8"); + +// Load environment variables and provide default values +const data = { + kener_full_version: process.env.KENER_BUILD_FULL_VERSION || "N/A", + kener_major_minor_version: process.env.KENER_BUILD_MAJOR_MINOR_VERSION || "N/A", + kener_major_version: process.env.KENER_BUILD_MAJOR_VERSION || "N/A", +}; + +// Render README.md +const output = Mustache.render(template, data); + +// Write to README.md +fs.writeFileSync(path.resolve(__dirname, "../README.md"), output); + +console.log("✅ README.md generated successfully!"); From e5565145b5c018ea9d9330ad5b5210c495a92d8a Mon Sep 17 00:00:00 2001 From: Kyle Affolder Date: Mon, 10 Feb 2025 11:24:07 -0500 Subject: [PATCH 26/26] fix(docker): action version number --- .github/workflows/protect-readme.yml | 2 +- .github/workflows/publish-images.yml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/protect-readme.yml b/.github/workflows/protect-readme.yml index 9963dc7..e2ece10 100644 --- a/.github/workflows/protect-readme.yml +++ b/.github/workflows/protect-readme.yml @@ -10,7 +10,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout code - uses: actions/checkout@v4.4.2 + uses: actions/checkout@v4.2.2 - name: Detect direct README changes run: | diff --git a/.github/workflows/publish-images.yml b/.github/workflows/publish-images.yml index 1633cce..a95eebd 100644 --- a/.github/workflows/publish-images.yml +++ b/.github/workflows/publish-images.yml @@ -37,7 +37,7 @@ jobs: steps: - name: Check out the repo - uses: actions/checkout@v4.4.2 + uses: actions/checkout@v4.2.2 # Install the cosign tool (except on PR) # https://github.com/sigstore/cosign-installer @@ -129,7 +129,7 @@ jobs: steps: - name: Checkout Repository - uses: actions/checkout@v4.4.2 + uses: actions/checkout@v4.2.2 - name: Extract Release Versions id: meta