Installation and Upgrade of GoodMem
Installing in a network-restricted environment
The default installer fetches from these upstream hosts:
get.goodmem.ai— the GoodMem CLI tarballget.docker.com— the Docker engine installer (only when Docker is not yet installed)ghcr.io— the GoodMem server imagedocker.io— the PostgreSQL+pgvector imagesigstore.dev— signature material for cosign verification
When any of these is unreachable — typically inside a corporate firewall or in mainland China — the installer accepts a small set of flags that let you complete an install using a pre-staged CLI tarball plus a reachable registry mirror.
This page walks through the canonical setup using Nanjing University's
public mirrors (ghcr.nju.edu.cn and docker.nju.edu.cn) as the example.
Substitute your own internal mirror hosts if you have them.
That mirror-based flow is described first. If the target machine has no reachable registry at all — a true air-gap — see Fully offline install (air-gapped) below, which pre-stages the container images as well as the CLI tarball.
Prerequisites
-
Docker engine is already installed and reachable. The installer's auto-install path calls
get.docker.com, which may also be blocked. On Debian/Ubuntu inside China, configure a Docker Hub mirror in/etc/docker/daemon.jsononce (e.g.https://docker.nju.edu.cn) andsudo systemctl restart docker. -
Two files delivered out of band (email, scp, internal object storage):
install.sh— the bash entry point (the same file served athttps://get.goodmem.ai).goodmem-<os>-<arch>.tar.gz— the CLI tarball matching the target platform (e.g.goodmem-linux-amd64.tar.gz).
-
A reachable mirror of
ghcr.iothat proxiespair-systems-inc/goodmem/server, such asghcr.nju.edu.cn. -
A reachable mirror of
docker.iothat proxiespgvector/pgvector, such asmirror.gcr.io(Google's public Docker Hub proxy — globally reachable and proxies the full Docker Hub namespace).Not every Docker Hub mirror proxies every namespace — at the time of writing
docker.nju.edu.cnreturns 403 forpgvector/pgvectorwhile serving other images fine. Before installing, verify with:docker pull <your-mirror>/pgvector/pgvector:pg17If that fails, pick a different mirror or rely on a daemon-level
registry-mirrorsconfig in/etc/docker/daemon.jsoninstead.
Install command
bash install.sh \
--local-cli-tarball ./goodmem-linux-amd64.tar.gz \
--goodmem-image ghcr.nju.edu.cn/pair-systems-inc/goodmem/server:latest \
--pgvector-image mirror.gcr.io/pgvector/pgvector:pg17 \
--skip-verify \
--handsfree --db-password "your-secure-password-min-14-chars" \
--tls-disabledWhat each flag does:
| Flag | Effect |
|---|---|
--local-cli-tarball <path> | Use this tarball instead of downloading from get.goodmem.ai. |
--goodmem-image <ref> | Override the GoodMem server image — point at a mirrored registry (e.g. ghcr.nju.edu.cn/...). |
--pgvector-image <ref> | Override the pgvector image — point at a mirrored Docker Hub (e.g. mirror.gcr.io/...). |
--skip-verify | Skip cosign SLSA verification, which requires sigstore.dev. See the security note below. |
The image choices are sticky: they get stamped into the per-profile
.env file under ~/.goodmem/installs/local-docker/<profile>/. Subsequent
goodmem system upgrade runs reuse the same images automatically — no
need to repeat the flags on every upgrade.
Security note about --skip-verify
--skip-verify turns off the cosign SLSA-provenance check that normally
proves the image you pulled was built by GoodMem's CI from this repository.
Without it, you are trusting whatever bytes the mirror serves.
The mirror caching is content-addressable (an OCI manifest digest can't be forged without breaking SHA-256), so a benign mirror cannot serve a different image. The remaining risk is a stale mirror serving an older version, or a malicious mirror serving its own build. Two ways to harden:
- Pin a digest. Pass
--goodmem-image ghcr.nju.edu.cn/pair-systems-inc/goodmem/server@sha256:...with the digest you cross-checked against upstream. The installer then pulls that exact content. - Manually verify. If your network reaches sigstore.dev intermittently
(e.g., via a VPN), run
cosign verify-attestation --type slsaprovenance ...against the mirror before approving the install for production use.
Upgrading
First, obtain the new CLI tarball. Ask your contact at PAIR Systems for the latest release.
Then, manually upgrade Goodmem CLI without network access:
goodmem upgrade --local-cli-tarball ./goodmem-linux-amd64.tar.gz --yesThen you can upgrade the GoodMem server image. The command below pulls from the mirror configured at install time. --skip-cli-check bypasses the version gate that contacts get.goodmem.ai; --skip-verify mirrors the install-time choice.
goodmem system upgrade --skip-cli-check --skip-verifyVersion discovery
Without get.goodmem.ai, the CLI cannot tell you "a new version is
available". You'll need to learn about new releases out of band (mailing
list, internal portal, GitHub Releases on a reachable network) and bring
the new goodmem-<os>-<arch>.tar.gz over to the target machine, then run
goodmem upgrade --local-cli-tarball .... The server side picks up the
matching image automatically on the next goodmem system upgrade.
Fully offline install (air-gapped)
The network-restricted flow
above still pulls the two container images — just from a mirror instead of the
default registries. When the target machine has no reachable registry at
all, pre-stage those images too: pull them on a connected machine,
docker save them to a file, copy it across, and docker load on the target.
No mirror hosts and no --goodmem-image / --pgvector-image flags are needed.
Prerequisites
- Docker engine already installed on the target. The installer's
auto-install path calls
get.docker.com, which is unreachable here, so install Docker out of band first. - Three files delivered out of band (scp, USB, internal object storage):
install.sh— the bash entry point (the same file served athttps://get.goodmem.ai).goodmem-<os>-<arch>.tar.gz— the CLI tarball matching the target platform (e.g.goodmem-linux-amd64.tar.gz).goodmem-images.tar.gz— the saved container images, built in the next step.
Save and load the images
On a connected machine, pull both images for the target's architecture, then save them into a single file:
docker pull --platform linux/amd64 ghcr.io/pair-systems-inc/goodmem/server:latest
docker pull --platform linux/amd64 pgvector/pgvector:pg17
docker save \
ghcr.io/pair-systems-inc/goodmem/server:latest \
pgvector/pgvector:pg17 \
| gzip > goodmem-images.tar.gzOn the target machine, load them into the local Docker store:
gunzip -c goodmem-images.tar.gz | docker load
docker images | grep -E 'goodmem/server|pgvector' # both tags should appearMatch the architecture. The saved images (--platform linux/amd64) and the
CLI tarball (goodmem-linux-amd64.tar.gz) must both match the target CPU —
amd64 images will not run on an arm64 host, and vice versa.
Install command
Because the loaded images already carry the tags the installer expects, omit
the --goodmem-image / --pgvector-image flags entirely:
bash install.sh \
--local-cli-tarball ./goodmem-linux-amd64.tar.gz \
--skip-verify \
--handsfree --db-password "your-secure-password-min-14-chars" \
--tls-disabled--skip-verify is what makes this work with no network: it drops the image
pull-and-verify step, so Docker Compose resolves both images from the local
Docker store (pull policy missing) and never contacts a registry. The Compose
files themselves are embedded in the CLI binary, so nothing is fetched there
either.
If you re-tag the images while loading them, they no longer match the defaults;
pass --goodmem-image / --pgvector-image with your tags so the installer and
Compose find them.
Upgrading
There is no registry to pull from, so stage the new artifacts by hand — the same save/load pattern as the install.
First, upgrade the CLI from a new tarball (obtain it as described under Version discovery below):
goodmem upgrade --local-cli-tarball ./goodmem-linux-amd64.tar.gz --yesThen stage and load the new server image on the target, exactly as at install time:
# On a connected machine:
docker pull --platform linux/amd64 ghcr.io/pair-systems-inc/goodmem/server:latest
docker save ghcr.io/pair-systems-inc/goodmem/server:latest | gzip > goodmem-server.tar.gz
# Copy over, then on the target:
gunzip -c goodmem-server.tar.gz | docker loadFinally, roll the server onto the freshly-loaded image:
goodmem system upgrade --skip-cli-check --skip-verify--skip-cli-check bypasses the version gate that contacts get.goodmem.ai;
--skip-verify skips the registry pull and cosign check, so the upgrade uses
the image you just loaded. The pgvector image rarely changes between releases —
if it does, docker load the new one the same way before upgrading.
Version discovery
With no network, the CLI cannot tell you when a new version is available. Track
releases out of band (mailing list, internal portal, or GitHub Releases on a
reachable network), then bring both the new goodmem-<os>-<arch>.tar.gz and
the new server image over to the target and follow the Upgrading steps above.