From 51a3d810d2a73a6300c51d3baf6060bb33f6b92c Mon Sep 17 00:00:00 2001 From: DanConwayDev Date: Sun, 11 Jan 2026 15:09:46 +0000 Subject: docs: add production deployment how-to guide - Complete guide for deploying ngit-grasp to NixOS servers - Step-by-step deployment instructions - Configuration options reference - Troubleshooting section - Security hardening recommendations - Multiple instance examples - References nix/example-configuration.nix which has clear examples --- docs/how-to/deploy.md | 487 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 487 insertions(+) create mode 100644 docs/how-to/deploy.md (limited to 'docs') diff --git a/docs/how-to/deploy.md b/docs/how-to/deploy.md new file mode 100644 index 0000000..6fe8776 --- /dev/null +++ b/docs/how-to/deploy.md @@ -0,0 +1,487 @@ +# How-To: Deploy ngit-grasp to Production + +**Purpose:** Deploy ngit-grasp to a production NixOS server +**Difficulty:** Intermediate +**Time:** 30-60 minutes + +--- + +## Problem + +You want to: +- Deploy ngit-grasp to a NixOS server +- Configure it as a systemd service +- Set up reverse proxy (Caddy) +- Ensure proper security and monitoring + +--- + +## Prerequisites + +- NixOS server with SSH access +- Flakes enabled on server and local machine +- Domain name configured (DNS pointing to server) +- Basic knowledge of NixOS configuration + +--- + +## Solution + +### Step 1: Add ngit-grasp to Your Server's Flake + +In your server's `flake.nix`, add ngit-grasp as an input: + +```nix +{ + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs/nixos-24.11"; + ngit-grasp.url = "github:DanConwayDev/ngit-grasp"; + # or use a specific git repository: + # ngit-grasp.url = "git+https://git.shakespeare.diy/npub.../ngit-grasp.git"; + }; + + outputs = { self, nixpkgs, ngit-grasp, ... }@inputs: { + nixosConfigurations.your-hostname = nixpkgs.lib.nixosSystem { + system = "x86_64-linux"; + specialArgs = { inherit inputs; }; + modules = [ + ./configuration.nix + # ... other modules + ]; + }; + }; +} +``` + +--- + +### Step 2: Create Service Configuration + +Create a new file for your ngit-grasp service (e.g., `services/ngit-grasp.nix`): + +```nix +{ inputs, ... }: + +{ + imports = [ inputs.ngit-grasp.nixosModules.default ]; + + services.ngit-grasp.production = { + enable = true; + domain = "ngit.example.com"; + + # Network + bindAddress = "127.0.0.1"; + port = 8082; + + # Storage + dataDir = "/persistent/ngit-grasp"; + + # Identity + relayName = "My GRASP Relay"; + relayDescription = "A Rust GRASP implementation with proactive sync"; + relayOwnerNsecFile = "/persistent/ngit-grasp/relay-owner.nsec"; + + # Sync - bootstrap from relay.ngit.dev + syncBootstrapRelayUrl = "wss://relay.ngit.dev"; + + # Metrics + metricsEnabled = true; + + # Logging + logLevel = "info"; + }; + + # Caddy reverse proxy + services.caddy.virtualHosts."ngit.example.com" = { + extraConfig = '' + reverse_proxy 127.0.0.1:8082 { + header_down X-Real-IP {http.request.remote} + header_down X-Forwarded-For {http.request.remote} + } + ''; + }; +} +``` + +**Key configuration options:** + +- **Instance name** (`production`): Can be any name. Used for systemd service (`ngit-grasp-production`) +- **domain**: Your relay's domain (used in GRASP validation) +- **port**: Local port (use reverse proxy for HTTPS) +- **dataDir**: Where git repos and database are stored +- **relayOwnerNsecFile**: Path to file containing relay owner's nsec + - If file doesn't exist, ngit-grasp will auto-generate one + - Alternative: `relayOwnerNsec = "nsec1..."` (less secure, in nix store) +- **syncBootstrapRelayUrl**: Bootstrap relay to sync from on startup + +See [nix/example-configuration.nix](../../nix/example-configuration.nix) for more examples. + +--- + +### Step 3: Import the Service + +Import your service configuration in your main configuration file: + +```nix +# In configuration.nix or services/default.nix +{ + imports = [ + ./services/ngit-grasp.nix + # ... other services + ]; +} +``` + +--- + +### Step 4: Update Flake Lock + +```bash +cd /path/to/server/config +nix flake update ngit-grasp +git add flake.lock +git commit -m "Add ngit-grasp and update flake.lock" +``` + +--- + +### Step 5: Validate Configuration + +Before deploying, validate the configuration builds: + +```bash +nix flake check +``` + +--- + +### Step 6: Deploy to Server + +Deploy the new configuration to your server: + +```bash +# Build and switch in one command (builds on server) +nixos-rebuild switch --flake .#your-hostname \ + --target-host user@server.example.com \ + --use-remote-sudo \ + --build-host user@server.example.com +``` + +**Alternative:** Build locally, then deploy: + +```bash +# Build locally +nixos-rebuild build --flake .#your-hostname + +# Deploy to server +nixos-rebuild switch --flake .#your-hostname \ + --target-host user@server.example.com \ + --use-remote-sudo +``` + +**Note:** Building locally requires your machine to trust the server's nix signing key. + +--- + +### Step 7: Verify Deployment + +SSH to the server and check the service: + +```bash +ssh user@server.example.com + +# Check service status +systemctl status ngit-grasp-production + +# View logs +journalctl -u ngit-grasp-production -f + +# Check if listening on port +ss -tlnp | grep 8082 +``` + +--- + +### Step 8: Test Functionality + +From your local machine, test the relay: + +```bash +# Test NIP-11 relay info +curl https://ngit.example.com -H "Accept: application/nostr+json" | jq + +# Test WebSocket connection +websocat wss://ngit.example.com +# Then type: ["REQ","test",{}] +# Should receive events + +# Test git clone (if you have repos) +git ls-remote https://ngit.example.com//.git +``` + +--- + +## Configuration Options + +### Required +- `enable` - Enable this instance +- `domain` - Domain where relay is hosted + +### Network +- `bindAddress` - IP to bind to (default: "127.0.0.1") +- `port` - Port to listen on (default: 8080) + +### Storage +- `dataDir` - Base directory for data (default: /var/lib/ngit-grasp-{name}) +- `databaseBackend` - "lmdb" | "nostr-db" | "memory" (default: "lmdb") + +### Identity +- `relayName` - Relay name for NIP-11 (default: "{domain} grasp relay") +- `relayDescription` - Relay description +- `relayOwnerNsecFile` - Path to file with relay owner nsec (recommended) +- `relayOwnerNsec` - Inline nsec (less secure) + +### Sync +- `syncBootstrapRelayUrl` - Bootstrap relay URL (optional) +- `syncDisableNegentropy` - Disable NIP-77 negentropy (default: false) +- `syncMaxBackoffSecs` - Max backoff for reconnection (default: 3600) +- `syncDisconnectCheckIntervalSecs` - Check interval (default: 60) +- `syncBaseBackoffSecs` - Base backoff time (default: 5) + +### Metrics +- `metricsEnabled` - Enable /metrics endpoint (default: true) +- `metricsConnectionPerIpAbuseThreshold` - Abuse threshold (default: 10) +- `metricsTopNRepos` - Number of top repos to track (default: 10) + +### Logging +- `logLevel` - "trace" | "debug" | "info" | "warn" | "error" (default: "info") + +### Security +- `user` - User to run as (default: "ngit-grasp-{name}") +- `group` - Group to run as (default: "ngit-grasp") + +See [nix/module.nix](../../nix/module.nix) for complete option definitions. + +--- + +## Systemd Service + +The NixOS module creates a systemd service: `ngit-grasp-{instance-name}` + +```bash +# Start/stop/restart +systemctl start ngit-grasp-production +systemctl stop ngit-grasp-production +systemctl restart ngit-grasp-production + +# Enable/disable autostart +systemctl enable ngit-grasp-production +systemctl disable ngit-grasp-production + +# View logs +journalctl -u ngit-grasp-production -f +journalctl -u ngit-grasp-production --since "1 hour ago" + +# Check status +systemctl status ngit-grasp-production +``` + +--- + +## Multiple Instances + +You can run multiple instances on the same server: + +```nix +services.ngit-grasp = { + production = { + enable = true; + domain = "ngit.example.com"; + port = 8082; + dataDir = "/persistent/ngit-production"; + }; + + staging = { + enable = true; + domain = "ngit-staging.example.com"; + port = 8083; + dataDir = "/persistent/ngit-staging"; + logLevel = "debug"; + }; +}; +``` + +Each instance: +- Runs as separate systemd service: `ngit-grasp-production`, `ngit-grasp-staging` +- Has its own user: `ngit-grasp-production`, `ngit-grasp-staging` +- Stores data in separate directory +- Can have different configuration + +--- + +## Troubleshooting + +### Service won't start + +**Check logs:** +```bash +journalctl -u ngit-grasp-production -n 50 +``` + +**Common issues:** +- Port already in use: Check with `ss -tlnp | grep 8082` +- Data directory permissions: Should be owned by service user +- Invalid nsec file: Check file exists and contains valid nsec + +### Can't connect via WebSocket + +**Check:** +- Service is running: `systemctl status ngit-grasp-production` +- Firewall allows connections: `nix-shell -p nmap --run "nmap -p 443 ngit.example.com"` +- Caddy is configured correctly: `systemctl status caddy` +- DNS resolves: `dig ngit.example.com` + +### Sync not working + +**Check logs for sync errors:** +```bash +journalctl -u ngit-grasp-production | grep -i sync +``` + +**Common issues:** +- Bootstrap relay URL incorrect or unreachable +- Network connectivity issues +- Bootstrap relay doesn't support negentropy (disable with `syncDisableNegentropy = true`) + +### High memory/CPU usage + +**Monitor metrics:** +```bash +curl http://localhost:8082/metrics +``` + +**Tune configuration:** +- Reduce `metricsTopNRepos` +- Increase `syncMaxBackoffSecs` +- Switch to `databaseBackend = "nostr-db"` for better performance + +--- + +## Rollback + +If deployment fails, rollback to previous configuration: + +```bash +# On the server +nixos-rebuild switch --rollback + +# Or remotely +nixos-rebuild switch --rollback \ + --target-host user@server.example.com \ + --use-remote-sudo +``` + +--- + +## Upgrading + +To upgrade ngit-grasp: + +```bash +# Update flake input +nix flake update ngit-grasp + +# Review changes +git diff flake.lock + +# Commit +git add flake.lock +git commit -m "Update ngit-grasp" + +# Deploy +nixos-rebuild switch --flake .#your-hostname \ + --target-host user@server.example.com \ + --use-remote-sudo \ + --build-host user@server.example.com +``` + +--- + +## Security Hardening + +The NixOS module includes systemd hardening: + +- `NoNewPrivileges = true` - Prevents privilege escalation +- `ProtectSystem = "strict"` - Read-only filesystem except dataDir +- `ProtectHome = true` - No access to home directories +- `PrivateTmp = true` - Private /tmp +- `RestrictAddressFamilies` - Only allow needed network families +- `SystemCallFilter` - Restrict system calls + +Additional recommendations: + +1. **Use nsec file instead of inline:** + ```nix + relayOwnerNsecFile = "/persistent/ngit-grasp/relay-owner.nsec"; + # NOT: relayOwnerNsec = "nsec1..."; # Ends up in nix store! + ``` + +2. **Restrict data directory permissions:** + ```bash + chmod 750 /persistent/ngit-grasp + chown ngit-grasp-production:ngit-grasp /persistent/ngit-grasp + ``` + +3. **Use HTTPS (reverse proxy required):** + - ngit-grasp binds to localhost by default + - Use Caddy/nginx for TLS termination + - Caddy handles certificates automatically + +4. **Monitor logs regularly:** + ```bash + journalctl -u ngit-grasp-production --since today | grep -i error + ``` + +--- + +## Monitoring + +### Prometheus Metrics + +ngit-grasp exposes Prometheus metrics at `/metrics`: + +```bash +curl http://localhost:8082/metrics +``` + +See [Prometheus Setup](./prometheus-setup.md) for complete monitoring guide. + +### Basic Health Checks + +```bash +# Check if service is running +systemctl is-active ngit-grasp-production + +# Check if port is listening +nc -zv localhost 8082 + +# Check relay info +curl https://ngit.example.com -H "Accept: application/nostr+json" + +# Check disk usage +du -sh /persistent/ngit-grasp/* +``` + +--- + +## Related Documentation + +- [Configuration Reference](../reference/configuration.md) - All configuration options +- [NixOS Module](../../nix/module.nix) - Module source code +- [Example Configuration](../../nix/example-configuration.nix) - More examples +- [Prometheus Setup](./prometheus-setup.md) - Monitoring guide +- [Nix Flakes How-To](./nix-flakes.md) - Nix development environment + +--- + +*Part of the [ngit-grasp how-to guides](./)* -- cgit v1.2.3