Commit Graph
45 Commits
Author SHA1 Message Date
Julien LutranandClaude Opus 5 58dcaa5d41 nas: new storage host on A1SAi-2750F — 4 TB off USB onto SATA
Builds the box that ends the usb4t dropouts: the JMicron bridge was the
least reliable device in the setup and it held the intended off-site copy
of ks4. The 4 TB now sits on direct SATA as pool `tank`.

- OS on mdraid RAID1 across two 120 GB SSDs (Intel 330 + Toshiba Q300),
  both ESPs bootable; `incus` ZFS mirror on their tails, ~22% left
  unallocated as over-provisioning
- media at /export/media, exported read-only over NFSv4 to nuc
- transmission-bt moves here (its WireGuard tunnel is in-container, so
  ks4 needed no change) and writes to the dataset locally
- backup pools nucbackup / ks4backup / nasbackup
- monitoring live: msmtp (submission+auth, verified 250), zed with
  NOTIFY_DATA, zpool-health.sh every 15 min, smartd on all three disks

Traps recorded because none of them point at their own cause: booting
with the display active kills the i915 probe and wedges incus; d-i picks
grub-pc vs grub-efi from how the installer booted; `incus storage create`
hangs forever on a mountpoint=none dataset; the BMC is deliberately never
cabled, so there is no out-of-band console.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-30 23:53:30 +02:00
Julien LutranandClaude Fable 5 a2003a11e8 nuc: autosuspend/UAS ruled out — both already disabled, drop happened anyway
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-30 01:04:04 +02:00
Julien LutranandClaude Fable 5 058833470b nuc: second dropout rules out the cable; add the pool-health watchdog
Aug 29 16:22 the enclosure dropped again despite the new cable, pool
suspended, and ZED sent nothing (suspended pools keep the vdev ONLINE;
data-class events were muted). Enclosure replacement is now the prime
candidate and a gate before the pool hosts the ks4 off-site leg.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-30 00:33:29 +02:00
Julien LutranandClaude Fable 5 4856010cb5 backup-strategy: note the measured nightly cost
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-29 05:10:15 +02:00
Julien LutranandClaude Fable 5 f9cf92772e docs: record the measured steady-state nightly (1.24 TiB walked in 1m43s)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-29 05:10:01 +02:00
Julien LutranandClaude Fable 5 7e9cd7fdde ks4/README: document the user.os inventory column
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-28 19:44:18 +02:00
Julien LutranandClaude Fable 5 5f827638d6 nuc: scrub clean — 0B repaired, no known data errors, no dropouts
The metadata/file errors were artefacts of the interrupted writes, not
corruption. The 2.5h scrub doubled as a soak test of the new cable.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-28 19:19:24 +02:00
Julien LutranandClaude Fable 5 db7b63a143 docs: restore drill passed — S3 leg gate closed
18/18 instances replicated, restic seed complete and restore-tested
(tree identical to live; dump loads into a scratch MariaDB, 12/12
tables). Remaining ks2 gates are the nuc leg after FTTH.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-28 19:16:02 +02:00
Julien LutranandClaude Fable 5 0481f162ee restic-backup: §7 becomes a scripted, repeatable restore drill
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-28 18:42:58 +02:00
Julien LutranandClaude Fable 5 6ab143c856 nuc: note why its mail path differs from ks2/ks4 (source address, not config)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-28 17:44:03 +02:00
Julien LutranandClaude Fable 5 6461bf7081 nuc: alerting works — zed -> mail -> msmtp -> submission(587)
Records the working chain and the two dead ends: port 25 gets the mail
rspamd-rejected (dynamic home IP, no SPF alignment), and the missing
PTR delays the 587 greeting enough that short-timeout probes look like
a firewall block. Credentials live only in /etc/msmtprc (600).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-28 17:16:55 +02:00
Julien LutranandClaude Fable 5 5ceb2ab742 nuc: document the usb4t dropout incident, recovery and alerting fix
Nightly replication had been failing since Aug 17 behind a misleading
incus error; root cause is a JMicron USB bridge dropping off the bus
(61 disconnects in 30 days) and suspending the pool — the disk itself
is SMART-clean. Records the recovery (clear/scrub), the damage, the
ordered fixes, and why nothing alerted: zed was running without an MTA
on the host.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-28 16:49:27 +02:00
Julien LutranandClaude Fable 5 d7ec780747 doc: plakar out of the current architecture, kept as reference
backup-strategy.md now leads with the three target legs (local incus
push to sdb, nuc pull over WireGuard, restic to S3 for DBs and
selected trees) and carries the plakar/ks2 story in a closing History
section. restic-backup.md, install.md, local-backup-cron.md and the
ks2 docs describe the predecessor only as 'the first S3
implementation', with one operational note that plakar is still
installed for issue #2338 reproduction.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-28 16:20:20 +02:00
Julien LutranandClaude Fable 5 b5aef914f5 doc: instance leg to S3 shelved; ks2 push is the interim off-site leg
Decided 2026-08-28: instances are protected by replication (sdb now,
nuc after FTTH, ks2 push in between), their data/DBs/configs by
restic-data — a third copy of instance filesystems in S3 was not
worth the moving parts. backup-strategy.md now explains the
replication-vs-backup split and the rebuild path when no replica
survives; restic-backup.md §6 is marked SHELVED (script and empty
repo kept).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-28 16:17:11 +02:00
Julien LutranandClaude Fable 5 7d5d1d9b6b ks4/README: note the incus exec sudo grant
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-28 16:04:34 +02:00
Julien LutranandClaude Fable 5 a0e3a7dd86 doc: split per-host READMEs, gitea cross-repo links, consistency pass
- nuc/README.md and ks4/README.md carry the host sections (+ network
  flows) that lived in the top-level README; links rebased
- top README: repo links (doc/scripts on git.lutran.fr), index points
  at the new per-host pages
- cross-repo references now use https://git.lutran.fr/julien/scripts
  instead of relative ../scripts paths that resolve nowhere
- plakar-s3-data.md and plakar-incus-integration.md marked SUPERSEDED
  / RETIRED with pointers to restic-backup.md; their measurements and
  rationale kept
- install.md, local-backup-cron.md, incus-copy.md: crontab sections
  updated to the live schedule (01:00 replicas, 05:00 restic, Sun
  maintenance); retired legs labelled as such
- restic-backup.md: status live, cutover recorded, post-GC memory
  estimate, seed plan dated
- seafile-gc.md: online GC noted, stale 'crons commented out' removed
- ks2/: what-ks2-does-today rewritten (nothing writes to it any more),
  legs table and gates reflect restic, decommission steps updated
- db-exclude replaces the plakar-era config name (script keeps a
  fallback)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-28 16:04:07 +02:00
Julien Lutran 80f0219716 Refactor README.md 2026-08-28 15:56:44 +02:00
Julien LutranandClaude Fable 5 c18c8edc5b doc: add backup-strategy.md and new-container.md for non-specialist readers
backup-strategy.md: the two-tool architecture (incus copy + restic),
ASCII map of the legs (ks4 sdb / nuc pull / two S3 buckets), the
schedule table, a 30-second health check, and restore recipes for a
file, a database and a whole instance.

new-container.md: conventions for adding a service — one container
per service, no Docker (incus runs OCI natively, incus-compose for
stacks), gateway/proxy ingress, leave the snapshot schedule alone,
what the backups pick up automatically vs the one line to add to
restic-paths, DB-discovery requirements (incl. the .my.cnf trap), a
verification run, and the pitfalls (tmpfs /tmp, tiny-file swarms,
cron PATH).

README: start-here links, ks4 durability bullet and flow chart
updated to the restic era.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-28 15:37:19 +02:00
Julien LutranandClaude Fable 5 33b2a87d8f seafile-gc closure (515,842 inodes final); restic-backup: cron PATH gotcha
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-28 12:53:12 +02:00
Julien LutranandClaude Fable 5 26ae55163e seafile-gc: online-GC verified, recurring cron design, -r purge results (-277G total)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-27 16:54:50 +02:00
Julien LutranandClaude Fable 5 f6d488c1e9 seafile-gc: results — 24.9M->5.6M inodes, blocks -235G, 21h33 rm-fs
Documents library identified as commit-storm source (19M fs objects,
~4.9M commits for 2.9G of data); its commit store survives GC and is
retired by recreating the library after fixing the offending client.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-27 15:22:17 +02:00
Julien LutranandClaude Fable 5 6ebc93db2e seafile-gc: diagnose never-run GC (24.9M inodes) and the reclamation procedure
GC never ran in the server's life: 13 ghost libraries, unlimited
history on 16/17 repos, 867G blocks vs 710G live data, and an
fs/commits object swarm that makes per-file backup walks take days.
Procedure: pre-GC zfs snapshot, keep_days=90 default, offline
seaf-gc (+ --rm-deleted, --rm-fs), measure, quarterly GC schedule,
then re-decide the S3 backup mechanism and the 13.x upgrade.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-26 16:37:05 +02:00
Julien LutranandClaude Fable 5 a551aed157 restic-backup: generic exclude file name
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-25 13:07:41 +02:00
Julien LutranandClaude Fable 5 3de6d01b58 restic-backup: install upstream 0.19.1 (Debian's 0.18.0 misses needed fixes)
Live-tree mid-walk deletion crash (0.18.1 #5421), faster index
loading (0.19.0 #5713) and lower check memory (#5610), index repair
robustness, clean exit codes, and the empty-snapshot-on-inaccessible-
source fix (0.19.1 #5667). Upgrades via restic self-update.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-25 12:58:48 +02:00
Julien LutranandClaude Fable 5 de72120105 restic-backup: two-bucket layout (restic-data + restic-incus), two drivers
Giants merged into restic-data (single nightly invocation, one index
load, --group-by host retention); instances leg gets per-instance
mountpoints — restic picks parents by host+path, a shared mountpoint
would cause nightly full re-reads.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-25 12:50:07 +02:00
Julien LutranandClaude Fable 5 f7843f9e37 plan: S3 legs migrate to restic; interim ks2 replica push until FTTH
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-25 12:45:18 +02:00
Julien LutranandClaude Fable 5 fb410259c5 restic-backup: restic becomes THE S3 tool — full rewrite
Four buckets (data/nextcloud/seafile/instances), instances leg via
incus file mount (no plugin architecture in restic/rustic — mount the
source instead of forking the tool), nightly driver spec, parallel
plakar comparison week, plakar retirement plan (kloset kept for
PlakarKorp/plakar#2338 debugging), interim ks2 replica push until the
FTTH/nuc leg.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-25 12:44:48 +02:00
Julien LutranandClaude Fable 5 3dec0c0a7b restic-backup: note rustic as format-compatible escape hatch (lock-free prune, lower RAM)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-25 12:17:23 +02:00
Julien LutranandClaude Fable 5 3381fe62bf restic-backup: prune tuning (--max-unused 10%, --max-repack-size 4G) with churn-based rationale
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-25 12:14:50 +02:00
Julien LutranandClaude Fable 5 93450a6fed restic-backup: appdata lives under nextcloud/data/, fix exclude paths
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-25 12:12:39 +02:00
Julien LutranandClaude Fable 5 d5dd6933af restic-backup: dry-run exclude verification, tmpfs-cache rejection, arc_min initramfs + headroom caveat
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-25 12:08:22 +02:00
Julien LutranandClaude Fable 5 dcc5c87cf1 Draft restic-backup: giant fs trees to S3, option analysis, migration gate
pack-size 64 MiB (object count vs prune amplification), split repos
for index RAM, cache on /backup, read-concurrency vs the seek-bound
walk, nextcloud preview excludes, ARC floor before seeding, weekly
rotating read-data-subset verification, and the analysis of a full
plakar->restic migration (conclusion: the split is a reasonable end
state, gated on PlakarKorp/plakar#2338).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-25 11:55:38 +02:00
Julien LutranandClaude Fable 5 1325f8b7a5 plakar-s3-data: growth issue filed upstream as PlakarKorp/plakar#2338
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-25 09:29:28 +02:00
Julien LutranandClaude Fable 5 7967b61920 plakar-incus-integration: analyze the giant-instance seek-bound wall
Per-file access to cold, tiny-file trees on HDD is ~275 IOPS whatever
the importer; only zfs send reads sequentially. Options recorded,
direction: per-file for the 16 small instances, zfs send for
nextcloud/seafile.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-24 22:23:09 +02:00
Julien LutranandClaude Fable 5 6c392356e8 plakar-s3-data: leg live; restore tests must target /backup, not tmpfs
- status: S3 kloset seeded, restore-tested, nightly cron installed
- restore-test paths moved off /tmp — it is a 16G tmpfs on ks4 and the
  10 GiB dumps restore sat in RAM squeezing the ZFS ARC
- seafile-fs note rewritten: cause unknown, local-kloset bisect next;
  nextcloud 3-4h/night cost tracked for the upstream growth issue

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-24 17:04:40 +02:00
Julien LutranandClaude Fable 5 ae82d9f682 plakar-s3-data: seed done except seafile-fs (EINTR livelock, excluded)
Seafile's block store wedged the fs walker for 12h in an lstat
preemption/EINTR livelock on the live pool; coverage moves to the
incus leg reading the sdb replica. Restore test + cron are the
remaining steps of the data leg.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-24 00:07:01 +02:00
Julien LutranandClaude Fable 5 4b73d77803 plakar-incus-integration: chain the S3 instance leg after incus-copy
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-23 09:29:01 +02:00
Julien LutranandClaude Fable 5 7da9c7cdae plakar-incus-integration: record Route B upstreaming decision
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-23 09:05:01 +02:00
Julien LutranandClaude Fable 5 79ad1b7179 Document the ks2 decommission plan and the new ks4 backup legs
- ks2/: decommission plan with release gates (rental ends Sep 30),
  nuc-seed and final-decommission runbooks
- ks4/local-backup-cron.md: leg-1 cron re-enabled, ks2 rsync stopgap,
  full-resend caveat when refreshes lapse past snapshots.expiry
- ks4/plakar-s3-data.md: plakar direct-to-S3 leg (auto-discovered DB
  dumps incl. grants/globals, fs sources, exclude list, restore test)
- ks4/plakar-incus-integration.md: design + scaffold status of the
  plakar incus importer
- README.md: index ks2/, update the ks4 durability bullet

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-23 08:56:28 +02:00
Julien LutranandClaude Opus 4.8 4b30b43c7f nuc/transmission-bt: document the watch folder for auto-adding torrents
scp a .torrent into /srv/media/.watchdir and Transmission auto-downloads
it. Documents the settings (watch-dir-force-generic + trash-original),
the correct active config path (--config-dir .../info), and the perms.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-17 17:38:43 +02:00
Julien LutranandClaude Opus 4.8 447570c267 Remove pihole from instances table (deleted, superseded by blocky)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-17 14:08:04 +02:00
Julien LutranandClaude Opus 4.8 19bad64105 nuc: document LAN gateway migration 192.168.0.1 -> 192.168.0.2
Update host NIC/interfaces (gw + DNS to public 1.1.1.1/9.9.9.9, no
container dependency), fix transmission-bt kill-switch routes, and add a
note that DHCP instances self-heal while static ones (privoxy,
transmission-bt) must be updated by hand. Also spell out the macvlan
test-from-inside/external-host rule.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-17 11:07:16 +02:00
Julien LutranandClaude Opus 4.8 43ef0e5447 nuc/jellyfin-client: document host-side input hotplug auto-recovery
Add udev rule + oneshot service + script on nuc that restart the
container kiosk when the Logitech Unifying receiver is replugged, since
hotplug uevents don't cross into the container's netns and cage only
enumerates input at startup.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-08-11 01:39:27 +02:00
Julien LutranandClaude Fable 5 61e3606d33 Set Europe/Paris timezone in all nuc containers
Applied live to the 5 running containers; install scripts and the
post-install checklist now include the timedatectl step.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-11 00:52:05 +02:00
Julien LutranandClaude Fable 5 ee9eaee889 Initial import: nuc and ks4 infrastructure documentation
README with instance tables and nuc<->ks4 network flow chart;
per-container install/troubleshooting docs for nuc (jellyfin
server/client, transmission-bt, bare-metal reinstall) and the
ks4 two-leg backup scheme (incus-copy over wireguard).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-08-09 22:50:07 +02:00