The production guide was NixOS-only despite presenting itself as the general deployment entry point, and its examples referenced an unavailable GitHub source and a hardening control the module does not set. Turn the entry point into an environment chooser, preserve the corrected NixOS material in its own guide, add a hardened generic systemd unit and repeatable Linux installation, document the preferred unprivileged Proxmox layout, and update repository navigation and architecture references. Each path assumes the shared deployment contract from the container change. Kubernetes automation, remote host mutation, and changes to the existing NixOS module are deliberately excluded. Validated the canonical Git remote with git ls-remote, parsed and scored the systemd unit with systemd-analyze, checked all new deployment-guide links, removed trailing whitespace, scanned the staged diff for key-shaped nsec values, and ran git diff --check.
3.0 KiB
Deploy a static binary with systemd
Use this path for a conventional Debian, Ubuntu, Fedora, or other systemd Linux server when containers are unnecessary. Build the portable binary on a Nix build machine, then copy only the binary and service files to the server.
Build a pinned binary
From a clean checkout of the reviewed tag or revision:
nix build .#static
file result/bin/ngit-grasp
Copy result/bin/ngit-grasp, deploy/systemd/ngit-grasp.service, and
deploy/systemd/ngit-grasp.env.example to the server through your normal
authenticated deployment channel.
The deployment host does not need Nix or Rust. It does need Git and trusted CA certificates:
sudo apt-get update
sudo apt-get install -y ca-certificates git
Use the equivalent packages on non-Debian distributions.
Install
getent group ngit-grasp >/dev/null || sudo groupadd --system ngit-grasp
id -u ngit-grasp >/dev/null 2>&1 || \
sudo useradd --system --gid ngit-grasp --home-dir /var/lib/ngit-grasp \
--create-home --shell /usr/sbin/nologin ngit-grasp
sudo install -Dm755 ngit-grasp /usr/local/bin/ngit-grasp
sudo install -Dm644 ngit-grasp.service \
/etc/systemd/system/ngit-grasp.service
sudo install -Dm640 -o root -g ngit-grasp ngit-grasp.env.example \
/etc/ngit-grasp/ngit-grasp.env
sudo install -d -m 0750 -o ngit-grasp -g ngit-grasp \
/var/lib/ngit-grasp \
/var/lib/ngit-grasp/git \
/var/lib/ngit-grasp/relay
Edit /etc/ngit-grasp/ngit-grasp.env and set NGIT_DOMAIN.
If restoring an existing identity, install .relay-owner.nsec as mode 0600
owned by ngit-grasp under /var/lib/ngit-grasp. Otherwise the first start
generates it there.
Reverse proxy and TLS
Keep the service bound to 127.0.0.1:7334. For Caddy, a domain-root virtual
host is:
ngit.example.com {
reverse_proxy 127.0.0.1:7334
}
Point DNS at the server and replace ngit.example.com in both Caddy and the
ngit-grasp environment file. Caddy preserves WebSocket upgrades automatically.
Start and verify
On the server:
sudo systemctl daemon-reload
sudo systemctl enable --now ngit-grasp
sudo systemctl status ngit-grasp --no-pager
sudo journalctl -u ngit-grasp -n 50 --no-pager
From the repository checkout on the operator workstation:
scripts/verify-deployment.sh https://ngit.example.com
The service unit applies a restrictive umask, filesystem protection, private temporary directory, empty capability set, and bounded five-minute shutdown.
Upgrade and rollback
Build the new pinned binary before touching the server. Read CHANGELOG.md,
stop the service, snapshot /var/lib/ngit-grasp, install the new binary, and
start the service:
sudo systemctl stop ngit-grasp
sudo install -Dm755 ngit-grasp /usr/local/bin/ngit-grasp
sudo systemctl start ngit-grasp
Run the verifier and inspect startup integrity summaries. If the release changed storage, restoring the old binary also requires restoring its matching state snapshot.