Skip to content

Production install

Install on any Linux or macOS host (x64/arm64) with Docker + the compose v2 plugin:

Terminal window
curl -fsSL https://nugetkeep.com/install | bash

This downloads the self-contained nugetkeep-install binary for your platform from the public releases repo, verifies its sha256 against the release’s checksums.txt, and launches it. On a terminal you get a guided wizard — port, database, package storage, optional domain with automatic HTTPS, optional OIDC/SSO, optional license key — and at the end a running stack plus the admin API key and a ready-to-run dotnet nuget push line.

Pass flags after --:

Terminal window
curl -fsSL https://nugetkeep.com/install | bash -s -- --domain nuget.acme.com

The generated deploy lands in ./deploy (override with --dir): a docker-compose.yml, a 0600 .env holding the secrets, and a Caddyfile when a domain is set. Re-running is idempotent — the admin key is reused (rotate with --force), bundled database/storage passwords are never silently rotated, and switching database or storage providers requires an explicit confirmation because data and blobs do not migrate.

Windows: run the same command inside WSL2 — native Windows support lands later. Alpine/musl hosts: run the Docker image directly.

Terminal window
curl -fsSL https://nugetkeep.com/install | bash -s -- --yes \
--image ghcr.io/atypical-consulting/nugetkeep:latest --port 5380 --api-key "$ADMIN_KEY"

--yes takes defaults and never prompts (without a terminal, the installer refuses to guess unless --yes is set). Every flag has an environment-variable twin with the same names the classic script used (DB, STORAGE, API_KEY, ASSUME_YES, …).

CommandWhat it does
install (default)Collect → validate → render → apply: brings the compose stack up and waits for /health/ready.
render --target compose|docker-run|helmWrite the deployment files only; never touches Docker.
validatePre-flight probes only (Docker, database, storage, OIDC, port) — exit code for CI.
license <jwt|file>Verify a license key offline and print edition/customer/expiry.

Single container — no compose, one docker run:

Terminal window
curl -fsSL https://nugetkeep.com/install | bash -s -- render --target docker-run \
--image ghcr.io/atypical-consulting/nugetkeep:latest
./deploy/run.sh

Kubernetes — renders values.yaml + nugetkeep-secret.yaml + helm-install.sh for the NuGetKeep Helm chart (the installer never touches your cluster):

Terminal window
curl -fsSL https://nugetkeep.com/install | bash -s -- render --target helm \
--image ghcr.io/atypical-consulting/nugetkeep:latest

Pull the chart once from GHCR and point the generated script at it:

Terminal window
helm pull oci://ghcr.io/atypical-consulting/charts/nugetkeep --untar --untardir ~/.nugetkeep
NUGETKEEP_CHART_PATH=~/.nugetkeep/nugetkeep ./deploy/helm-install.sh

(Contributors working from a source checkout can use the chart at charts/nugetkeep directly instead.)

The helm target expects the cluster to bring its own database/object storage/SSO — bundled PostgreSQL/MinIO/Dex are compose-only, and the installer says so.

Terminal window
curl -fsSL https://nugetkeep.com/install | NUGETKEEP_INSTALL_VERSION=0.5.0 bash

NUGETKEEP_INSTALL_BASE_URL points the shim at a mirror serving the same URL layout. To audit before running: the shim is plain text at nugetkeep.com/install, and the tarballs + checksums.txt can be downloaded and checked by hand from the releases repo.

FlagPurpose
--dir <path>Output directory for the stack files (default ./deploy).
--port <n>Host port when not behind Caddy (default 8080).
--image <ref>Image to deploy. The public GHCR image (ghcr.io/atypical-consulting/nugetkeep, pinned to the installer’s version) is the default outside a source checkout; inside one, the local Dockerfile is built instead.
--api-key <key>Pin the admin key (otherwise a strong one is generated).
--db <mode>sqlite (default), postgres (bundled container), external-postgres.
--db-connection <conn>For external-postgres — Npgsql keyword form or a postgres:// URI; validated before anything is written.
--db-password <pw>Pin the bundled-postgres password (otherwise generated; never rotated on re-run).
--skip-db-checkSkip the external-database connection pre-flight.
--storage <mode>filesystem (default), minio (bundled), s3, azure-blob.
--s3-endpoint / --s3-bucket / --s3-region / --s3-access-key / --s3-secret-key / --s3-path-styleExternal S3-compatible settings (prefer the S3_SECRET_KEY env var for the secret).
--azure-connection <conn> / --azure-container <name>Azure Blob settings (prefer the AZURE_CONNECTION env var).
--minio-password <pw>Pin the bundled-MinIO root password (otherwise generated; reused on re-run).
--skip-storage-checkSkip the bucket/container pre-flight.
--domain <host>Front with Caddy for automatic HTTPS on that domain (compose target).
--oidc-authority / --oidc-client-id / --oidc-client-secretEnable SSO.
--bootstrap-admins <csv>Emails auto-granted Admin on first login.
--with-dex / --dex-email / --dex-passwordBundle a local Dex IdP (local/dev only).
--with-monitoring / --grafana-port <n>Prometheus + Grafana sidecars (compose); the chart’s ServiceMonitor toggle (helm).
--license-key <jwt|file>Validate (offline) and install an Enterprise license.
--target <t>compose (default), docker-run, helm (render only for the last two).
--pull / --no-buildImage acquisition control for install.
--forceRotate the admin key / confirm a provider switch.
--dry-runPrint the rendered files (secrets redacted) instead of writing.
--printLegacy install alias for render-only (prefer the render command).
--allow-test-licenseAccept test-signed license keys (development only).
--yesNon-interactive: take defaults, never prompt.

The interactive picker offers SQLite (single container, zero config — the right start for most teams), a bundled PostgreSQL container managed by the same stack, or an existing PostgreSQL server. Bundled mode adds a second volume, nugetkeep-pgdata, and the summary prints a pg_dump backup hint; external mode validates the connection before the stack is written. Trade-offs, backup guidance, and the no-data-migration caveat when switching: Choosing a database.

A second picker chooses where package blobs live: the local data volume (zero config), a bundled MinIO container, an existing S3-compatible bucket (AWS S3, MinIO, R2, …), or Azure Blob Storage. Bundled MinIO adds a nugetkeep-miniodata volume; the external modes pre-flight the bucket/container before the stack is written. Trade-offs and the no-blob-migration caveat: Choosing package storage.

Manage the stack afterwards from the deploy dir: cd deploy && docker compose ps / logs -f / restart / down. The nugetkeep-data volume survives docker compose down. To enable SSO, see Identity & SSO; to license Enterprise features, see Applying a license.

Contributors only: from a source checkout, scripts/install.sh still works with the same flags — it is a thin wrapper that runs the same installer from source (needs the .NET SDK from global.json); without the SDK it points you at the hosted command above.