jkunz 42980acc68
Docker (tags) / security (push) Failing after 51s
Docker (tags) / test (push) Failing after 17s
v8.0.0
2026-10-15 06:32:02 +00:00
2019-06-08 21:36:23 +02:00
2026-10-15 06:32:02 +00:00
2026-10-15 06:32:02 +00:00

🐳 ht-docker-node

Production-ready Docker images for Node.js with NVM built in, multi-arch support, and modern runtimes (Bun, Deno). Every image ships with tini as PID 1 and full NVM integration — switch Node versions on the fly, no sourcing required.

Multi-arch • Alpine & Ubuntu • NVM built-in • Bun, Deno & pnpm • tini init • CI/CD optimized

Issue Reporting and Security

For reporting bugs, issues, or security vulnerabilities, please visit community.foss.global/. This is the central community hub for all issue reporting. Developers who sign and comply with our contribution agreement and go through identification can also get a code.foss.global/ account to submit Pull Requests directly.


🚀 Quick Start

# Pull and run the full-featured Ubuntu image
docker pull code.foss.global/host.today/ht-docker-node:latest
docker run -it code.foss.global/host.today/ht-docker-node:latest

# Or go lean with Alpine (~200 MB vs ~900 MB)
docker pull code.foss.global/host.today/ht-docker-node:alpine-node
docker run -it code.foss.global/host.today/ht-docker-node:alpine-node

NVM is ready the moment you enter the container — no manual sourcing, no .bashrc hacks:

$ nvm install 22
$ nvm use 22
$ node -v   # v22.x.x ✅

📦 Available Images

Built on Ubuntu 24.04. Maximum compatibility, all build tools included, plus Chromium/Chrome headless shell for Puppeteer and Chrome DevTools Protocol use, and MongoDB 8.0.

Tag Description Key Contents
:latest Kitchen-sink Node.js image Node LTS + NVM + pnpm + Bun + Deno + Chromium/Chrome headless shell + MongoDB 8.0 + Rust with musl C toolchains
:lts Alias of :latest Same — explicit LTS naming for clarity
:szci CI/CD workhorse :latest + @ship.zone/szci preinstalled
:fossglobal_preinstalled_<ver> Preloaded tooling image :szci + tsrun, tstest, tapbundle, smartfile, and more

Ubuntu-Based (Slim Runtime)

Built on Ubuntu 24.04 (glibc 2.39) with only what a Node.js app needs at runtime: NVM, Node.js LTS, pnpm, tini, curl, git and CA certificates. No compilers, Rust, Chromium, MongoDB, Bun or Deno.

Tag Description Size Architectures
:ubuntu-node Node.js LTS + NVM + pnpm on glibc ~700 MB amd64, arm64

Use it as the production stage of an app that ships glibc-only native binaries (prebuilt Rust or C++ workers, for example). Build in :latest or :lts, then copy the result over:

FROM code.foss.global/host.today/ht-docker-node:lts AS build
WORKDIR /app
COPY . ./
RUN pnpm install --frozen-lockfile && pnpm run build && pnpm prune --prod

FROM code.foss.global/host.today/ht-docker-node:ubuntu-node AS production
WORKDIR /app
COPY --from=build /app /app
CMD ["node", "cli.js"]

Add runtime system packages your app needs (fonts, for example) with apt-get install --no-install-recommends in the production stage.

Alpine-Based (Lightweight & Multi-Arch) ⚡

40–75 % smaller than Ubuntu. Native performance on both amd64 and arm64 (Apple Silicon, Graviton, Ampere).

Tag Description Size Architectures
:alpine-node Node.js LTS + NVM + pnpm ~200 MB amd64, arm64
:alpine-bun Node.js LTS + NVM + Bun ~150 MB amd64, arm64
:alpine-deno Node.js LTS + NVM + Deno Includes complete Deno/V8 source amd64, arm64
:alpine-szci Alpine Node + szci + build tools ~350 MB amd64, arm64
:smartdb-qualification SmartDB release qualification with ext4/XFS tooling ~250 MB amd64, arm64

💡 Docker automatically pulls the right arch for your platform. Build on a Mac, deploy on an ARM server — same tag, native speed everywhere.

The Alpine Deno images install the reviewed deno=2.7.4-r2 package from Alpine 3.24. Each image contains its exact source and license materials; builds reject package identities that differ from that inventory.

The :smartdb-qualification image extends :alpine-node with util-linux, e2fsprogs, and xfsprogs. SmartDB release automation consumes it only by an exact Linux amd64 manifest digest and runs it without network access or a writable container root.

What every image includes

Feature Detail
tini PID 1 init — proper signal forwarding & zombie reaping
NVM v0.40.7 — works in RUN, docker exec, CI scripts, interactive shells
Node.js LTS v24.13.0 (default, switchable)
docker-entrypoint.sh Loads NVM at runtime so docker run … bash -c "nvm use 22" just works

💡 Key Features

The Alpine-based images include NVM's documented coreutils prerequisite so installed-version lookup and aliases work with GNU ls options.

NVM 0.40.7 selects the published ARM64 musl binaries during both builds and runtime version changes. Alpine ARM64 binaries are available from Node 20.20.1, 22.21.1 and 24.9.0 in their respective release lines. Older releases such as Node 18 have x64 musl artifacts only; choose a version with a published artifact for the target architecture.

The alpine-szci, dbase and dbase_dind images carry no Deno: SZCI 10 runs on their Node.js.

pnpm 12 native installation

All image families install pnpm 12.3.1 with the official standalone installer. The installer selects the native GNU or musl executable for the image architecture and verifies the signed package metadata. pnpm runs independently of the Node version selected with NVM, including project packageManager pins to native pnpm 12 releases.

Since image version 6, the bundled package manager is pnpm 12. Projects must follow the pnpm 12 configuration and lockfile documentation; the image does not rewrite project configuration. The shared global policy sets minimumReleaseAge to 10,080 minutes and includes foss.global-owned scopes such as @lossless.org/* in minimumReleaseAgeExclude. A project-local exclusion array replaces the global array, so inspect both effective values from the project directory when diagnosing an install.

SZCI images install @ship.zone/szci@10.0.1, whose npm wrapper requires Node.js 22 or newer. Keep a supported Node version selected when invoking SZCI. GNU images (:szci) run its packaged native executable, a Node.js single executable application that needs GNU libc 2.28+, libstdc++ and libatomic; the image installs libatomic1 for it. The Alpine SZCI, Docker CLI and Docker-in-Docker images run SZCI's bundled musl build on the image's Node.js. Optional native dependencies remain enabled; the wrapper selects the supported runtime.

Alpine license materials are installed at /usr/share/doc/ht-docker-node/alpine. Deno-bearing images additionally carry the complete Deno/V8 corresponding source there, including the LGPL math sources and rebuild instructions. Coreutils and the LGPL ACL/attribute libraries carry their corresponding-source archives. The checked source manifests and package/binary identities bind these materials to the installed versions.

🔄 NVM — Zero-Config Node Version Management

NVM is pre-wired into every shell context. No manual sourcing required in any of these scenarios:

Dockerfile RUN commands (via the bash-with-nvm SHELL wrapper):

FROM code.foss.global/host.today/ht-docker-node:latest

# Works directly — no sourcing needed!
RUN nvm install 22 && nvm use 22 && npm ci
RUN nvm alias default 22          # persists for later RUN steps

CI/CD scripts (via BASH_ENV=/etc/bash.bashrc):

# Gitea / GitLab CI
test:
  image: code.foss.global/host.today/ht-docker-node:latest
  script:
    - nvm install 22 && nvm use 22
    - pnpm ci && pnpm test

Interactive shells and docker exec:

docker exec -it mycontainer bash
$ nvm ls          # lists installed versions
$ nvm install 20  # installs Node 20
$ nvm use 20      # switches immediately

⚠️ Note on version persistence across RUN steps: Each Dockerfile RUN starts a new shell. Use nvm alias default <version> to persist your choice, or chain commands in a single RUN.

🛡️ tini — Proper Init for Containers

All images use tini as PID 1:

tini → docker-entrypoint.sh → your command

This means:

  • ✅ Signals (SIGTERM, SIGINT) are forwarded correctly to your app
  • ✅ Zombie processes are reaped automatically
  • ✅ Clean container shutdown — no orphaned processes

🌐 Chromium Headless Shell (Ubuntu :latest and descendants)

Puppeteer uses the preconfigured headless executable automatically:

const browser = await puppeteer.launch(); // uses /usr/local/bin/chromium

The :latest image copies chromedp's Chrome headless shell, built from Chromium 151.0.7922.34, from a digest-pinned multi-architecture image and exposes it through /usr/local/bin/chromium. Images built from :latest, including :lts and :szci, inherit it. Environment variables PUPPETEER_EXECUTABLE_PATH and CHROME_BIN are pre-set. The browser is headless-only and is tested for Puppeteer and Chrome DevTools Protocol use on native amd64 and arm64; it is not a general headful Chromium installation.

Browser license and third-party credit materials are installed at /usr/share/doc/ht-docker-node/chromium and tracked under third_party/chromium.

🦀 Rust and static musl builds (Ubuntu :latest and descendants)

:latest installs Rust with rustup (stable at image build time) and the targets aarch64-unknown-linux-gnu, x86_64-unknown-linux-musl and aarch64-unknown-linux-musl, plus the C toolchains that crates such as ring, aws-lc-sys and mimalloc need to compile for the musl targets. cc-rs finds them by their <arch>-linux-musl-gcc, -ar and -ranlib names, and @git.zone/tsrust builds linux_amd64_musl and linux_arm64_musl with them.

Image architecture musl C toolchains Static musl targets it builds
linux/amd64 cross-tools/musl-cross 20260823 (GCC 16.2.0, binutils 2.47, musl 1.2.6) for both triples, under /opt/x-tools/<triple>, each tool on PATH as x86_64-unknown-linux-musl-gcc and x86_64-linux-musl-gcc (likewise aarch64-…) x86_64-unknown-linux-musl and aarch64-unknown-linux-musl
linux/arm64 Ubuntu musl-tools: aarch64-linux-musl-gcc is the native musl-gcc wrapper (installed by musl-dev), aarch64-linux-musl-ar and -ranlib link to the native binutils aarch64-unknown-linux-musl only; there is no x86_64 musl C compiler

Set the aarch64 musl linker in the project's .cargo/config.toml; the x86_64 musl target links with the default cc:

[target.aarch64-unknown-linux-musl]
linker = "aarch64-linux-musl-gcc"

A project that pins its toolchain in rust-toolchain.toml gets that toolchain and the targets it lists from rustup on first use; the musl C toolchains serve every Rust version.

The amd64 toolchains are verified against pinned SHA-256 digests during the image build. Their license files, crosstool-NG configurations, source checksums and the location of their corresponding source are installed at /usr/share/doc/ht-docker-node/musl-cross and tracked under third_party/musl-cross.

🏔️ Alpine — Production Optimized

FROM code.foss.global/host.today/ht-docker-node:alpine-node

RUN nvm install 22 && nvm use 22
RUN pnpm install && pnpm build
# Result: ~200 MB image

Why Alpine?

  • ✅ 60–75 % smaller → Faster pulls, faster deploys
  • ✅ Reduced attack surface → Fewer packages = fewer CVEs
  • ✅ Native musl builds → No glibc compatibility layer
  • ✅ Multi-arch → Same tag works on x64 and ARM64

🛠️ Usage Examples

Basic Node.js App

FROM code.foss.global/host.today/ht-docker-node:alpine-node

WORKDIR /app
COPY package*.json ./
RUN pnpm install

COPY . .
RUN pnpm build

EXPOSE 3000
CMD ["node", "dist/index.js"]

Multi-Version Testing

FROM code.foss.global/host.today/ht-docker-node:latest

WORKDIR /app
COPY package*.json ./

RUN nvm install 20 && nvm use 20 && npm ci && npm test
RUN nvm install 22 && nvm use 22 && npm ci && npm test

# Ship with Node 22
RUN nvm alias default 22 && npm run build

Deno Application

FROM code.foss.global/host.today/ht-docker-node:alpine-deno

WORKDIR /app
COPY . .

# Deno and Node.js are both available
CMD ["deno", "run", "--allow-net", "main.ts"]

Bun for Ultra-Fast Installs

FROM code.foss.global/host.today/ht-docker-node:alpine-bun

WORKDIR /app
COPY package.json bun.lockb ./
RUN bun install

COPY . .
RUN bun run build
CMD ["bun", "run", "start"]

TypeScript Multi-Stage Build

# Build stage
FROM code.foss.global/host.today/ht-docker-node:alpine-node AS builder
WORKDIR /app
COPY package*.json ./
RUN pnpm install
COPY tsconfig.json ./
COPY src ./src
RUN pnpm build

# Production stage — only runtime deps
FROM code.foss.global/host.today/ht-docker-node:alpine-node
WORKDIR /app
COPY package*.json ./
RUN pnpm install --prod
COPY --from=builder /app/dist ./dist
EXPOSE 3000
CMD ["node", "dist/index.js"]

Production-Hardened Setup

FROM code.foss.global/host.today/ht-docker-node:alpine-node

# Non-root user
RUN addgroup -g 1001 -S nodejs && adduser -S nodejs -u 1001

WORKDIR /app
COPY package*.json ./
RUN pnpm install --frozen-lockfile && pnpm cache clean

COPY --chown=nodejs:nodejs . .
RUN pnpm build

USER nodejs
EXPOSE 3000
CMD ["node", "dist/index.js"]

🔧 NVM Cheat Sheet

# Install a specific version
nvm install 22.5.0

# Use a version (current shell)
nvm use 22

# Set default (persists across shells / RUN steps)
nvm alias default 22

# Install and switch to latest LTS
nvm install --lts && nvm use --lts

# List installed versions
nvm ls

# Chain in a single Dockerfile RUN
RUN nvm install 22 && nvm use 22 && npm ci && npm test

🏗️ Building the Images

This project uses @git.zone/tsdocker for Docker image management.

# Install tsdocker
pnpm install -g @git.zone/tsdocker@latest

# Discover all Dockerfiles and their tags
tsdocker list

# Build all images (multi-arch: amd64 + arm64)
tsdocker build

# Run all test scripts
tsdocker test

# Push to a specific registry
tsdocker push code.foss.global

Manual Build (single image)

docker buildx build \
  --platform linux/amd64,linux/arm64 \
  -f Dockerfile_alpine-node \
  -t your-registry/your-image:alpine-node \
  --push .

Image Dependency Chain

Some images depend on others being in the registry first:

Dockerfile (:latest) ──► Dockerfile_lts (:lts)
                     ──► Dockerfile_szci (:szci)
                          ──► Dockerfile_fossglobal_preinstalled_* (:fossglobal_preinstalled_<ver>)

Dockerfile_alpine-node (:alpine-node)
                     ──► Dockerfile_alpine-szci (:alpine-szci)
                     ──► Dockerfile_smartdb-qualification (:smartdb-qualification)

The standalone images (:ubuntu-node, :alpine-bun, :alpine-deno) have no registry dependencies.


📊 Image Comparison

Feature Ubuntu :latest Alpine :alpine-node
Base Size ~900 MB ~200 MB
Build Tools ✅ Full (gcc, g++, make, python3) ⚠️ Install separately (apk add build-base)
Chromium/Chrome headless shell ✅ Pre-installed ❌
MongoDB ✅ 8.0 ❌
Runtimes Node + Bun + Deno + pnpm Node + pnpm
Compatibility ✅ Maximum (glibc) ✅ Good (musl)
Multi-arch ✅ amd64, arm64 ✅ amd64, arm64
tini init ✅ ✅
Best for Complex builds, E2E tests, full-stack dev Production, CI/CD, microservices

🐛 Troubleshooting

NVM command not found

Shouldn't happen in our images, but if it does:

export NVM_DIR="/usr/local/nvm"
[ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh"

Alpine native module build failures

Some npm packages require native build tools:

FROM code.foss.global/host.today/ht-docker-node:alpine-node
RUN apk add --no-cache python3 make g++
RUN pnpm install

Or use :alpine-szci which ships with build tools pre-installed.

Version not persisting across RUN steps

Each Dockerfile RUN creates a new shell. Use nvm alias default:

RUN nvm install 22 && nvm alias default 22
RUN node -v   # ✅ v22.x.x


This repository contains open-source code licensed under the MIT License. A copy of the license can be found in license.md.

Please note: The MIT License does not grant permission to use the trade names, trademarks, service marks, or product names of the project, except as required for reasonable and customary use in describing the origin of the work and reproducing the content of the NOTICE file.

Trademarks

This project is owned and maintained by Task Venture Capital GmbH. The names and logos associated with Task Venture Capital GmbH and any related products or services are trademarks of Task Venture Capital GmbH or third parties, and are not included within the scope of the MIT license granted herein.

Use of these trademarks must comply with Task Venture Capital GmbH's Trademark Guidelines or the guidelines of the respective third-party owners, and any usage must be approved in writing. Third-party trademarks used herein are the property of their respective owners and used only in a descriptive manner, e.g. for an implementation of an API or similar.

Company Information

Task Venture Capital GmbH
Registered at District Court Bremen HRB 35230 HB, Germany

For any legal inquiries or further information, please contact us via email at hello@task.vc.

By using this repository, you acknowledge that you have read this section, agree to comply with its terms, and understand that the licensing of the code does not imply endorsement by Task Venture Capital GmbH of any derivative works.

Bundled browser binaries and other third-party image contents retain their own licenses; Chromium and chromedp license and credit materials are tracked under third_party/chromium and included in the published image.

The musl C toolchains of the amd64 :latest image (GCC, binutils, musl, Linux headers, GMP, MPFR, MPC, ISL, zlib, zstd and mold, built with crosstool-NG) retain their own licenses, including the GPL and LGPL. Their license files, build configurations and source checksums are tracked under third_party/musl-cross and installed at /usr/share/doc/ht-docker-node/musl-cross, which also names where their complete corresponding source is published.

pnpm 12.3.1 and its bundled dependencies retain their own licenses. The upstream pnpm licenses, locked native dependency notices, Rust and musl materials are tracked under third_party/pnpm and copied to /usr/share/doc/ht-docker-node/pnpm; the installed pnpm dist/ tree retains its upstream component licenses.

S
Description
multiarch docker base images
oci
Readme
11 MiB
2026-10-15 06:32:02 +00:00
Languages
Shell 48.8%
Python 27.1%
Dockerfile 15.9%
JavaScript 8.2%