Install¶
Tapyr is a single static binary with the web UI embedded. Releases ship it for Linux, macOS and Windows (amd64, arm64), and as the multi-arch image ghcr.io/kentrow/tapyr.
Binary¶
Download the archive of your platform and checksums.txt from the releases page, check it, then put tapyr in your PATH:
VERSION=0.1.0
curl -LO https://github.com/kentrow/tapyr/releases/download/v$VERSION/tapyr_${VERSION}_linux_amd64.tar.gz
curl -LO https://github.com/kentrow/tapyr/releases/download/v$VERSION/checksums.txt
sha256sum --ignore-missing -c checksums.txt
tar xzf tapyr_${VERSION}_linux_amd64.tar.gz tapyr
./tapyr version
On macOS, sha256sum is not installed: check the archive with shasum -a 256 --ignore-missing -c checksums.txt.
Each archive has its SBOM next to it (<archive>.sbom.json, SPDX), and holds LICENSE, NOTICE and THIRD_PARTY_LICENSES, the licenses and notices of the software the binary includes.
Container image¶
docker run -d --name tapyr \
-v "$PWD/config:/etc/tapyr:ro" \
-v tapyr-data:/home/nonroot/data \
-p 9790:9790 \
ghcr.io/kentrow/tapyr:0.1.0
- The image runs
tapyr run --config /etc/tapyras thenonrootuser (uid 65532), ongcr.io/distroless/static-debian12. - The state store (quota consumption, rotated tokens, counters) defaults to
./data/tapyr.db, that is/home/nonroot/datain the image: keep it on a volume, or Tapyr forgets on restart what it already spent of the daily and monthly quotas. - Set
settings.server.listento0.0.0.0:9790in the configuration, so that the published port reaches the UI, the status API and/metrics. - Secrets come from environment variables or files (
{ env: NAME },{ file: /path }): pass them with-eor mount them, never in the configuration files. docker kill -s HUP tapyrreloads the configuration.
Tags: X.Y.Z, X.Y (latest patch of a minor version) and latest (latest release).
systemd¶
examples/systemd has a hardened unit: a dynamic user, the configuration in /etc/tapyr, the secrets in an environment file read by systemd, the state store in /var/lib/tapyr, and systemctl reload tapyr for a reload.
Kubernetes¶
examples/kubernetes has Kustomize manifests: a Deployment of one replica (non-root, read-only root file system, probes on /readyz and /healthz), its Service, a volume for the state store, and the configuration as a ConfigMap whose changes roll the Deployment out. Run a single replica: a second one would spend the same quotas without coordinating.
Verify the signatures¶
The checksums and the image are signed with cosign in keyless mode by the release workflow of the repository. The signature proves that the files and the image were built by that workflow, from a tag of Kentrow/tapyr. The identity is compared as written, case included.
# The checksums of a release (then check the archives with sha256sum, above).
cosign verify-blob checksums.txt \
--bundle checksums.txt.sigstore.json \
--certificate-identity "https://github.com/Kentrow/tapyr/.github/workflows/release.yml@refs/tags/v$VERSION" \
--certificate-oidc-issuer https://token.actions.githubusercontent.com
# The image.
cosign verify ghcr.io/kentrow/tapyr:$VERSION \
--certificate-identity "https://github.com/Kentrow/tapyr/.github/workflows/release.yml@refs/tags/v$VERSION" \
--certificate-oidc-issuer https://token.actions.githubusercontent.com
The SBOM of the image is attached to it as an attestation:
docker buildx imagetools inspect ghcr.io/kentrow/tapyr:$VERSION --format '{{ json .SBOM }}'
From source¶
Go 1.27 and Node.js 22 or later:
git clone https://github.com/kentrow/tapyr.git
cd tapyr
make build # the UI, then the static binary in ./bin/tapyr
make docker # or the image tapyr:dev