Add section headers and explanatory comments to clarify the purpose of each configuration block, with emphasis on the critical persistent path requirement for early boot secret decryption.
Fixes DNS resolution failures when persistent timers trigger backups
after system wake.
The NixOS borgbackup module adds network-online.target dependencies
to the timer when persistentTimer=true, but systemd timers don't pass
their dependencies to the services they trigger. This caused onsite
backups to start before the network was ready, resulting in "Could not
resolve hostname" errors.
Adding after/wants network-online.target directly to the service
ensures the backup waits for network availability regardless of how
it's triggered (timer or offsite's Wants= dependency).
Example failure (Oct 11, 07:43):
- Backup started at 07:43:43 (persistent timer caught up)
- DNS lookup failed: "Could not resolve hostname viridian.home.arpa"
- WiFi connected at 07:43:47 (4 seconds too late)
Applied to both fuchsia and viridian onsite backups.
Fixes multiple issues with borgbackup service coordination:
1. Race condition between onsite/offsite backups
- Set Type=oneshot to ensure services wait for completion
- Added Wants= dependency to trigger onsite when offsite runs
- Prevents snapshot path collision at /btrfs-subvolumes
2. Network unavailability after sleep/wake
- Added persistentTimer=true to onsite backups
- NixOS module now auto-adds network-online.target dependencies
- Fixes DNS resolution failures for SSH repos
3. Data loss risk from missed backups
- Persistent timers ensure backups run on wake if missed
- Protects work done before sleep from being unbackored
4. Duplicate onsite runs at midnight
- Removed 15-minute stagger (00:15 -> 00:00)
- Systemd deduplicates services in same transaction
- Onsite now runs once, not twice
Applied to both fuchsia and viridian for consistency.
Update backup paths to use actual persistent storage locations (/persist/*) rather than bind-mounted paths, making it clear where data truly resides and simplifying restore operations.
Changes staging directories from hidden to visible and aligns backup paths with actual BTRFS subvolume naming conventions for better clarity when browsing archives.
Adds persistentTimer=true to both fuchsia and viridian offsite backup configurations to ensure backups run on next boot if the system was asleep at the scheduled time. Without this, daily backups would be skipped entirely until the next scheduled run.
Fixes backup system authentication and hostname resolution issues.
Changes:
- Change PermitRootLogin from "no" to "prohibit-password" in global SSH config
(allows key-based root login for host-to-host backups while blocking passwords)
- Update fuchsia onsite backup to use viridian.home.arpa FQDN instead of shortname
- Update SSH knownHosts to use FQDNs (fuchsia.home.arpa, viridian.home.arpa)
(system-level config uses FQDNs, user shortcuts remain in home-manager)
This enables the complete 3-2-1 backup strategy with automated backups working
correctly between fuchsia and viridian, and fuchsia to BorgBase.
Restructures SSH trust relationships from global to host-specific configuration
for better locality of concern and principle of least privilege.
Changes:
- Collapse nixos/common/global/ssh/ back to ssh.nix (single-file module)
- Move internal host trust (fuchsia/viridian) to per-host services/ssh/
- Split BorgBase known hosts by repository (li9kg944 for fuchsia, r7ag7x1w for viridian)
- Add viridian SSH server config to accept backup connections from fuchsia
- Add fuchsia borgbackup passphrase for offsite backups
- Configure viridian to create /srv/borg-repo/fuchsia for remote backups
This enables the 3-2-1 backup strategy with fuchsia backing up to both viridian
(onsite) and BorgBase (offsite) with proper SSH authentication.
Add critical system state from persist.nix to borgbackup jobs:
- SSH host keys (required for borg authentication)
- machine-id and nixos state
- Network and bluetooth configurations
Paths mirror persist.nix configuration for maintainability.
Service-specific persist data (traefik, crowdsec) excluded -
will create dedicated subvolumes if/when needed.
Add automated snapshot and backup system with three independent tiers:
Snapper (hourly local snapshots):
- Configure snapper for all srv-* subvolumes
- Tiered retention: 24 hourly, 7 daily, 4 weekly, 12 monthly
- Snapshots stored at /.snapshots on viridian drive
- Provides fast operational rollback for user errors
Borgbackup onsite (hourly local backups):
- Independent staging snapshots at /.staging-onsite
- Repository on data drive at /srv/borg-repo
- Unencrypted (physical security assumed)
- Matches snapper retention policy
- Fast local disaster recovery
Borgbackup offsite (daily remote backups):
- Independent staging snapshots at /.staging-offsite
- Encrypted backups to borgbase repository
- Retention: 7 daily, 4 weekly, 12 monthly
- Remote disaster recovery with prune policy
Architecture decisions:
- Separate staging directories prevent job conflicts
- Staging snapshots decouple borg jobs from snapper
- Consistent zstd,9 compression across both borg jobs
- Special case handling for containers subvolume path
Migrate from path-based persistence (/persist/var/lib/*) to dedicated
BTRFS subvolumes for better data isolation and snapshot capabilities.
- Move valuable user-facing services to /srv/* with srv-* subvolumes:
- forgejo: git repositories and database
- opengist: paste data
- minecraft: game world data
- lighttpd: static web content
- containers: OCI container volumes
- Update home directory to use hm-sajenim subvolume on viridian disk
- Remove jupyterhub service (no longer in use)
- Update borgbackup paths to match new service locations
- Follow upstream service defaults where possible for maintainability
Services kept on /persist (disposable state):
- traefik, crowdsec, murmur
Restructured systemPackages list with alphabetically sorted categories to improve
maintainability and reduce vertical space. Added descriptive comments for all
environment configuration sections.
Add comprehensive inline documentation to both NixOS and Home Manager
global configuration files, explaining the purpose of each section,
overlay usage, unfree package policy, and configuration settings.
Remove PageUp/PageDown pane rotation keybinds that don't align with wezterm workflow. The static pane layout approach (fixed splits + zoom toggle) doesn't benefit from rotation like dynamic window managers do.
Also update CLAUDE.md to clarify that Home Manager is a NixOS module, so just build/switch commands handle both system and user configurations together.
Replace manual GitHub fetchFromGitHub with packaged versions of zsh plugins and consolidate plugin loading through the plugins list instead of manual sourcing.
Implements spatial "master pane" focusing that mirrors XMonad's master
window concept. Alt+Delete now focuses the largest pane in the current
tab, completing the unified Delete key semantic across all tools:
- Gui+Delete (XMonad): Focus master window (largest in layout)
- Alt+Delete (WezTerm): Focus master pane (largest, ties to lowest index)
- Delete (Neovim): Center cursor view
The implementation is spatially-aware rather than content-aware,
maintaining the navigation layer's positional abstraction. When panes
are equal-sized, the lowest-indexed pane is chosen for predictability.
Implemented key tables to create clean, organized namespaces for tab and
pane management. This refactoring improves keybinding discoverability and
reduces cognitive load by grouping related operations.
Key changes:
- LEADER + t enters tab mode (n/q/r for new/quit/rename)
- LEADER + p enters pane mode (s/v/q/m for split/vsplit/quit/maximize)
- LEADER + Escape enters copy mode (vim-like pseudo-normal mode)
- CTRL + SHIFT + v for paste (standard terminal convention)
- Removed smart-splits plugin in favor of simpler native navigation
- Navigation keys remain at top level for quick access
Add sequential pane navigation and rotation to match XMonad's window
management pattern. This creates consistent muscle memory across both
the window manager and terminal multiplexer.
Changes:
- Add Alt+PageUp/PageDown for sequential pane focus (mirrors XMonad's window cycling)
- Add Alt+Ctrl+PageUp/PageDown for pane rotation (mirrors XMonad's rotAll)
- Change Leader+Tab to Leader+t for new tab (free up 't' was for zoom, now 'm')
- Change zoom from Leader+t to Leader+m (matches XMonad's maximize mnemonic)
Keybinding philosophy:
- Base keys (Alt+PageUp/Down) = navigation/viewing
- Ctrl modifier = structural control (resize/rotate)
- Consistent with XMonad: Mod+PageUp/Down (focus), Mod+Ctrl+PageUp/Down (rotate)
Replace dynamic pane management with explicit keybindings for better
discoverability. Add dmenu-based tab renaming and direct tab navigation
by index for improved workflow efficiency.
Move all allowUnfreePredicate declarations to global configs to prevent
the "last definition wins" merging issue. Unfree packages are now managed
in two central locations:
- NixOS system packages: nixos/common/global/default.nix
- Home Manager packages: home-manager/sajenim/global/default.nix
- Remove ollama service configuration and dependencies
- Clean up traefik routing for ollama web interface
- Comment out traefik service examples for clarity
- Add CLAUDE.md with comprehensive repository documentation
- Configure claude-code package in editors feature
- Add MCP nixos integration for better Nix ecosystem support
- Include Claude settings with co-authored-by disabled
- Update unfree predicate for proprietary AI tools