Production deployment previously depended on an illustrative Docker snippet and did not define which state or identity must survive replacement. Add a non-root runtime image, loopback-only Compose service, optional Caddy TLS overlay, shared /data layout, bounded public verifier, and an identity-persistence container test. Document backup, proxy, single-writer, upgrade, and rollback requirements as the contract for every environment. This assumes one ngit-grasp writer per state directory and a reverse proxy or platform edge for public TLS. Image publication and provider-specific control-plane setup are deliberately left to separate changes. Validated with sh -n, ShellCheck 0.11.0, locked Cargo metadata, YAML parsing, Docker Hub tag lookups, local input-failure checks, and git diff --check. Docker/Podman is unavailable in this VM, so the included end-to-end container test was not run here.
3.9 KiB
Deploy with Docker or Podman
This is the portable default for a Linux host. The repository ships a
multi-stage Dockerfile, a loopback-only Compose service, and an optional
Caddy overlay for automatic HTTPS.
The image contains ngit-grasp, Git, CA certificates, and a small init process.
It prepares /data and then runs ngit-grasp as UID/GID 10001.
Prerequisites
- Docker Engine with Compose v2, or a compatible Podman Compose setup
- durable local storage for the named volume
- a domain whose DNS points to the host
- ports 80 and 443 available when using bundled Caddy
Review the deployment contract before placing the state volume on remote or managed storage.
Fresh VPS with automatic HTTPS
Create the small deployment environment file:
cp deploy.env.example .env
Set NGIT_DOMAIN in .env, then start the relay and Caddy:
docker compose -f compose.yaml -f compose.caddy.yaml up --build -d
docker compose -f compose.yaml -f compose.caddy.yaml ps
scripts/verify-deployment.sh https://ngit.example.com
Caddy obtains and renews the certificate. The relay is also published on
127.0.0.1:7334 for local diagnostics, but it is not directly reachable from
the network.
The bundled Caddy configuration serves ngit-grasp at the domain root. To share
a hostname using NGIT_BASE_PATH, use an existing reverse proxy and configure
its path routing explicitly.
Existing reverse proxy
Start only the relay service:
docker compose up --build -d
curl -H 'Accept: application/nostr+json' http://127.0.0.1:7334
Proxy the public HTTPS hostname to http://127.0.0.1:7334. Preserve WebSocket
upgrades, request methods, bodies, and query strings. Forwarded client IP
headers are ignored by default; configure NGIT_TRUSTED_PROXY_CIDRS only after
identifying the exact container-visible proxy address and keeping the backend
private.
State and identity
The ngit-grasp-data named volume is mounted at /data and contains all
durable state. The first start creates /data/.relay-owner.nsec; retaining the
volume retains the public identity advertised in NIP-11.
Inspect the resolved volume without guessing its Compose prefix:
docker volume inspect ngit-grasp_ngit-grasp-data
Do not use docker compose down --volumes in production. It deletes the relay
identity, events, and Git repositories.
Operations
# Logs
docker compose logs --follow ngit-grasp
# Controlled restart
docker compose restart ngit-grasp
# Stop while retaining state
docker compose stop
# Start again
docker compose start
When the Caddy overlay is active, include both -f arguments for commands that
must operate on the complete project.
Backup
Stop the writer, archive the complete volume, and start it again:
docker compose stop ngit-grasp
docker run --rm \
--volume ngit-grasp_ngit-grasp-data:/data:ro \
--volume "$PWD:/backup" \
alpine:3.22 \
tar -czf /backup/ngit-grasp-data.tar.gz -C /data .
docker compose start ngit-grasp
Store the archive away from the Docker host. Test restoration into a separate, non-public deployment before relying on it.
Upgrade
Pin or check out the intended tag, read CHANGELOG.md, take a backup, and
rebuild without overlapping the old and new writers:
docker compose stop ngit-grasp
docker compose build --pull ngit-grasp
docker compose up -d ngit-grasp
scripts/verify-deployment.sh https://ngit.example.com
For storage-changing releases, follow the linked migration guide and restore the pre-upgrade volume snapshot before attempting a binary rollback.
Validate the image locally
The repository includes a destructive-to-test-resources-only integration check. It builds the image, creates uniquely named temporary container and volume resources, replaces the container, and confirms the NIP-11 pubkey did not change:
scripts/test-container-deployment.sh
Set CONTAINER_ENGINE=podman to exercise a compatible Podman CLI.