No description
Find a file
autocommit e50036b0ff
Some checks failed
Build and Publish / build-and-publish (push) Failing after 44s
deps-upgrade(dependencies): ⬆️ Update dependencies to latest stable versions for security patches and feature improvements
Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
2026-06-11 01:20:34 -07:00
.forgejo/workflows fix(ci): fix backslash-bang syntax error in workflow 2026-01-30 15:49:44 -08:00
dist chore(gitignore): Add missing patterns 2026-01-22 11:09:16 -08:00
node_modules chore(gitignore): Add missing patterns 2026-01-21 12:34:56 -08:00
src chore: initial commit 2026-01-21 11:37:53 -08:00
templates chore: initial commit 2026-01-21 11:37:53 -08:00
.gitignore chore(gitignore): Add missing patterns 2026-01-22 11:09:16 -08:00
package.json deps-upgrade(dependencies): ⬆️ Update dependencies to latest stable versions for security patches and feature improvements 2026-06-11 01:20:34 -07:00
PASSWORD_ROTATION.md chore: initial commit 2026-01-21 11:37:53 -08:00
README.md chore: trigger CI publish 2026-01-30 11:55:56 -08:00
tsconfig.json chore: initial commit 2026-01-21 11:37:53 -08:00
tsup.config.ts chore(build): 🔧 Update tsup config for optimized ESM output with minification 2026-01-21 15:29:24 -08:00

@lilith/restic-setup-client

Configure restic backup clients on workstations with automated systemd timers.

Features

  • Initialize restic repositories for Code and dotfiles backups
  • Deploy systemd user timers for automated backups (no root required)
  • Configure backup schedules: Code every 5min, dotfiles every 12hr
  • Retention policy: 7 daily, 4 weekly, 3 monthly backups (auto-pruned)

Installation

pnpm add @lilith/restic-setup-client

Prerequisites

CRITICAL: The ~/.vault/ directory must be a symlink to your project's vault directory. This is required for the circular dependency solution (see Architecture section).

# Setup vault symlink first using @lilith/vault-setup-client
npx @lilith/vault-setup-client link \
  --project ~/Code/@applications/@lilith/lilith-platform

# Verify symlink
ls -la ~/.vault
# Should show: ~/.vault -> /path/to/lilith-platform/vault

Why? Without this symlink:

  • Password rotation will fail (no ~/.vault/restic-password.txt)
  • Disaster recovery won't work (circular dependency)
  • Dotfiles backup won't include vault files

See @lilith/vault-setup-client for details.

Usage

CLI

# Setup backup client
npx @lilith/restic-setup-client \\
  --server http://10.0.0.11:8000 \\
  --password CWPVvKALTwyJfbdVE3oIq7L8Wc7MH4Pz

# With custom hostname
npx @lilith/restic-setup-client \\
  --server http://10.0.0.11:8000 \\
  --hostname apricot \\
  --password CWPVvKALTwyJfbdVE3oIq7L8Wc7MH4Pz

Programmatic API

import { setupClient } from '@lilith/restic-setup-client'

const result = await setupClient({
  serverUrl: 'http://10.0.0.11:8000',
  hostname: 'apricot', // Optional: defaults to $(hostname)
  password: 'CWPVvKALTwyJfbdVE3oIq7L8Wc7MH4Pz',
  codeBackupInterval: '5min', // Optional: default
  dotfilesBackupInterval: '12hr', // Optional: default
})

if (result.success) {
  console.log(`✅ Setup complete`)
  console.log(`Code repo: ${result.codeRepoUrl}`)
  console.log(`Dotfiles repo: ${result.dotfilesRepoUrl}`)
} else {
  console.error(`❌ Setup failed: ${result.error}`)
}

What It Does

1. Configuration Setup

Creates ~/.config/restic/:

  • password (mode 600): Repository password
  • dotfiles-include.txt: List of dotfiles to backup

2. Repository Initialization

Initializes two repositories on the REST server:

  • <hostname>-code: Backs up ~/Code
  • <hostname>-dotfiles: Backs up selected dotfiles

3. Systemd Timer Deployment

Deploys 4 systemd user units to ~/.config/systemd/user/:

  • restic-backup-code.service + restic-backup-code.timer
  • restic-backup-dotfiles.service + restic-backup-dotfiles.timer

Timers are enabled and started automatically.

Backup Configuration

Code Backup (restic-backup-code.timer)

  • Frequency: Every 5 minutes
  • Target: ~/Code
  • Excludes: node_modules, .git/objects, dist, build, .next, target, __pycache__, .pyc, .venv, venv
  • Retention: 7 daily, 4 weekly, 3 monthly
  • Nice level: 10 (low priority)
  • I/O class: idle

Dotfiles Backup (restic-backup-dotfiles.timer)

  • Frequency: Every 12 hours
  • Target: Selective dotfiles from dotfiles-include.txt
  • Includes: .bashrc, .zshrc, .ssh, .gitconfig, .config/nvim, .vault (symlink), etc.
  • Excludes: .cache, Trash, .npm, .pnpm-store, browser caches
  • Retention: 7 daily, 4 weekly, 3 monthly

Note: .vault is backed up as a symlink, preserving the link to the project vault.

Operations

Check Timer Status

# List all restic timers
systemctl --user list-timers | grep restic

# Check service status
systemctl --user status restic-backup-code.timer
systemctl --user status restic-backup-dotfiles.timer

Manual Backup

# Trigger code backup now
systemctl --user start restic-backup-code.service

# Trigger dotfiles backup now
systemctl --user start restic-backup-dotfiles.service

View Backup Logs

# Follow code backup logs
journalctl --user -u restic-backup-code.service -f

# View recent dotfiles backup
journalctl --user -u restic-backup-dotfiles.service -n 50

List Snapshots

export RESTIC_PASSWORD_FILE=~/.config/restic/password

# Code snapshots
restic -r rest:http://10.0.0.11:8000/$(hostname)-code snapshots

# Dotfiles snapshots
restic -r rest:http://10.0.0.11:8000/$(hostname)-dotfiles snapshots

Restore Files

export RESTIC_PASSWORD_FILE=~/.config/restic/password
REPO="rest:http://10.0.0.11:8000/$(hostname)-code"

# List files in latest snapshot
restic -r $REPO ls latest

# Restore specific file
restic -r $REPO restore latest \\
  --target ~/restore \\
  --include ~/Code/path/to/file.txt

# Restore entire Code directory
restic -r $REPO restore latest --target ~/restore

Requirements

  • restic binary installed (dnf install restic or brew install restic)
  • systemd for user timers
  • Vault symlink (~/.vault/ → project vault) via @lilith/vault-setup-client
  • SSH access to restic REST server (for initial password fetch, optional)

Architecture

Vault Circular Dependency Solution

Problem: Restic backups ~/Code, but we need the restic password to restore ~/Code after data loss.

Solution: Symlink + dual backup paths

  1. Primary storage: Project vault at lilith-platform/vault/
  2. Symlink: ~/.vault/lilith-platform/vault/ (convenient access)
  3. Dual backups:
    • Code backup: Backs up project vault via ~/Code/.../@lilith/lilith-platform/vault/
    • Dotfiles backup: Backs up symlink .vault directly

Disaster Recovery Flow:

# 1. Restore dotfiles first (includes ~/.vault symlink)
restic -r rest:http://10.0.0.11:8000/$(hostname)-dotfiles restore latest --target ~/

# 2. Use vault password to restore Code
export RESTIC_PASSWORD_FILE=~/.vault/restic-password.txt
restic -r rest:http://10.0.0.11:8000/$(hostname)-code restore latest --target ~/

# 3. Full recovery complete (vault + code + dotfiles)

Defense-in-depth: Password also stored in macOS Keychain via password rotation.

Integration with Server

This package is designed to work with @lilith/restic-setup-server:

import { deployServer, generatePassword } from '@lilith/restic-setup-server'
import { setupClient } from '@lilith/restic-setup-client'

// 1. Deploy server on devops host
const password = generatePassword()
const serverResult = await deployServer({
  host: '10.0.0.11',
  password,
})

// 2. Setup client on workstation
if (serverResult.success) {
  const clientResult = await setupClient({
    serverUrl: serverResult.serverUrl,
    password: serverResult.password,
  })
}

License

UNLICENSED - Internal Lilith Platform infrastructure package