Harthelm Docs
Install

Get Harthelm

Where the chart, the images and the release files come from: the registry login of your licence, signatures, SBOMs, air-gapped bundles and the source code.

Last updated 2026-10-20

Every Harthelm release is published on two hosts Since 1.6.0:

HostHoldsAccess
registry.harthelm.devthe images and the chart, as an OCI registrya login with your licence id and registry token
get.harthelm.devthe release files: hart, checksums, SBOMs, the air-gapped bundles, the source codepublic HTTPS, no login

Releases before 1.6.0 are not on these hosts; take them from the registry you got them from.

What comes with your licence

With your licence you receive two things:

  • the licence file, which you install into Harthelm (Licence);
  • the registry token, the password for registry.harthelm.dev. The user name is your licence id, the id that hart admin license prints after Licence:, for example HL-2026-0123.

The token belongs to one installation: each installation gets its own. It is shown once, when it is delivered, so put it into your secret store right away. It carries your licence's end date and stops working when the licence ends. If you lose it or it leaks, ask for a new one; the old one is then revoked.

When the token stops working

After a licence ends or is revoked, the registry refuses its token at the next login, at the latest five minutes later, with 401 Unauthorized. Pods that run keep running, but a node that has to pull an image it does not have yet (a new node, a workspace that wakes on another node) fails. An installation that pulls from its own registry needs the token only to fill it.

Log in

Keep the token in a file that only you can read, here registry-token, so it stays out of your shell history. Every client logs in with the licence id as user name:

Terminal
helm registry login registry.harthelm.dev --username <licence id> --password-stdin < registry-token
docker login registry.harthelm.dev --username <licence id> --password-stdin < registry-token

Helm keeps its own login. cosign and skopeo read Docker's; without Docker, log them in themselves:

Terminal
cosign login registry.harthelm.dev --username <licence id> --password-stdin < registry-token
skopeo login registry.harthelm.dev --username <licence id> --password-stdin < registry-token

A wrong id or token, or a licence that has ended, gets 401 Unauthorized. The registry has no anonymous access.

What the registry holds

Every image is one level below registry.harthelm.dev/harthelm/, and every image is multi-arch (linux/amd64 and linux/arm64):

ImageTag
harthelm, harthelm-agent, harthelm-base, harthelm-ide, harthelm-toolsthe release, for example 1.6.0
postgresql (17.x and 18.x), mariadb (the 11.4, 11.8 and 12.3 series), valkey, rabbitmq, seaweedfsthe vendor's own tag
cloudnative-pg, cert-manager-controller, cert-manager-cainjector, cert-manager-webhook, cert-manager-startupapicheckthe vendor's own tag

The last row holds the operators the chart needs, so you can install them from the same registry too (their charts take an image registry value). The chart is oci://registry.harthelm.dev/harthelm/charts/harthelm. It pins every image by digest as registry.harthelm.dev/harthelm/<image>@sha256:…, so an install from this registry sets no global.imageRegistry.

Release candidates (1.6.0-rc.1 and so on) may appear in the registry too. Install releases only: Helm skips pre-releases when it resolves a version range unless you pass --devel, and you always pass the exact version.

Install from registry.harthelm.dev

The cluster's nodes pull the images with your licence's login too. Give them a pull Secret in the release namespace, harthelm-system (created in Install):

Terminal
kubectl -n harthelm-system create secret docker-registry harthelm-pull \
  --docker-server=registry.harthelm.dev --docker-username=<licence id> \
  --docker-password="$(cat registry-token)"

and name it in your values:

my-values.yaml
global:
  imagePullSecrets:
    - name: harthelm-pull

The chart's pods list it, and core copies it into every team namespace and lists it on the workspace, service and managed-database pods there. The preflight checks that it exists with the type kubernetes.io/dockerconfigjson. Names that start with ws- are refused. See global.imagePullSecrets.

After helm registry login:

Terminal
helm install harthelm oci://registry.harthelm.dev/harthelm/charts/harthelm --version 1.6.0 \
  -n harthelm-system --create-namespace -f my-values.yaml

Install has the steps before (operators, DNS, sign-in, master key, licence) and after it; its <your registry> is registry.harthelm.dev/harthelm.

Install from your own registry

To keep the images in a registry of your own, mirror them from the release's images-public.txt with its mirror.sh (the release files), on a host that reaches both registries and is logged in to registry.harthelm.dev. skopeo reads that login; SKOPEO_SRC_FLAGS="--src-creds <licence id>:<registry token>" passes it instead.

Terminal
./mirror.sh registry.example.internal images-public.txt
./mirror.sh --verify registry.example.internal images-public.txt

The repository paths stay, so the images land at registry.example.internal/harthelm/<image> with the same digests. --verify only reads: it asks your registry for every image and compares the digest. Then install the public chart, from the registry or as harthelm-<version>-public.tgz, with your registry in the values:

my-values.yaml
global:
  imageRegistry: registry.example.internal

Verify the signatures before you mirror: the copies do not carry them. Air-gapped installs has the rest: the chart in your registry, the operators and the mirrors the workspaces need.

Verify the signatures

Every image of a release and its chart are signed with Harthelm's release key, with cosign. A multi-arch image has a signature on its index and on each platform's manifest. The signatures are stored next to what they sign in registry.harthelm.dev. They use no transparency log, so you verify with the public key alone and pass --insecure-ignore-tlog (cosign warns about it). Use cosign 3 or newer, logged in to the registry as above.

The release key

Terminal
curl -fsSLO https://docs.harthelm.dev/cosign.pub
sha256sum cosign.pub      # macOS: shasum -a 256 cosign.pub

The checksum is 50fdf235ee7d88278f787bc434f929a01ce56ac5c65c392638ecf4862c74f77a, and a copy of the key you got another way must have the same. The file, cosign.pub, holds:

cosign.pub
-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEeyIf7om4hH4S4MA3LYxv7XYs+H69
DlTjcooCJsZds6ERhcEvE1Pbuj59n103EgIcTV/0VJtIM1O4T7NyFHsWRQ==
-----END PUBLIC KEY-----

Images

Take an image's digest from images-public.txt and verify it:

Terminal
cosign verify --key cosign.pub --insecure-ignore-tlog \
  registry.harthelm.dev/harthelm/harthelm@sha256:<digest>

cosign lists the checks it made, prints what it verified as JSON and exits 0. Any other result means the image is not one that Harthelm released. To verify every image of the release:

Terminal
grep -v '^#' images-public.txt | while read -r ref; do
  [ -n "$ref" ] || continue
  repo=${ref%@*}
  if cosign verify --key cosign.pub --insecure-ignore-tlog "${repo%:*}@${ref#*@}" > /dev/null 2>&1; then
    echo "ok      $ref"
  else
    echo "FAILED  $ref"
  fi
done

The chart

Terminal
helm pull oci://registry.harthelm.dev/harthelm/charts/harthelm --version 1.6.0

Helm prints the chart's Digest: sha256:…. Verify that digest:

Terminal
cosign verify --key cosign.pub --insecure-ignore-tlog \
  registry.harthelm.dev/harthelm/charts/harthelm@sha256:<digest>

The chart pins every image by digest, so a verified chart also fixes the images it starts.

Mirrors and bundles

A mirror made with mirror.sh holds the images without their signatures, and the air-gapped bundles hold none either. Verify on the connected side, before you mirror or carry a bundle over. A bundle's images.txt names the digests of the platform manifests, which are signed too, so the loop above works on it as well (each line is registry.harthelm.dev/harthelm/<image>:<tag>@<platform digest>). The bundle's own chart is pinned to those digests when the bundle is made and is not signed; the bundle's checksum covers it.

Read the SBOMs

harthelm-<version>-sboms.tar.gz holds one SPDX 2.3 JSON document per Harthelm image and platform: ten files, five images on two platforms, made with syft from the released images.

Terminal
v=1.6.0
sha256sum -c "harthelm-$v-sboms.tar.gz.sha256"      # macOS: shasum -a 256 -c
tar -xzf "harthelm-$v-sboms.tar.gz"
ls sbom/

The files are sbom/harthelm-<image>-<version>-linux-<arch>.spdx.json, for example sbom/harthelm-harthelm-agent-1.6.0-linux-arm64.spdx.json. List the packages of one, with their version and licence:

Terminal
jq -r '.packages[] | [.name, .versionInfo, .licenseConcluded] | @tsv' \
  sbom/harthelm-harthelm-1.6.0-linux-amd64.spdx.json

A vulnerability scanner that reads SPDX takes the files as they are, for example grype sbom:sbom/harthelm-harthelm-1.6.0-linux-amd64.spdx.json. The managed services' and the operators' images come from their vendors, and so do their SBOMs.

The release files

Every release has its files under https://get.harthelm.dev/releases/<version>/:

FileWhat
harthelm-<version>-public.tgzthe chart, as in the registry
images-public.txtevery image of the release, one per line: registry.harthelm.dev/harthelm/<image>:<tag>@sha256:<digest>
mirror.shcopies the images into your registry (above)
hart_<version>_<os>_<arch>.tar.gz, hart_<version>_SHA256SUMShart for darwin and linux on amd64 and arm64, and the checksums of the four archives
harthelm-<version>-sboms.tar.gz and .sha256the SBOMs
harthelm-restore-<version>.tar.gz and .sha256the restore runbooks
harthelm-<version>-amd64.tar, harthelm-<version>-arm64.tar and their .sha256the air-gapped bundles
harthelm-<version>-sources.txtthe index of the source bundle

Check every download against its checksum:

Terminal
v=1.6.0
curl -fsSLO "https://get.harthelm.dev/releases/$v/harthelm-restore-$v.tar.gz"
curl -fsSLO "https://get.harthelm.dev/releases/$v/harthelm-restore-$v.tar.gz.sha256"
sha256sum -c "harthelm-restore-$v.tar.gz.sha256"    # macOS: shasum -a 256 -c

The hart archives share one file: sha256sum --ignore-missing -c hart_1.6.0_SHA256SUMS. A checksum from the same host shows that a download is complete, not who made it; for the images and the chart, the signatures do that.

Air-gapped bundles

Without a host that reaches both registry.harthelm.dev and your registry, carry a bundle over. There is one per architecture, harthelm-<version>-amd64.tar and harthelm-<version>-arm64.tar, and it unpacks to one directory:

PathWhat
images.txtevery image of the release for that platform, by the digest of its platform manifest
oci/the images as an OCI image layout
harthelm-<version>.tgzthe chart, pinned to those digests
mirror.sh, README.txtthe script and these steps

Use the bundle of your nodes' architecture: its chart pins that platform's manifests. A cluster with nodes of both architectures needs the multi-arch images instead: mirror them from images-public.txt (above), through a directory if no host sees both sides, and install the public chart.

Check and verify on the connected side

Download the bundle and its .sha256, check it, and verify the signatures of its images while you still reach registry.harthelm.dev:

Terminal
v=1.6.0; arch=amd64
sha256sum -c "harthelm-$v-$arch.tar.sha256"         # macOS: shasum -a 256 -c
tar -xf "harthelm-$v-$arch.tar"

Then carry the .tar and its .sha256 over.

Load your registry

On a host that reaches your registry, check the file again, unpack it and load the images:

Terminal
v=1.6.0; arch=amd64
sha256sum -c "harthelm-$v-$arch.tar.sha256"
tar -xf "harthelm-$v-$arch.tar" && cd "harthelm-$v-$arch"
./mirror.sh --from-bundle . registry.example.internal
./mirror.sh --verify registry.example.internal

skopeo copies every image out of the bundle's layout with its digest. --verify only reads and compares.

Install

The chart holds values-airgap.yaml, the values an air-gapped install needs, with placeholders for your hosts. Take it out, fill it in, and set global.imageRegistry: registry.example.internal in your values:

Terminal
tar -xzf "harthelm-$v.tgz" harthelm/values-airgap.yaml && cp harthelm/values-airgap.yaml .
helm install harthelm "./harthelm-$v.tgz" -n harthelm-system -f values-airgap.yaml -f my-values.yaml

The images are then registry.example.internal/harthelm/<image>. Air-gapped installs explains the values, the operators and the mirrors for the workspaces' tools.

The source code

Harthelm's images contain components under the GPL, LGPL and MPL. The complete source of each of them (Ubuntu, Debian and Alpine source packages, the Nix sources, npm tarballs and vendor tarballs), in the versions a release ships, is one file per release:

Terminal
v=1.6.0
curl -fsSLO "https://get.harthelm.dev/sources/harthelm-$v-sources.tar"
curl -fsSLO "https://get.harthelm.dev/sources/harthelm-$v-sources.tar.sha256"
sha256sum -c "harthelm-$v-sources.tar.sha256"

Its index, harthelm-<version>-sources.txt, is next to it and in the release's folder. The files under sources/ are written once and kept for every release. You do not need them to run Harthelm. Open-source components says what the bundle holds and where the notices are.

On this page