Second Brain Insurance: Restic + Org-Roam

I’ve been hoarding notes in Org-Roam like a digital dragon. It’s my second brain, my task list, and my scratchpad for everything from TypeScript snippets to local development hacks. As that directory grows, so does the low-level anxiety that a single disk failure or a fat-fingered command could wipe out years of “aha!” moments.

I am in the process of committing these notes to a Git repository, but not everything is ready to be committed.

I needed a backup solution that was three things: encrypted (because my notes are private), deduplicated (to save space), and automated. I landed on Restic, a fast, secure backup tool that fits perfectly into a CLI-centric workflow.

Lesson Learned: Trust the Tool

When I first sat down to build this, I spent a bit of time over-engineering my folder structure. I was manually injecting shell variables to keep things organized across different machines. It looked something like this:

# The "Over-Engineered" Way
export backup_slug="kb"export
restic_repo="$HOME/.backups/$USER@$(hostname)--${backup_slug}"

After reviewing Restic’s documentation on listing snapshots, I realized the tool already handles snapshots from multiple hosts natively. Every time you create a snapshot, Restic tags it with the host it came from by default. This means I can keep the repository path simple on my disk (~/.backups/kb) and let Restic’s internal metadata handle the host identification. While the current implementation doesn’t backup multiple hosts to the same remote Restic repo, it positions me to do just that when I eventually save my snapshots to the cloud.


The Manual Foundation

Before scripting everything away, I like to run the commands manually to make sure the “plumbing” works. Now that I’ve ditched the manual namespacing, the setup is much more straightforward.

1. Initializing the Repo

We’ll just use a straightforward kb (knowledge base) directory in our hidden backups folder.

export restic_repo="$HOME/.backups/kb"mkdir -p "${restic_repo}"
restic -r "${restic_repo}" init

A note on security: When you run init, Restic will ask for a password. This password is the only way to decrypt your data. There’s no recovery flow here, so keep it somewhere safe like a password manager.

2. The First Pass

Next, we push the files. I make sure to exclude metadata folders like .git or .stfolder (from Syncthing). There’s no point in backing up my version control history inside a backup.

restic -r "${restic_repo}" backup \
    --exclude '.git' \
    --exclude '.stfolder' \
    --exclude '.stignore' \
    ~/kb

Once this finishes, you can run restic snapshots and you’ll see your hostname automatically attached to the entry. Clean and simple.


The “Set It and Forget It” Script

Manual commands are great for learning and one-off execution, but for real-world reliability, we need a script. I’ve wrapped the logic into a Bash script that handles the repo creation automatically.

#!/usr/bin/env bash
# Backup the Org-roam knowledge base
export backup_slug="kb"
export restic_repo="${HOME}/.backups/kb"

# Check if repo exists, otherwise, create it. By using this paradigm,
# I can sync this backup script across hosts and backup the same repo:
if [ ! -f  "${restic_repo}/config" ]; then
  mkdir -p "${restic_repo}"
  restic -r "${restic_repo}" init
fi

# Create the backup
restic -r "${restic_repo}" backup \
  --exclude '.git' \
  --exclude 'node_modules' \
  --exclude '.stfolder' \
  --exclude '.stignore' \
  ~/kb

What’s Next?

Right now, this is backing up to my local disk. It protects me against accidentally deleting a file or a weird filesystem corruption, but it won’t help if my laptop decides to take a coffee bath.

The next evolution of this is to hook up Rclone. Since Restic supports Rclone as a backend, I can eventually pipe these encrypted snapshots straight to Google Drive, a B2 bucket, or an S3 instance. That’ll get me to that “3-2-1” backup gold standard. But for today? My notes are safe, encrypted, and I can get back to building.


Posted

in

by

Tags: