Commit Graph
100 Commits
Author SHA1 Message Date
Claude eab374978e tools: fbq-add-source.sh — manage compose volume mounts + config.yaml together
Previously only edited config.yaml. Now:
- Shows existing volume mounts with host→container paths
- Detects when a host path isn't mounted yet and adds it to compose
- Remove flow optionally removes the volume mount from compose too
- Show displays both compose mounts and config sources side by side
- Uses down/up (not just restart) when compose changes

https://claude.ai/code/session_014CCYqVwW6d6f5dw1qRokYt
2026-06-08 14:29:00 +00:00
Claude a1a88c2821 tools: fbq-add-source.sh — support multiple volume mounts
Previously only detected the first volume mount, so sources on a
second mount (e.g. /files2) were not reachable. Now lists all mounts
from docker-compose.yml and lets the user pick by number or type a
full container path directly.

https://claude.ai/code/session_014CCYqVwW6d6f5dw1qRokYt
2026-06-08 13:52:14 +00:00
Claude 6133721af7 tools: remove readOnly from fbq-add-source.sh — not a valid Quantum config field
Quantum's YAML parser rejects 'readOnly' under source config with
'unknown field'. Removed the prompt, the written field, and the
display column entirely.

https://claude.ai/code/session_014CCYqVwW6d6f5dw1qRokYt
2026-06-08 13:35:32 +00:00
Claude 653963da08 tools: add edit mount option to mount-network-drive.sh
Allows editing share path, mount point, and options for an existing
fstab entry. CIFS entries also offer credential update (backs up the
old credentials file before overwriting). Backs up fstab before any
change and offers immediate remount to apply.

https://claude.ai/code/session_014CCYqVwW6d6f5dw1qRokYt
2026-06-08 13:28:00 +00:00
Claude 06a163614d tools: add mount-network-drive.sh for SMB/CIFS and NFS shares
Interactive script to mount network drives and persist them in /etc/fstab:
- SMB/CIFS: prompts for share path, mount point, credentials (saved to
  /etc/samba/credentials.<name> at 600/root), SMB version
- NFS: prompts for export path, mount point, NFS version
- Tests the mount before writing fstab
- Backs up /etc/fstab before any edit
- Remove flow: unmounts, removes fstab entry, optionally removes creds file
- Shows currently mounted network shares and fstab entries
- Uses nofail + _netdev so a missing share doesn't block boot

https://claude.ai/code/session_014CCYqVwW6d6f5dw1qRokYt
2026-06-08 13:13:15 +00:00
Claude 838af715aa tools: fix fbq-add-source.sh exiting after first source with set -e
(( n++ )) returns exit code 1 when the pre-increment value is 0,
which kills the script under set -euo pipefail. Replace with
n=$(( n + 1 )) which always returns 0.

https://claude.ai/code/session_014CCYqVwW6d6f5dw1qRokYt
2026-06-08 12:43:42 +00:00
Claude 97e6fa25ed tools: change fbq-add-source.sh quit option from 4 to 0
https://claude.ai/code/session_014CCYqVwW6d6f5dw1qRokYt
2026-06-08 12:40:52 +00:00
Claude 6030c8b06d tools: fix fbq-add-source.sh failing to list sources with inline yaml comments
yq stops mid-array when it encounters inline comments like
'# grant per-user only'. Strip comments via sed before piping
to yq in list_sources, source_exists, and before in-place edits.

https://claude.ai/code/session_014CCYqVwW6d6f5dw1qRokYt
2026-06-08 12:37:57 +00:00
Claude 5af33a9ebb tools: fix null display in fbq-add-source.sh for sources without name/config
Sources added manually without a name or config block showed "null"
for name and readOnly. Use yq // operator to fall back to sensible
defaults: "(unnamed)" for missing name, false for missing booleans.

https://claude.ai/code/session_014CCYqVwW6d6f5dw1qRokYt
2026-06-08 05:32:10 +00:00
Claude 99e8671110 tools: simplify fbq-add-source.sh — config.yaml only, no compose edits
Assumes the parent data directory is already broadly mounted in
docker-compose.yml so subdirectories are already inside the container.
Script now only edits config.yaml and restarts the container — no
docker-compose surgery needed per new source.

https://claude.ai/code/session_014CCYqVwW6d6f5dw1qRokYt
2026-06-08 05:20:41 +00:00
Claude 7379f0b62f tools: add fbq-add-source.sh for FileBrowser Quantum source management
Interactive script that keeps docker-compose.yml and config.yaml in sync
when adding or removing file sources in a FileBrowser Quantum installation.

- Prompts for host path, source name, defaultEnabled, readOnly
- Validates against duplicate volume mounts and source entries
- Backs up both files before editing
- Uses yq v4 for safe YAML editing (no fragile sed/awk on YAML)
- Offers container restart after changes
- Works standalone; no post-install framework dependency

https://claude.ai/code/session_014CCYqVwW6d6f5dw1qRokYt
2026-06-08 04:59:11 +00:00
Claude 9cae430166 additional_directories.sh: fix nested bind-mount problem properly
Root cause: user scopes inside /data/... (the main data bind-mount) mean
any extra mount would nest inside another bind-mount — Docker does not
reliably layer these, so directories appeared in `ls` but were empty
and FileBrowser returned 404.

Fix: detect nested scopes and migrate them to the named volume (fb_users)
before adding any extra mounts.

Migration flow:
- Detects scope is inside /data bind-mount
- Suggests a new scope path in the named volume (e.g. /alice)
- Creates the scope directory via docker exec (no host-side clutter)
- Offers to mount the user's personal files dir as my-files/
- Updates the user's scope in FileBrowser via API PUT /api/users/:id
- Then adds requested extra dirs as non-nested bind-mounts

Also added: let user choose the display name for each added folder
(e.g. mount audiobookshelf but show it as "audiobooks").

https://claude.ai/code/session_014CCYqVwW6d6f5dw1qRokYt
2026-06-08 04:02:03 +00:00
Claude 6d0d72bef5 additional_directories.sh: create host mount-point dirs for nested mounts
When a user's FileBrowser directory lives inside an existing bind-mount
(e.g. /srv/data/users/alice), Docker needs an empty directory at the
host-side equivalent path before it can overlay an inner bind-mount on
top of the outer one.  Without it the inner mount silently fails and
the extra folder never appears.

Now creates the mount-point directory on the host automatically before
adding the compose entry, with a visible note so the user knows a dir
was created.

https://claude.ai/code/session_014CCYqVwW6d6f5dw1qRokYt
2026-06-08 03:46:21 +00:00
Claude 412560aa8f filebrowser: replace manage_users.sh with additional_directories.sh
Symlinks don't work for giving scoped FileBrowser users access to extra
folders — FileBrowser's afero.BasePathFs blocks symlinks that resolve
outside the user's scope directory.

Switch to bind-mount approach: additional_directories.sh edits
docker-compose.yml to add real bind-mount entries for each extra folder,
so FileBrowser sees them as actual subdirectories within the user's root.
No symlinks, no scope-boundary issues.

Features:
- Reads FB_PATH from .env to list available source folders on the host
- Parses docker-compose.yml to show what's already configured per user
- Adds/removes volume entries with a timestamped backup before each edit
- Prompts to restart the container after changes
- Normalises scope paths from the API (handles missing leading slash)

manage_users.sh removed — user CRUD is handled by the FileBrowser web UI.

https://claude.ai/code/session_014CCYqVwW6d6f5dw1qRokYt
2026-06-08 03:29:36 +00:00
Claude c72a20af42 manage_users.sh: strip to directory-access-only tool
Removed all user CRUD (add, delete, rename, passwd, scope change).
The FileBrowser web UI handles those. Script is now focused solely
on adding/removing extra folder shortcuts for users who have a
restricted root directory. Simpler menu, ~half the code.

https://claude.ai/code/session_014CCYqVwW6d6f5dw1qRokYt
2026-06-08 03:06:52 +00:00
Claude 2e63ca1756 caddy: document internal vs host port in Caddyfile template and README
Services on caddy_net talk container-to-container using the internal
port. The host-mapped port (left side of ports:) is only for direct
access from another machine. Added this as a comment block in the
generated Caddyfile starter and in the README.

https://claude.ai/code/session_014CCYqVwW6d6f5dw1qRokYt
2026-06-08 02:57:12 +00:00
Claude c2df116a72 manage_users.sh: don't auto-create user dir, rename scope→directory
- Remove silent mkdir -p when adding extra directories. If the user's
  directory doesn't exist in the container, ask before creating it.
  This avoids creating folders the admin didn't intend.

- Rename all user-facing "scope" text to "directory" throughout:
  prompts, banners, menu labels, column headers, help text, error
  messages. The FileBrowser API field is still called "scope"
  internally, and the CLI subcommand name stays "scope" for compat.

https://claude.ai/code/session_014CCYqVwW6d6f5dw1qRokYt
2026-06-08 02:30:53 +00:00
Claude 39c85326e6 filebrowser: named volume for user dirs, rename linked→additional dirs
docker-compose now uses two separate mounts:
  fb_users named volume → /srv      (user home dirs + shortcuts, Docker only)
  FB_PATH bind mount    → /srv/data (actual files, unchanged on host)

User dirs and their shortcuts live entirely in the Docker named volume —
they persist across reboots but never appear on the host filesystem.
Full-access scope is /data; per-user scopes are /alice etc.

manage_users.sh:
- Detect layout: get_data_root() returns /srv/data (new) or /srv (legacy)
  so the script works with both old and new installs automatically
- "Linked directories" renamed to "additional directories" throughout
  (menu labels, prompts, error messages, usage text)
- prompt_add_links → prompt_add_dirs, menu_links → menu_add_dirs
- Available-folder listing and symlink targets use get_data_root()
- Scope examples updated to show /data for full access (new layout)
- Don't offer additional directories when scope is /data (full access)

https://claude.ai/code/session_014CCYqVwW6d6f5dw1qRokYt
2026-06-08 02:23:07 +00:00
Claude 659b3924c0 fix manage_users.sh: strip fields that cause 400 on newer FileBrowser
Removed dateFormat, hideDotfiles, singleClick, and sorting from the
POST /api/users payload — FileBrowser rejects them as invalid data
types on some versions. Only stable fields are now sent.

https://claude.ai/code/session_014CCYqVwW6d6f5dw1qRokYt
2026-06-08 01:25:15 +00:00
Claude d591f38acf fix manage_users.sh: show API errors on user creation, fix symlink listing
- User creation was silently failing: api_post used curl -sf (fail on
  HTTP error) with output piped to /dev/null, so set -Eeuo pipefail
  would exit the script with no message. Now captures HTTP status code
  and response body, printing the server's error message on failure.

- Symlink folder listing (? prompt) only searched -type d, missing
  symlinked directories in /srv. Changed to -type d -o -type l so
  all browsable entries appear. Also switched xargs echo to tr for
  a cleaner one-line display.

- mkdir -p and ln -s in docker exec were not checked for errors;
  failures would silently kill the script under set -e. Both now
  show a useful error message and continue/return instead of crashing.

https://claude.ai/code/session_014CCYqVwW6d6f5dw1qRokYt
2026-06-08 01:12:43 +00:00
Claude 956c13e723 filebrowser.sh: full Caddy config in standalone stub (not just info msg)
Replace the "configure manually" stub with a real implementation that
matches common.sh's configure_caddy_for_service behaviour:
- Prompts to configure (skippable)
- Asks for domain with example hint
- Backs up Caddyfile before writing
- Checks for duplicate domain entry, offers overwrite
- Appends site block with reverse_proxy, security headers, JSON log
- fmt + reload via docker exec caddy caddy fmt/reload

Used when filebrowser.sh is run standalone without the repo present.
When the repo is present (common.sh sourced), the real function is used.

https://claude.ai/code/session_01UZus2Q9gNTfUdqSMrhuX29
2026-06-08 00:54:15 +00:00
Claude c005e01156 filebrowser.sh: fix DOCKER_DIR pointing to /root when run with sudo
DOCKER_DIR was computed before ACTUAL_HOME, so $HOME resolved to
/root (the root user's home) instead of the invoking user's home.
Files were created under /root/docker/ rather than ~/docker/.

Fix: compute ACTUAL_USER and ACTUAL_HOME first, then DOCKER_DIR.

https://claude.ai/code/session_01UZus2Q9gNTfUdqSMrhuX29
2026-06-08 00:42:13 +00:00
Claude 9641bebda8 filebrowser.sh: support standalone execution (sudo bash filebrowser.sh)
Add standalone bootstrap block at the top (BASH_SOURCE[0] == $0 guard):
- If lib/common.sh is present (repo cloned), source it — gets real helpers
  and picks up any existing ~/docker/.config site settings automatically
- If not (one-off copy), inline minimal stubs: logging, require_docker
  (checks Docker is installed, gives install hint if not), prompt_text/yn
  (match common.sh eval pattern so install_filebrowser locals work),
  configure_caddy_for_service (no-op with manual hint), write_readme
- Sets DOCKER_DIR, ACTUAL_USER, SITE_TZ etc. with sensible defaults
- register_service becomes a no-op (no wizard menu to register into)
- Execution deferred via _RUN_STANDALONE flag to after function definition

Still works identically when sourced by setup.sh — the bootstrap block
is skipped entirely in that path.

https://claude.ai/code/session_01UZus2Q9gNTfUdqSMrhuX29
2026-06-08 00:27:15 +00:00
Claude 9ab7979833 manage_users.sh: fix login silently bailing on credential entry
Three fixes in ensure_token:
- Use jq to build the login JSON so special chars in passwords
  (quotes, backslashes, etc.) don't break the raw string interpolation
- Add || true to the curl call so set -e doesn't silently exit on
  connection refused before the response check runs
- Show FileBrowser's actual response on failure so the user can see
  whether it's wrong credentials vs unreachable vs something else

https://claude.ai/code/session_01UZus2Q9gNTfUdqSMrhuX29
2026-06-08 00:06:21 +00:00
Claude ea1a9cf3b7 manage_users.sh: list folders on demand with ? instead of auto-display
Auto-displaying all top-level dirs could be a wall of text.
Typing ? at the folder prompt lists them on demand instead.

https://claude.ai/code/session_01UZus2Q9gNTfUdqSMrhuX29
2026-06-07 23:27:54 +00:00
Claude c71c08ac87 manage_users.sh: show available folders before link prompt
List top-level directories from /srv so the user knows what to type
without having to guess. Subdirs (e.g. documents/shared) still work.
Skip link prompt when scope is / (user already has full access).

https://claude.ai/code/session_01UZus2Q9gNTfUdqSMrhuX29
2026-06-07 23:22:22 +00:00
Claude c584811be4 manage_users.sh: remove /srv from all user-facing prompts
Users think in FileBrowser folder names, not container paths.

- prompt_add_links: prompt now "Folder to add [done]:" with examples
  like "music  photos  documents/shared" — /srv added internally
- list_links: strip /srv prefix from displayed target paths
- menu_links: rename options to "Add folders" / "Remove a folder"
- scope prompts: remove the leading "/" hint (confusing); normalise
  internally instead
- ok message shows "(from path/subdir)" only when link name differs

https://claude.ai/code/session_01UZus2Q9gNTfUdqSMrhuX29
2026-06-07 23:18:50 +00:00
Claude 5fdeff3f9a manage_users.sh: inline link prompts on add/scope-change
- prompt_add_links: shared helper loops asking for /srv paths until
  blank Enter, creates symlinks via docker exec, skips bad paths
- cmd_add: offers linked-dir prompt right after user creation
- cmd_scope: offers linked-dir prompt after a scope change
- menu_links: tighter submenu (list + add loop + remove) replacing
  the old menu_symlinks; called from Modify option 5
- Scope prompts now show the leading / so the user only types the rest
- Note on delete: symlinks on disk survive user deletion (by design)

https://claude.ai/code/session_01UZus2Q9gNTfUdqSMrhuX29
2026-06-07 23:15:12 +00:00
Claude b884d79dd2 manage_users.sh: add linked-directory (symlink) management
New option 5 in the Modify submenu: "Manage linked directories"

- Lists existing symlinks inside the user's scope dir (via docker exec)
- Add: prompts for source path (/srv/...) and a display name, creates
  the symlink inside /srv<scope>/<name> → /srv<source> in the container
- Remove: lists links, prompts for name, refuses to delete non-symlinks
- Warns if source path doesn't exist yet; offers to create anyway
- Auto-detects container name from docker-compose.yml next to the script
- Checks that the container is running before any docker exec calls

This is the recommended workaround for FileBrowser's single-scope
limitation: symlinks inside the scope dir appear as normal folders.

https://claude.ai/code/session_01UZus2Q9gNTfUdqSMrhuX29
2026-06-07 23:07:27 +00:00
Claude 141c9115a7 Rewrite manage_users.sh: add interactive menu, fix password nameref bug
- Interactive menu when run with no args (login once, reuse token)
- Modify submenu: change username, password, scope, or toggle admin
- Fix: prompt_password now uses local -n nameref (bash 4.3+) so the
  caller's local variable is actually set; printf -v was writing to
  global scope and being shadowed by the caller's local declaration
- One-shot commands unchanged: list/add/delete/passwd/scope/rename/info
- FileBrowser only supports one scope per user — documented clearly

https://claude.ai/code/session_01UZus2Q9gNTfUdqSMrhuX29
2026-06-07 22:52:42 +00:00
Claude 774f6ad561 Add 6 new utility services: gatus, mail-archiver, rustdesk, unifi, vaultwarden, watchyourlan
- gatus: status/uptime monitoring page with hot-reloaded config
- mail-archiver: IMAP email archive and full-text search (postgres backend)
- rustdesk: self-hosted remote desktop relay, cross-VLAN/FQDN docs
- unifi: UniFi Network Application with MongoDB init via Docker configs
- vaultwarden: Bitwarden-compatible password manager with SMTP prompts
- watchyourlan: network device tracker (host networking for ARP scanning)

All follow caddy_net container-routing pattern except rustdesk (raw TCP/UDP)
and watchyourlan (network_mode: host, incompatible with caddy_net).

README.md services table updated with all 6 new entries.

https://claude.ai/code/session_01UZus2Q9gNTfUdqSMrhuX29
2026-06-07 22:32:44 +00:00
Claude 9c52ac22e1 Fix Caddy routing: use container:port via caddy_net (DoTheEvo pattern)
Undo the host.docker.internal approach from the previous commit — proper
Docker networking routes Caddy to services by container name on the shared
caddy_net, not via the host gateway.

- lib/common.sh: configure_caddy_for_service now accepts either a plain
  port number (localhost:PORT fallback) or container:port (preferred).
  The Caddyfile entry uses the container name for direct Docker DNS routing.
- services/caddy.sh: remove extra_hosts hack; update Caddyfile template
  comments to show container_name:port format
- All service files: update configure_caddy_for_service calls to pass
  container_name:internal_port (e.g. "filebrowser:80", "mealie:9000").
  Services using network_mode:host keep plain port numbers.
- tools/manage_users.sh: new FileBrowser user-management script (deployed
  to ~/docker/filebrowser/ during installation). Manages users via the
  FileBrowser REST API: list, add, delete, passwd, scope, info commands.
  Documents username format (letters/numbers/hyphens/underscores),
  password rules (min 8 chars, letter + number required), and scope path
  convention relative to /srv (= FB_PATH on the host).

https://claude.ai/code/session_01UZus2Q9gNTfUdqSMrhuX29
2026-06-07 22:12:01 +00:00
Claude 56bec03c9b Fix Caddy routing and add caddy_net to all Docker services
- lib/common.sh: fix broken reverse_proxy target — localhost inside Caddy's
  container is the container's own loopback, not the host; change to
  host.docker.internal so proxied ports are actually reachable
- services/caddy.sh: add extra_hosts host.docker.internal:host-gateway so
  the above resolves correctly; create caddy_net bridge network in Caddy's
  own compose so other services can reference it as external; update all
  Caddyfile template comments and README examples to match
- services/filebrowser.sh: update image tag from deprecated :s6 to :latest;
  remove non-functional PUID/PGID env vars (filebrowser/filebrowser does not
  honour them); add configure_caddy_for_service call; add caddy_net
- services/ntfy.sh: add configure_caddy_for_service call; add caddy_net
- services/portainer.sh: add configure_caddy_for_service call; add caddy_net
- services/frigate-notify.sh, watchtower.sh: add caddy_net for
  container-to-container comms (frigate, ntfy) without a Caddy call
- All remaining web-facing Docker services: add caddy_net network block to
  docker-compose and CADDY_NET to .env where applicable; services using
  network_mode: host (wolf-pair, lyrion) have the top-level block only

https://claude.ai/code/session_01UZus2Q9gNTfUdqSMrhuX29
2026-06-07 22:02:26 +00:00
Claude 22aa5c6701 Add backup test scripts and enhance workers with timing, counts, and pre-flight checks
- extras/test_backup_kopia.sh: stop → restore → compare → roll back test for Kopia
- extras/test_backup_borg.sh:  stop → extract → compare → roll back test for Borg
- backup workers: add START_TS/BACKUP_COUNT/DURATION_STR to completion log and ntfy
- backup workers: pre-flight disk check warns and records failure if < 512 MB free
- services/backup.sh: install test_backup_kopia.sh + optional weekly test timer
- services/borg-backup.sh: install test_backup_borg.sh + optional weekly test timer
- ntfy notifications include service count, duration, and per-failure detail lines
2026-06-04 21:23:48 +00:00
Claude 862ecf10e9 feat: backup test script, ntfy notifications, and error categorization
extras/test_backup.sh — new unified test script (Kopia + Borg):
  • Stops container, moves live data aside, restores latest backup,
    compares restored vs live with diff -rq (content, not timestamps),
    moves live data back and restarts container
  • PASS = restore succeeded; diff output is informational (files changed
    since last backup are normal)
  • FAIL = restore command failed or target empty after restore
  • --list flag, CLI service arg, interactive picker
  • Handles both full-service dirs and sub-path sources (gaming-backup)
  • Cleanup trap always restores live data even on error
  • Sends ntfy notification on pass and fail

extras/backup_kopia.sh, backup_borg.sh, backup_gaming.sh:
  • ntfy_send() + categorize_error() helpers added
  • Each snapshot/archive failure captures stderr and categorizes:
    disk full, remote unreachable, repository not found, wrong passphrase,
    permission denied, unknown error
  • Single ntfy notification at end: success (low priority) or failure
    (urgent) with per-service failure reasons listed
  • backup_borg.sh: changed 2>&1 | pipe to 2>"$_ERR" | so stdout logs
    cleanly and stderr is captured for error categorization

services/backup.sh, borg-backup.sh, gaming-backup.sh:
  • New ntfy prompt section in installer (URL + optional token)
  • NTFY_URL / NTFY_TOKEN written to backup.conf
  • test_backup.sh copied from extras/ into service dir
  • Summary updated to show test_backup.sh commands and ntfy URL

https://claude.ai/code/session_019XgsQ13XKm4Zj3cNsDNwHj
2026-06-04 20:03:30 +00:00
Claude 925ded308f fix: install gaming-backup restore as restore_gaming.sh
Consistent with the service-name convention:
  backup_gaming.sh + restore_gaming.sh
  (source extras/restore_kopia.sh is installed under the gaming name)

https://claude.ai/code/session_019XgsQ13XKm4Zj3cNsDNwHj
2026-06-04 19:42:32 +00:00
Claude e55449442f refactor: move backup/restore worker scripts to extras/ as source files
Replace embedded heredocs in the three backup service installers with
cp from versioned source files in extras/:

  extras/backup_kopia.sh   — Kopia worker (was inline in services/backup.sh)
  extras/backup_borg.sh    — Borg worker  (was inline in services/borg-backup.sh)
  extras/backup_gaming.sh  — gaming saves worker (was inline in services/gaming-backup.sh)
  extras/restore_kopia.sh  — unified Kopia restore (multi-dest + single-dest)
  extras/restore_borg.sh   — unified Borg restore with destination picker

Each installer now does `cp extras/<script>.sh $DIR/<script>.sh` instead of
writing the script inline. Workers and restore scripts are now readable in the
repo rather than buried in heredocs.

Restore scripts are installed flat into the service directory root:
  ~/docker/backup/backup_kopia.sh   ~/docker/backup/restore_kopia.sh
  ~/docker/borg-backup/backup_borg.sh   ~/docker/borg-backup/restore_borg.sh
  ~/docker/gaming-backup/backup_gaming.sh   ~/docker/gaming-backup/restore_kopia.sh

The new restore scripts handle destination selection internally, so a single
script replaces the old per-destination restore/<dest>/ layout.

Also fixes `local` used outside a function in restore_kopia.sh and
restore_borg.sh (destination picker loop), and removes the now-superseded
extras/restore_kopia_backup.sh and extras/restore_borg_backup.sh.

https://claude.ai/code/session_019XgsQ13XKm4Zj3cNsDNwHj
2026-06-04 18:50:09 +00:00
Claude 159c6608a9 Add borg-backup service with restore script
New service: borg-backup (backup group)
- Installs borgbackup from apt
- Same coverage as Kopia backup: full ~/docker/<service>/ snapshots
- Minecraft: flush world (save-all), archive, no downtime
- All others: stop → archive → restart
- Multi-destination support with per-service routing
- SSH remote repos supported natively (user@host:/path)
- Per-service pruning: keep-daily/weekly/monthly
- repo compact after each run
- Systemd timer (with cron fallback)
- repokey-blake2 encryption; key export reminder in summary
- worker.sh: run / list / info subcommands

New restore helper: extras/restore_borg_backup.sh
- Installed to ~/docker/borg-backup/restore/<dest>/
- Interactive: lists services → pick archive → inspect (/tmp) or restore in-place
- In-place restore: stops container, moves current data aside, extracts, restarts
- Old data kept as .pre-restore-DATE with rollback instructions printed

https://claude.ai/code/session_019XgsQ13XKm4Zj3cNsDNwHj
2026-06-04 17:14:02 +00:00
Claude 9b9b0b6fd0 Restore VT share links in manual instructions
The #fragment links work fine in a browser — only curl/wget can't follow them.
Show them as clickable links for users at the terminal on the server.

https://claude.ai/code/session_019XgsQ13XKm4Zj3cNsDNwHj
2026-06-04 16:45:19 +00:00
Claude acffd6e67b Add Vanilla Tweaks auto-install from extras/datapacks/
Place datapacks_<ver>.zip or crafting_tweaks_<ver>.zip in extras/datapacks/
before running the Minecraft installer and they will be detected automatically.

- Pattern match: *datapack* → unzip into datapacks-download/; *craft* → copy as-is
- Version extracted from filename; compared against selected MC version at picker step
- Early banner notice when ZIPs are absent (where to put them and naming convention)
- If ZIPs present: show found files + version check, offer "Use pre-packaged VT?" (default y)
- Accepting skips the individual datapack picker entirely
- Manual fallback instructions updated to hint at extras/datapacks/ for next time
- Removed broken VT share# links from manual instructions
- Added extras/datapacks/README.md (naming convention + download sources)
- Added .gitignore: extras/datapacks/*.zip never committed

https://claude.ai/code/session_019XgsQ13XKm4Zj3cNsDNwHj
2026-06-04 16:40:51 +00:00
Claude 7ae5a20e0e Rename backup services: backup (comprehensive) + gaming-backup (saves-only)
- backup: renamed from disaster-backup; full ~/docker/<service>/ snapshots,
  Minecraft flushed not stopped, everything else stop/snap/start for DB
  consistency; backup.conf / restore/ layout; post-install-backup timer
- gaming-backup: renamed from backup; frequent game-save snapshots (Minecraft
  world data, emulator saves, Steam, Wolf state) with no service downtime;
  defaults to hourly schedule; separate gaming-kopia repo + gaming-backup timer
- Deleted services/disaster-backup.sh
- README: updated backup row to reflect new names

https://claude.ai/code/session_019XgsQ13XKm4Zj3cNsDNwHj
2026-06-04 15:58:15 +00:00
Claude 9aa9b00b59 disaster-backup: Minecraft flush-not-stop, update descriptions
Minecraft instances are flushed to disk (save-all) and snapshotted while
the server keeps running — no player disruption. All other services stop
briefly for filesystem-consistent database snapshots, then restart.
Also update file header, install banner, schedule description, and README.

https://claude.ai/code/session_019XgsQ13XKm4Zj3cNsDNwHj
2026-06-04 15:50:22 +00:00
Claude 55d8d09e46 Add Minecraft seed prompt and disaster-recovery backup service
- minecraft: prompt for world seed on new installs (skipped if world already exists); SEED env var wired into docker-compose.yml
- disaster-backup: new service that stops each Docker service, snapshots the full ~/docker/<service>/ directory (config + data + databases), then restarts it — multi-destination support so different services can go to different drives/repos; one restore_kopia_backup.sh per destination
- README: update backup row to list both backup and disaster-backup

https://claude.ai/code/session_019XgsQ13XKm4Zj3cNsDNwHj
2026-06-04 15:42:58 +00:00
Claude d21a7ea7fb feat: add interactive Kopia restore script, Authelia guidance in CLAUDE.md
- extras/restore_kopia_backup.sh: interactive restore tool — lists all
  snapshot sources, pick source + snapshot, choose inspect (restore to
  /tmp) or restore-in-place (moves current data aside as .pre-restore-DATE
  for easy rollback, auto-stops/starts the associated Docker service)
- services/backup.sh: copy restore script to ~/docker/backup/ during
  install; update summary to show restore command
- CLAUDE.md: add note to update README services table when adding a
  service; add Authelia section documenting which services have built-in
  auth, the import-authelia Caddy pattern for no-auth services, and
  remember_me_duration config for kiosk/persistent sessions

https://claude.ai/code/session_019XgsQ13XKm4Zj3cNsDNwHj
2026-06-04 15:07:04 +00:00
Claude 177598a79e docs: add CLAUDE.md, move backup guide into installer, drop linux-to-sync
- CLAUDE.md: full contributor guide — service template, all helpers,
  globals, DRY_RUN convention, Caddy wiring, non-Docker patterns
- services/backup.sh: print backup strategy guide (Kopia/Borg/rsync/
  rsnapshot + when to use each) at the start of install_backup()
- README.md: remove standalone backup section, fix broken backup row,
  inline base package list, add CLAUDE.md to layout
- services/linux-to-sync.sh: deleted (never worked)
- setup.sh: remove linux-to-sync from is_installed()

https://claude.ai/code/session_019XgsQ13XKm4Zj3cNsDNwHj
2026-06-04 14:29:02 +00:00
Claude 4cfef73090 docs: move base packages list into Services table, drop standalone section
https://claude.ai/code/session_019XgsQ13XKm4Zj3cNsDNwHj
2026-06-04 14:07:20 +00:00
Claude 5146412ade docs: expand README with base packages list and full backup strategy guide
Documents all packages installed by the base service, and adds a
Backup section covering Kopia, Borg, plain rsync, rsync --link-dest
(versioned snapshots with original folder structure), and rsnapshot —
with guidance on when to use each.

https://claude.ai/code/session_019XgsQ13XKm4Zj3cNsDNwHj
2026-06-04 13:51:46 +00:00
Claude 7a555987ed chore: remove old pre-modular files and internal planning docs
Keep only the two base install scripts (24.04, 26.04), the modular
system (setup.sh, lib/, services/, extras/, bootstrap.sh), and
LICENSE/README/VERSION. Everything else was superseded.

https://claude.ai/code/session_017WJtGcE5jjerAQCUBWUE3H
2026-06-04 13:30:05 +00:00
Claude e9830fef31 services/minecraft.sh: generate PREGEN_INSTRUCTIONS.md when chunky is selected
Writes radius, border status, and commands for monitoring, re-running,
and cancelling chunk pre-generation. Listed in the setup summary.

https://claude.ai/code/session_017WJtGcE5jjerAQCUBWUE3H
2026-06-04 13:19:07 +00:00
Claude f86e35aaf1 services/minecraft.sh: fix two incorrect printed instructions
- SCP example used $(whoami) which evaluates to root; use $ACTUAL_USER instead
- VT_VERSION stripped to major.minor (e.g. 1.21) so the picker version
  prompt is correct; previous awk printed the full patch string (1.21.4)

https://claude.ai/code/session_017WJtGcE5jjerAQCUBWUE3H
2026-06-04 12:56:16 +00:00
Claude 5138d6fca7 services/minecraft.sh: remove stale manual-run comment from pregen-startup.sh
Pregen runs automatically when starting the server; the "run manually"
comment inside the script was misleading.

https://claude.ai/code/session_017WJtGcE5jjerAQCUBWUE3H
2026-06-04 02:30:09 +00:00
Claude ae7b887b22 services/minecraft.sh: sync world border default and VT header from latest standalone
- World border default changed from y to n (border is opt-in)
- VT share links header updated with pack counts (22 datapacks, 10 crafting tweaks)

https://claude.ai/code/session_017WJtGcE5jjerAQCUBWUE3H
2026-06-04 02:27:36 +00:00
Claude f5e3fea71c README: spell out how to get repo onto USB (extract + drag)
Step 1 was vague. Now explicit: download ZIP, right-click Extract Here,
drag the folder onto the USB in the file manager sidebar.

https://claude.ai/code/session_017WJtGcE5jjerAQCUBWUE3H
2026-06-04 02:14:41 +00:00
Claude 9968776813 README: USB install — open folder in file manager, no path needed
When you open the USB folder in the file manager, you're already there.
Right-click → Open in Terminal → sudo bash bootstrap.sh, or double-click
bootstrap.sh → Run in Terminal → sudo prompt. No /media/whoami/DRIVENAME
path hunting required.

https://claude.ai/code/session_017WJtGcE5jjerAQCUBWUE3H
2026-06-04 02:09:53 +00:00
Claude d2c57b5fc6 README: simplify USB install — download ZIP, not git clone
The real workflow is: GitHub Code → Download ZIP → unzip → copy to USB.
No git, no auth, no file manager tricks. On the target machine: ls to find
the drive name, then sudo bash /media/$(whoami)/DRIVENAME/...bootstrap.sh.

https://claude.ai/code/session_017WJtGcE5jjerAQCUBWUE3H
2026-06-04 02:06:18 +00:00
Claude e168d6256c bootstrap.sh self-elevates with sudo; USB install docs rewritten
bootstrap.sh: add self-elevation — if not root, re-exec under sudo.
Double-clicking the script in GNOME ("Run in Terminal") now prompts for
the sudo password automatically, no extra commands needed.

README: rewrite USB section around the real workflow:
  - clone with "Open in Terminal" from the file manager sidebar
  - Option A: right-click folder → Open in Terminal → sudo ./setup.sh
  - Option B: double-click bootstrap.sh → "Run in Terminal?" → sudo prompt
  - note on nautilus-extension-gnome-terminal and exFAT vs ext4

https://claude.ai/code/session_017WJtGcE5jjerAQCUBWUE3H
2026-06-04 02:00:58 +00:00
Claude 1ac550d81e Remove Run Setup.desktop launcher and its README mention
https://claude.ai/code/session_017WJtGcE5jjerAQCUBWUE3H
2026-06-04 01:54:54 +00:00
Claude 8d7fb2df43 Add USB thumb drive install docs and double-click launcher
README: rewrite USB section with three steps:
  1. Auto-detect USB mount point and clone repo onto it
  2. Install nautilus-extension-gnome-terminal for right-click "Open in Terminal"
  3. Double-click "Run Setup.desktop" to launch wizard with sudo (no terminal needed)

Run Setup.desktop: launcher file included in the repo so it's present on the
USB automatically. Uses %k to find its own location, cds to that directory,
and runs sudo ./setup.sh in a terminal window.

https://claude.ai/code/session_017WJtGcE5jjerAQCUBWUE3H
2026-06-04 01:54:33 +00:00
Claude 3c3e9dd6da README: replace Docker-data USB section with thumb drive installer docs
The USB section was documenting the wrong thing. Replace with instructions
for carrying the repo on a USB stick and running setup.sh directly from it
on any fresh Ubuntu machine — no internet required for the repo.

Covers: cloning/copying to USB, finding the mount point on the target
machine, running setup from USB, exFAT vs ext4 trade-offs, fixing
permissions after copy.

https://claude.ai/code/session_017WJtGcE5jjerAQCUBWUE3H
2026-06-04 01:51:12 +00:00
Claude 8aa1d4552d Auto-install Docker, add USB drive docs, improve whitelist UI
- lib/common.sh: require_docker now installs Docker CE + Compose plugin
  via get.docker.com instead of erroring out if Docker is missing.
  Also adds the calling user to the docker group automatically.

- README.md: fix 'tells you how to install Docker' → 'installs Docker
  automatically'; add full USB drive usage section (mount, fstab,
  DOCKER_DIR config, moving existing data, tips).

- services/minecraft.sh: replace single-source whitelist import with the
  multi-source UI from the updated setup-minecraft.sh — collects players
  from the current instance, saved backup files, and other servers' backups;
  assigns letters to each source so you can import by letter (all from that
  source) or by number (specific player).

https://claude.ai/code/session_017WJtGcE5jjerAQCUBWUE3H
2026-06-04 01:37:58 +00:00
Claude 8ffebe9a5a bootstrap: self-elevate sudo; document double-click workflow
Added exec sudo bash self-elevation so bootstrap.sh works correctly when
double-clicked ("Run in Terminal") without the user needing to prefix sudo.
If already root, the check is a no-op.

Removed bootstrap.desktop — too fragile across desktop environments.
README now covers both "Open in Terminal" and double-click paths.

https://claude.ai/code/session_01Y4dMKtkqkpvmgDKoRdzhTG
2026-06-04 01:14:54 +00:00
Claude 39280d71cb README: document USB prep via GitHub ZIP download
The previous USB instructions assumed git was available. Added step-by-step
for the no-git path: GitHub ZIP download → unzip → copy to USB → run
bootstrap.sh. Includes the Ubuntu auto-mount path tip for finding the
drive name. Folder name note (ubuntu-post-install-main from ZIP) added.

https://claude.ai/code/session_01Y4dMKtkqkpvmgDKoRdzhTG
2026-06-04 01:08:42 +00:00
Claude 9773dcfb63 bootstrap: support USB/local-copy and private repo PAT
Three usage modes now documented and implemented:

1. Public repo: curl | sudo bash (unchanged)
2. Private repo, USB: copy whole repo to thumb drive, run bootstrap.sh
   from it — detects setup.sh alongside itself, copies to ~/ubuntu-post-install,
   execs setup.sh. No git auth, no internet needed for the scripts.
3. Private repo, PAT: bootstrap.sh --pat ghp_xxx — PAT stripped from
   stored remote URL after clone so it is not saved in plain text.

USB mode is the recommended approach for private repos: clone once,
put on a drive, run on every new machine.

https://claude.ai/code/session_01Y4dMKtkqkpvmgDKoRdzhTG
2026-06-04 01:00:57 +00:00
Claude 33f052ea0b Add bootstrap.sh and rewrite README for modular system
bootstrap.sh: one curl | sudo bash to get and run on a fresh box —
installs git if missing, clones/updates the repo, execs setup.sh.

README.md: complete rewrite. The old README described the monolithic
script (--restore, --migrate flags, Samba, NetBird, etc.) which no
longer exists. New README covers quick start, usage modes, service
table, layout, and managing installed services.

https://claude.ai/code/session_01Y4dMKtkqkpvmgDKoRdzhTG
2026-06-04 00:26:09 +00:00
Claude 2ab0008338 Bump NodeSource from Node 22 to Node 24 LTS
Both silent-send and immich already use NodeSource (not Ubuntu repos).
Node 24 is the current active LTS; 22 moves to maintenance in 2025.
Minimum version checks (>=18 and >=20) are unchanged — both services
accept any sufficiently recent Node.

https://claude.ai/code/session_01Y4dMKtkqkpvmgDKoRdzhTG
2026-06-04 00:22:07 +00:00
Claude 92e8866f13 pip_user_install: capability probe instead of version check
Probe for --break-system-packages support once (pip --help, cached in
_PIP_HAS_BSP) rather than comparing Ubuntu version numbers. Works on any
pip >= 22.3 regardless of distro; older pip (Ubuntu 22.04, pip 22.0)
falls back to --user only, which is correct there since PEP 668 isn't
enforced on 22.04 anyway.

The flag name is scary but harmless with --user: installs go to ~/.local/
which apt never manages regardless.

https://claude.ai/code/session_01Y4dMKtkqkpvmgDKoRdzhTG
2026-06-04 00:05:36 +00:00
Claude e8667f02cf pip_user_install: add --break-system-packages on Ubuntu 24.04+
pip3 install --user alone does not reliably bypass PEP 668 in all 24.04
environments. --break-system-packages (pip 22.3+) is the correct override.
Flag is only added when ubuntu_version_ge "24.04" so it does not run on
Ubuntu 22.04 where pip 22.0 ships and the flag is not yet supported.

https://claude.ai/code/session_01Y4dMKtkqkpvmgDKoRdzhTG
2026-06-04 00:01:57 +00:00
Claude ef08fef540 Add OS detection; surface version in header; centralise pip installs
lib/common.sh:
  - detect_os(): reads /etc/os-release into OS_DISTRO, OS_VERSION,
    OS_CODENAME globals (exported, auto-called on source)
  - ubuntu_version_ge(): numeric version comparison helper
  - pip_user_install(): central wrapper for pip3 install --user so any
    future version-specific flags are in one place

setup.sh:
  - Both header banners now show detected OS line (e.g., "Ubuntu 24.04 (noble)")
  - First-run path warns if not Ubuntu or < 24.04

services/sky-cam.sh, services/sync-cc.sh:
  - Replace inline pip3 invocations with pip_user_install helper

https://claude.ai/code/session_01Y4dMKtkqkpvmgDKoRdzhTG
2026-06-03 23:49:51 +00:00
Claude 370c513606 Skip required-packages step on re-run
On second run, is_installed base (command -v ncdu) detects that base
packages are already present and jumps straight to the service menu,
skipping the required-setup banner, confirm prompt, and apt-get install.
The first-run path is unchanged; `sudo ./setup.sh base` forces reinstall.

https://claude.ai/code/session_01Y4dMKtkqkpvmgDKoRdzhTG
2026-06-03 23:48:15 +00:00
Claude 56d2f9e85b Add site-wide defaults: timezone, domain, Caddy network
Introduces a one-time configuration wizard (sudo ./setup.sh configure)
that stores SITE_TZ, SITE_DOMAIN, and SITE_CADDY_NET in ~/docker/.config.
Every service now uses these as prompt defaults so the user types common
values once instead of re-answering the same questions for each service.

- lib/common.sh: load_site_config / save_site_config; auto-loads on source;
  backward-compat BASE_DOMAIN alias kept for old .config files
- setup.sh: run_site_configure wizard; first-run offer after base install;
  `sudo ./setup.sh configure` command to update defaults at any time
- 14 services: TZ_VAL now honours SITE_TZ, falling back to /etc/timezone
- 3 inline-heredoc services (filebrowser, homeassistant, ntfy): same fix
- authelia: SITE_TZ/SITE_DOMAIN as prompt defaults; SITE_CADDY_NET replaces
  hardcoded caddy_net throughout (env, compose patch, network creation)
- minecraft, frigate-audio: simplify BASE_DOMAIN read to use SITE_DOMAIN
- sky-cam: SITE_TZ as default for timezone prompt

https://claude.ai/code/session_01Y4dMKtkqkpvmgDKoRdzhTG
2026-06-03 22:13:59 +00:00
Claude cfad0ebd20 fix(linux-to-sync): run git clone as actual user, handle re-run, show errors
Three bugs fixed:
1. git clone ran as root — SSH key lookup failed because user's keys are in
   ~user/.ssh/, not /root/.ssh/. Both SSH and PAT clones now run via
   sudo -u ACTUAL_USER so git uses the right key and the clone is owned
   correctly without a separate chown step.
2. 2>/dev/null on git clone swallowed all error output — errors are now
   shown so authentication failures are diagnosable.
3. No re-run handling — trying to clone into an existing dir silently
   failed. Now detects .git, offers git pull instead.
Also: checks for SSH key existence before attempting SSH clone, and prints
actionable guidance (ssh-keygen, ssh-add, ssh -T git@github.com) on failure.

https://claude.ai/code/session_01Y4dMKtkqkpvmgDKoRdzhTG
2026-06-03 21:41:54 +00:00
Claude c3bb2cf18c feat(cameras): add sky-cam and frigate-audio service modules
sky-cam (cameras/non-docker):
  Clones outis1one/sky-cam via bootstrap.sh to ~/sky-cam. Prompts for
  latitude, longitude, timezone, camera names, BASE_DIR, and optional
  Mattermost webhook. Patches sky-cam.conf and installs systemd user
  timers via the repo's install.sh. Produces sunrise clips, Four Seasons
  timelapse, moon-track, and monthly moon-phase images.

frigate-audio (cameras/docker):
  Full stack from outis1one/frigate_w_audio: Frigate 0.17 NVR +
  Mosquitto MQTT broker + frigate-notify → ntfy push alerts. Audio-ready
  config template with face recognition and LPR pre-configured. Prompts
  for camera credentials, media storage path (supports drive detection),
  MQTT password (auto-generated), and ntfy server. Bootstraps the
  Mosquitto passwd file. Detector choice: CPU / USB Coral / PCIe Coral.
  Hardcoded media path from upstream replaced with a configurable prompt.

https://claude.ai/code/session_01Y4dMKtkqkpvmgDKoRdzhTG
2026-06-03 21:40:49 +00:00
Claude 1d4b38674d feat(extras): add sync-cc service — Whisper/ffsubsync subtitle tool
Adds sync_cc as an extras service module:
- extras/sync_cc.py: the Python tool (3196 lines) — 8 modes: SYNC,
  GENERATE, BATCH, RENAME (TMDB), EXTRACT, REMUX, EMBED, BURNSUBS
- services/sync-cc.sh: installs system deps (python3, ffmpeg, mkvtoolnix,
  ccextractor), pip installs openai-whisper + ffsubsync, copies the script
  to ~/sync-cc/, prompts for TMDB API key → .env, creates /usr/local/bin/sync-cc
  wrapper so users run it from any directory containing video/SRT files

Heavy optional deps (easyocr, pgsreader) are installed on first use by the
script itself. GPU (CUDA/MPS) is used automatically if detected.

https://claude.ai/code/session_01Y4dMKtkqkpvmgDKoRdzhTG
2026-06-03 21:36:22 +00:00
Claude a63f72ef17 feat(minecraft): port whitelist import + VT share links + pause from standalone
Three improvements ported from the standalone setupminecraft.sh:
- Whitelist: detect existing whitelist.json on re-run, offer to import
  players by number (0=all, comma list, Enter=skip), no UUID re-lookup
  for already-resolved entries; new gamertags still looked up via Mojang API
- Vanilla Tweaks: add vanillatweaks.net pre-configured share links at the
  top of the download instructions section (datapacks + crafting tweaks)
- Vanilla Tweaks: pause with "Press Enter when datapacks are in
  datapacks-download/" so user can SCP the ZIP before the build starts

https://claude.ai/code/session_01Y4dMKtkqkpvmgDKoRdzhTG
2026-06-03 21:32:39 +00:00
Claude cd59549e39 chore: add versioned snapshot setup_v0.9.5.sh, reset VERSION to 0.9.5
Introduces the versioned-snapshot naming convention: each release creates
a new setup_v<X.Y.Z>.sh file alongside the live setup.sh; old snapshots
are never removed. Resets VERSION from 1.0.0 to 0.9.5.

https://claude.ai/code/session_01Y4dMKtkqkpvmgDKoRdzhTG
2026-06-03 19:24:23 +00:00
Claude d5941f2b26 feat: parity milestone — add linux-to-sync, mark v1.0.0
Every service from ubuntu-post-install-24.04-crowdsec.sh is now a module.
35 services across 8 categories; setup.sh is the primary install path.

- services/linux-to-sync.sh (extras): clone private repo via SSH or PAT
- setup.sh: is_installed case for linux-to-sync (~/.git marker)
- MODULAR.md: migration table updated to show full inventory
- VERSION: 0.9.11 → 1.0.0 (parity achieved)

https://claude.ai/code/session_01Y4dMKtkqkpvmgDKoRdzhTG
2026-06-03 18:33:04 +00:00
Claude 2210dd4bed feat: add utilities + cameras batches (v0.9.11)
Utilities (8 modules):
- mealie: recipe manager, port 9925
- actualbudget: personal finance, port 5006
- traccar: GPS tracking, ports 8082 + 5000-5150 device protocols
- fmd: Android FindMyDevice server, random admin password, port 8084
- ddclient: dynamic DNS, config template, default start=n
- wg-easy: WireGuard VPN+UI, auto-detects public IP, random password
- meshcentral: remote device management, hostname prompt, ports 4430+4433
- magicmirror: smart mirror, 1-3 instances, MMM-* module auto-clone

Cameras (2 modules):
- frigate: AI NVR, auto-enables /dev/dri, starter config.yml, default start=n
- frigate-notify: Frigate push alerts, auto-detects local Frigate+ntfy, no web UI

https://claude.ai/code/session_01Y4dMKtkqkpvmgDKoRdzhTG
2026-06-03 18:30:58 +00:00
Claude a36f058a51 feat(media): add 6 media service modules (v0.9.10)
Migrate the full media batch from the monolith:

- jellyfin: auto-VAAPI on /dev/dri/renderD128 + render GID; DLNA/discovery UDP ports
- emby: UID/GID baked at install; HW transcoding block commented for manual opt-in
- audiobookshelf: separate audiobooks + podcasts paths; port 13378
- arm: optical drive detection; privileged:true; split movies/music output; port 8080
- lyrion: network_mode:host for Chromecast/Squeezebox UDP discovery; port 9000
- immich: multi-container stack (server+ML+valkey+postgres); two library strategies
  (unified with import-photos.sh helper, or external read-only); port 2283

https://claude.ai/code/session_01Y4dMKtkqkpvmgDKoRdzhTG
2026-06-03 18:24:02 +00:00
Claude 527808d610 feat(extras): add silent-send module + new extras category
Adds services/silent-send.sh — installs the Silent Send browser extension
(client-side PII redaction for AI chat). Non-docker module: installs git +
Node.js >=18 (NodeSource) + npm, clones outis1one/silent-send to ~/silent-send,
runs npm install (readies web-ext for Firefox build/sign), optionally builds a
signed Firefox .xpi, and prints per-browser load/build instructions. README
written to the checkout.

Introduces a new 'extras' category for non-docker add-ons pulled from other
repos, wired into setup.sh CATEGORY_ORDER (gaming -> extras -> backup) with an
is_installed marker. MODULAR.md groups list updated.

Bumps version to 0.9.9.
2026-06-03 18:11:07 +00:00
Claude d9b19b5f56 feat(gaming): add wolf-pair module — browser PIN form for Moonlight pairing
Adds services/wolf-pair.sh (gaming group, port 8090). Builds a tiny
python:3.12-alpine container from server.py + Dockerfile (both baked
into the script) that reads Wolf's docker logs for the current pairing
secret and serves a PIN entry form. Runs with network_mode: host so
localhost:47989 (Wolf's /pin/ API) is reachable; docker socket mounted
read-only for log access.

Replaces the ./manage.sh pin CLI workflow: visit the URL, type the PIN.
Optional Caddy subdomain, UFW port 8090, README in ~/docker/wolf-pair/.

Bumps version to 0.9.8.
2026-06-03 17:52:19 +00:00
Claude b619733a61 Add HANDOFF.md — migration status, taxonomy, wolf-pair open item
Status snapshot at v0.9.7 for continuing in a new session: module status by
category, final taxonomy, the module contract/conventions, verification steps,
and the open wolf-pair item (awaiting server.py + Dockerfile upload).

https://claude.ai/code/session_017eA2qqq9jfF2tNtpUYL8vK
2026-06-03 17:35:50 +00:00
Claude 9dc8c4063d v0.9.7: Caddy + CrowdSec modules; category menu with required-gate
- services/caddy.sh (homelab): reverse proxy + auto HTTPS, own ~/docker/caddy
  folder (compose + starter Caddyfile + README).
- services/crowdsec.sh (homelab): system-level IPS (agent + firewall bouncer +
  Caddy acquisition + optional ntfy alerts), README in ~/docker/crowdsec.
- setup.sh guided flow redesign:
  * Prints REQUIRED set (essentials + glow + docker check) with a cancel option.
  * Offers Caddy first (most services proxy through it).
  * Category menu LOOP: pick category -> checklist ([installed] marked) ->
    install -> back to menu, until Done. whiptail + text fallback.
- Categories reorganized: base/homelab/utilities/media/cameras/gaming/backup;
  moved ntfy/filebrowser/portainer/uptimekuma/watchtower to utilities;
  caddy->crowdsec->authelia ordered first in homelab.

Verified: bash -n all; --list groups by category with caddy first; cancel path
prints 'Cancelled, nothing changed'; dry-run guided flow runs required + loops
menu; run-one still works.

https://claude.ai/code/session_017eA2qqq9jfF2tNtpUYL8vK
2026-06-03 17:16:32 +00:00
Claude 4a37b3622d v0.9.6: README generation + migrate authelia + 5 services
- lib/common.sh: add write_readme helper. Every module now writes a README.md
  into its ~/docker/<service>/ folder (self-documenting service folders).
- services/authelia.sh: SSO + 2FA portal, ported from the authelia-setup repo +
  the monolith's working block (secrets + Argon2 hash generation, caddy_net,
  Caddyfile forward-auth snippet + portal block, README). Guards against
  clobbering an existing install.
- services/{filebrowser,ntfy,uptimekuma,portainer,watchtower}.sh: mechanical
  migrations from the monolith, each with a README. Ports 8085/8090/3001/9443/—.

All pass bash -n; ./setup.sh --list shows them under homelab; dry-run run-one
exits 0 for each with real commands guarded.

https://claude.ai/code/session_017eA2qqq9jfF2tNtpUYL8vK
2026-06-03 17:01:14 +00:00
Claude d4109839fc v0.9.5: port Minecraft to a per-service-folder module
services/minecraft.sh — full port of the standalone setupminecraft.sh into the
modular system. Each instance is its own ~/docker/<name>/ with a standalone
compose (multi-server via port auto-bump). Preserves flavour choice, the live
Modrinth version/mod picker, Vanilla Tweaks datapacks, whitelist UUID
pre-population, LuckPerms bootstrap, Chunky pre-gen, playit.gg tunnel, generated
networking/client docs, and the client-mods web page. Fixes the original's
env-block trailing-newline YAML bug. Selkies/manage.sh/setup-backup hand-offs
removed (points at 'sudo ./setup.sh backup').

Verified: bash -n; ./setup.sh --list shows minecraft under GAMING; dry-run
exits 0 with early return; generated compose validates.

https://claude.ai/code/session_017eA2qqq9jfF2tNtpUYL8vK
2026-06-03 16:42:45 +00:00
Claude 840566e3f8 v0.9.4: gaming modules (wolf, js99er), backup module, versioning
- services/wolf.sh (gaming): Games-on-Whales Wolf / Moonlight, per-service
  folder ~/docker/wolf, wolf-pair dropped, manage.sh pin workflow kept.
- services/js99er.sh (gaming): TI-99/4A emulator, own folder, port 8099,
  Selkies launcher tie-in removed.
- services/backup.sh: Kopia encrypted backups, paths adapted to ~/docker.
- Start versioning: VERSION (0.9.4), CHANGELOG.md, setup.sh --version flag.

All modules pass bash -n; ./setup.sh --list groups base/homelab/gaming/backup;
dry-run run-one exits 0 for every module with real commands guarded.

Note: minecraft module deferred to 0.9.5 (port hit a session limit).

https://claude.ai/code/session_017eA2qqq9jfF2tNtpUYL8vK
2026-06-03 16:25:25 +00:00
Claude d7b9f935c2 Add modular setup framework (lib + services + dispatcher) and glow
Introduce the modular post-install structure chosen for reconciling 'one
source of truth' with 'run just the service I want':

- lib/common.sh: shared helpers (logging, prompts, ownership, Caddy wiring) and
  a service registry. Single implementation of each helper.
- setup.sh: dispatcher — interactive menu, run-one (./setup.sh <name>), --list,
  --dry-run, --unattended. Sources lib + services/*.sh (self-registering).
- services/base.sh: essential CLI packages incl. glow (Charm apt repo).
- services/homeassistant.sh: first migrated service (bridge/host networking,
  trusted_proxies, Caddy integration).
- MODULAR.md: architecture, how to add a module, migration status.
- Groups: base/homelab/gaming/backup. Gaming group makes this a base for
  homelab OR gaming boxes.

Also add glow as a default app to the live -crowdsec scripts' essential
packages so it's installed today regardless of entry point.

Verified: bash -n on all new files; ./setup.sh --list groups services;
dry-run run-one routes correctly.

https://claude.ai/code/session_017eA2qqq9jfF2tNtpUYL8vK
2026-06-03 12:57:12 +00:00
Claude d528cfbea3 Home Assistant: prompt for bridge vs host networking
Let the user choose Home Assistant's networking mode at install time in the
-crowdsec variants:
- Bridge (default): publishes port 8123, works behind Caddy, isolated.
- Host: shares the host network for LAN device auto-discovery (Cast, HomeKit,
  mDNS/Zeroconf, some Zigbee/Z-Wave/Bluetooth).

The compose file is generated conditionally; both modes verified to produce
valid YAML, and both scripts pass 'bash -n' and a --dry-run --unattended pass.

https://claude.ai/code/session_017eA2qqq9jfF2tNtpUYL8vK
2026-06-03 12:25:15 +00:00
Claude 8f6523a47b Add Home Assistant to CrowdSec variants
Add Home Assistant (home-automation hub, port 8123) to the -crowdsec scripts
for 24.04 and 26.04, following the existing service pattern (menu entry,
detection, defaults, parse, uninstall, install block, UFW rule, Caddy template).

- Image ghcr.io/home-assistant/home-assistant:stable, config volume, privileged
  + /run/dbus for hardware integrations; documents host-networking alternative
  for full mDNS/device discovery.
- Pre-seeds config/configuration.yaml with default_config + http.trusted_proxies
  (only on a fresh install) so HA works behind the Caddy reverse proxy without
  the usual 400 'request from reverse proxy' error.
- Integrates with configure_caddy_for_service (subdomain 'home').

Added only to the -crowdsec tier (current tip); original and -no-keycloak
scripts stay frozen as the evolution record. Both variants pass 'bash -n' and a
--dry-run --unattended pass (exit 0), including with Home Assistant forced on.

https://claude.ai/code/session_017eA2qqq9jfF2tNtpUYL8vK
2026-06-03 12:20:36 +00:00
Claude b6af49f1f1 Add optional ntfy ban alerts to CrowdSec variants
When configuring CrowdSec, optionally wire up an ntfy push notification via
CrowdSec's HTTP notification plugin: writes /etc/crowdsec/notifications/ntfy.yaml
and references it from the default profile in profiles.yaml. Alerts fire on a
ban decision (after repeated failed attempts), not on every failed login.

Document the behavior in SCRIPT-VARIANTS.md, including why Authelia (email-only)
doesn't cover failed-login push. Both crowdsec variants verified with 'bash -n'
and a --dry-run --unattended pass (exit 0).

https://claude.ai/code/session_017eA2qqq9jfF2tNtpUYL8vK
2026-06-03 12:05:13 +00:00
Claude 7cf82d5d28 Add no-keycloak and CrowdSec script variants; restore originals
Provide three tiers of the install script for both 24.04 and 26.04:

- Originals (ubuntu-post-install-24.04.sh / -26.04.sh): restored to their
  true original state, with Keycloak intact, as a fallback baseline. (This
  reverts the in-place Keycloak removal from the previous commit; the cleanup
  now lives in the -no-keycloak variants instead.)
- -no-keycloak.sh: Keycloak fully removed, Authelia as the SSO/2FA option.
- -crowdsec.sh: builds on -no-keycloak and replaces fail2ban entirely with
  CrowdSec (SSH via auth.log/sshd collection, Caddy via caddy collection + log
  acquisition, firewall bouncer for enforcement, plus geo-blocking and
  community IP-reputation blocklists).

Add SCRIPT-VARIANTS.md documenting the three tiers and how the Authelia /
fail2ban / CrowdSec security layers differ.

All variants pass 'bash -n'.

https://claude.ai/code/session_017eA2qqq9jfF2tNtpUYL8vK
2026-06-03 11:34:43 +00:00
Claude f564b4b6d8 Remove Keycloak; standardize on Authelia for SSO
Keycloak never reliably ran (fiddly reverse-proxy/hostname config) and the
repo has standardized on Authelia for SSO + 2FA. This rips Keycloak out
entirely:

- Delete the install block, whiptail menu entry, uninstall plumbing, and
  EXISTING_SERVICES detection from both 24.04 and 26.04 scripts
- Delete docker-compose-keycloak.yml, fix-keycloak-proxy.sh, and
  KEYCLOAK-SETUP-GUIDE.md
- Remove the Keycloak block from caddy-setup-helper.sh
- Update docs (CADDY-FAIL2BAN-SETUP.md, SECURITY-IMPROVEMENTS.md,
  NEW-SCRIPT-STRUCTURE.md, SCRIPT-FLOW-INTRO.txt) to reference Authelia

Also documents the fail2ban/Authelia overlap: Authelia handles failed-login
regulation (per-account lockout); the Caddy fail2ban jail is complementary
firewall-level IP banning. Neither does geo-blocking — noted CrowdSec / Caddy
GeoIP as the path for that.

https://claude.ai/code/session_017eA2qqq9jfF2tNtpUYL8vK
2026-06-03 03:44:26 +00:00
Claude a8dd0d78dd Install Caddy before Authelia so Caddyfile exists at Authelia setup time
Authelia's installer auto-injects the (authelia) snippet and auth portal
block into the Caddyfile. Moving Caddy first means that injection works
in a single fresh install run without manual follow-up.

https://claude.ai/code/session_01FvqXSZyk3g7rUombwLcprZ
2026-06-02 18:44:15 +00:00
Claude 49f91ac9c0 Fix Authelia authentication_backend config for 4.38+ format
The working authelia-setup repo uses the Authelia 4.38+ password
hashing config format with a nested argon2 block and variant key.
The previous version used the old flat format which is rejected by
Authelia 4.39.20 validation. Fix both 24.04 and 26.04 scripts.

  Before (broken):
    password:
      algorithm: argon2id
      iterations: 3
      ...

  After (correct for 4.38+):
    password:
      algorithm: argon2
      argon2:
        variant: argon2id
        iterations: 3
        ...

https://claude.ai/code/session_01FvqXSZyk3g7rUombwLcprZ
2026-06-02 17:56:39 +00:00
Claude 9e353eb921 Sync 24.04 and 26.04 scripts: rename, Authelia, NetBird SSH
- Rename ubuntu-post-install.sh → ubuntu-post-install-24.04.sh to match 26.04 naming convention
- Add --allow-server-ssh systemd override to 24.04 NetBird install (already in 26.04)
- Add full Authelia install block to 26.04 (matching what was added to 24.04)
  - Whiptail menu, uninstall, detection, default vars, parse flags, install block
- Both scripts now identical in Authelia and NetBird SSH behavior

https://claude.ai/code/session_01FvqXSZyk3g7rUombwLcprZ
2026-06-02 17:52:25 +00:00
Claude db8e83447a Add working Authelia SSO install based on authelia-setup repo
Ports the full working configuration from outis1one/authelia-setup:
- Authelia 4.39.20 on caddy_net with secrets via env var files
- Generates jwt/session/storage secrets with openssl at install time
- Prompts for domain, admin user, SMTP settings, timezone
- Generates argon2id password hash via Docker during install
- Writes configuration.yml, users.yml, docker-compose.yml, .env
- Auto-injects (authelia) snippet + auth portal block into Caddyfile
- Creates caddy_net Docker network if missing
- Adds Authelia to whiptail service menu, uninstall list, and detection
- Adds Authelia snippet as commented example in new Caddyfile template

https://claude.ai/code/session_01FvqXSZyk3g7rUombwLcprZ
2026-06-02 17:43:35 +00:00
Claude d790d09295 Persist --allow-server-ssh in netbird systemd override
Without --allow-server-ssh, NetBird prompts for re-authentication on
every SSH connection. This adds a systemd drop-in override at
/etc/systemd/system/netbird.service.d/ssh-server.conf so the flag
is set automatically on every boot without manual intervention.

https://claude.ai/code/session_017jFG5YuHf2CCGS5HiheoeM
2026-06-01 21:51:34 +00:00
Claude afb5d22d2e Update NetBird SSH for v0.60.0+ breaking change in 26.04 script
NetBird v0.60.0 removed the built-in SSH server ('netbird ssh <peer-name>').
SSH now routes through standard openssh-server via a drop-in config at
/etc/ssh/sshd_config.d/99-netbird.conf on port 22022.

- Ensure openssh-server is installed and enabled when NetBird is selected
- Remove all 'netbird ssh <peer-name>' references
- Update instructions: connect via 'ssh user@<netbird-ip>' using netbird status
- Note the dashboard step: Peers > [peer] > SSH to enable per-peer SSH access
- Applied across install section, SSH summary, and next-steps section

https://claude.ai/code/session_017jFG5YuHf2CCGS5HiheoeM
2026-06-01 21:49:06 +00:00
Claude 8a276337ab Add ubuntu-post-install-26.04.sh for Ubuntu 26.04 LTS (Resolute Raccoon)
Based on the 24.04 script with the following updates:
- Updated all version references from 24.04 to 26.04
- Fixed Tailscale APT repo from hardcoded 'jammy' to 'resolute' codename
  (was a latent bug even on 24.04; jammy is 22.04)
- All other repos (Docker, Kopia, NodeSource) already use dynamic
  VERSION_CODENAME detection and work as-is on 26.04

https://claude.ai/code/session_017jFG5YuHf2CCGS5HiheoeM
2026-06-01 20:43:24 +00:00
Claude 947d9597e6 Require Node.js >= 20 for Immich CLI; install Node 22 LTS from NodeSource
The Immich CLI uses the File global class which requires Node.js v20+.
The script previously fell back to apt install nodejs which gives v18 on
Ubuntu and fails with "ReferenceError: File is not defined".

Now checks the Node.js major version first. If < 20, offers to install
Node.js 22 LTS from NodeSource before proceeding.

https://claude.ai/code/session_01NAtxAkC5t6YVb3gcP1VcX8
2026-02-19 07:15:51 +00:00
Claude d3d887a548 Fix Immich docker-compose: update DB image, create marker dirs, remove broken healthcheck
- Update database image from deprecated tensorchord/pgvecto-rs:pg14-v0.2.0
  to ghcr.io/immich-app/postgres:14-vectorchord0.4.3-pgvectors0.2.0
- Remove database command block (vectors.so) that blocks VectorChord from
  loading — the new image handles shared_preload_libraries internally
- Remove bogus healthcheck using non-existent googlechecksum function
- Create required subdirectories (thumbs, upload, backups, library, profile,
  encoded-video) with .immich marker files before first start — fixes
  ENOENT crash on encoded-video/.immich
- Update Valkey from 8-bookworm to 9-bookworm
- Fix status output: show UPLOAD_LOCATION instead of unset PHOTOS_DIR
  for external library strategy

https://claude.ai/code/session_01NAtxAkC5t6YVb3gcP1VcX8
2026-02-19 06:56:48 +00:00