Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Deployment

Two deploy paths: infrastructure (NixOS config changes) and application code (per-service repos).

Infrastructure

Pushing to main triggers .github/workflows/deploy.yaml which runs deploy-rs over Tailscale to rebuild NixOS on the target machine.

# From the dev shell (preferred)
nix develop
deploy .#terebithia
deploy .#prattle

# Manual one-off
nix develop .#default --command deploy --ssh-user kierank .#terebithia

Builds happen on an arch-matched CI runner; only the closure diff is copied to the target.

Application Code

Each service repo has a minimal workflow calling the reusable .github/workflows/deploy-service.yml. On push to main:

  1. Connects to Tailscale (tag:ci)
  2. SSHes as the service user (e.g., cachet@terebithia) via Tailscale SSH
  3. Snapshots the SQLite DB (if db_path is provided)
  4. git pull + install (bun install --frozen-lockfile, or whatever install_command says) + sudo systemctl restart
  5. Health check (HTTP URL or systemd status fallback)
  6. Auto-rollback on failure (restores DB snapshot + reverts to previous commit)

Per-app workflow. Copy and change the with: values:

name: Deploy
on:
  push:
    branches: [main]
  workflow_dispatch:
jobs:
  deploy:
    uses: taciturnaxolotl/dots/.github/workflows/deploy-service.yml@main
    with:
      service: cachet
      health_url: https://cachet.dunkirk.sh/health
      db_path: /var/lib/cachet/data/cachet.db
    secrets:
      TS_OAUTH_CLIENT_ID: ${{ secrets.TS_OAUTH_CLIENT_ID }}
      TS_OAUTH_SECRET: ${{ secrets.TS_OAUTH_SECRET }}

Omit health_url to fall back to systemctl is-active. Omit db_path for stateless services. Set install_command for anything that is not bun, e.g. env UV_PYTHON_DOWNLOADS=never uv sync --frozen for python/uv services (see botme).

Adding a new service

  1. Create a module in modules/nixos/services/ using mkService or a custom module
  2. Register secrets in secrets/secrets.nix and encrypt with agenix
  3. Enable in the target machine’s default.nix
  4. Add a deploy workflow to the app repo (if it has one)

See modules/nixos/services/cachet.nix for a minimal mkService example.