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
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
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
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
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
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.
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.
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
- 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
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
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
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
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
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
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
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
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
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
- 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
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
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
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
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
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
- 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
The healthcheck test value contained "googlechecksum: $$Chksum"
which YAML interprets as a mapping separator (colon-space in an
unquoted scalar). This caused "mapping values are not allowed in
this context" on the command line below it.
Fixed by using >- block scalar for the healthcheck test and
multi-line array format for the postgres command, matching the
official Immich docker-compose format.
https://claude.ai/code/session_01NAtxAkC5t6YVb3gcP1VcX8
Three issues fixed:
1. SSH/VPN/Remote Desktop rerun detection: When services are already
configured, ask a single "Reconfigure?" question instead of
prompting through every individual service again.
2. Whiptail selection respected: When user selects specific services
in the whiptail menu, skip all unrelated sections (linux-to-sync,
Caddy Legacy, Kopia, local backup, cloud backup, UFW) instead of
prompting for each one.
3. Import-photos.sh reminder: Clarify that import-photos.sh should
be run AFTER the main setup script completes, not during.
https://claude.ai/code/session_01NAtxAkC5t6YVb3gcP1VcX8
- apt upgrade at end of script now prompts (default: no) instead of
running unconditionally. This prevents unwanted package upgrades
when running the script just to install a new service.
- Immich setup: ask "existing photos?" first (default: no) so fresh
installs only get one path question. Strategy choice and path prompts
now only appear when relevant to the chosen strategy.
https://claude.ai/code/session_01NAtxAkC5t6YVb3gcP1VcX8
The user should decide *what* they want (import vs external library)
before being asked *where* their photos are. The "what" frames the
context for the "where" question.
https://claude.ai/code/session_01NAtxAkC5t6YVb3gcP1VcX8
The import-photos.sh script creates the admin account via API, so
"Open browser and create admin account" is no longer needed for the
import path. Post-setup is now just:
Import path (Strategy 1 + existing photos):
"Run ~/docker/immich/import-photos.sh" — one step, no browser
External library path (Strategy 2):
Still requires web UI for library creation (3 steps)
No existing photos:
Still requires web UI for storage template (2 steps)
https://claude.ai/code/session_01NAtxAkC5t6YVb3gcP1VcX8
The import-photos.sh helper script now handles the entire setup flow
without requiring any manual web UI interaction:
1. Checks if Immich is initialized via /api/server/config
2. If uninitialized: creates admin account via /api/auth/admin-sign-up
(prompts for email, password, name)
3. If already initialized: prompts for existing credentials
4. Logs in via /api/auth/login to get bearer token
5. Creates API key via /api/api-keys automatically
6. Configures storage template via /api/system-config (PUT)
7. Installs immich-cli (checks immich → npx → npm → offers apt install)
8. Runs recursive upload with EXIF date preservation
Also accepts an API key as argument to skip account setup for re-runs.
Fixes:
- Removed -f flag from curl calls that suppressed error details
- Fixed $? check after login (now uses if ! command pattern)
- Variable naming collision (INSTALL_NODE → INSTALL_NODE_YN)
- Post-setup instructions now just say "run the import script"
instead of listing manual steps
https://claude.ai/code/session_01NAtxAkC5t6YVb3gcP1VcX8
When Strategy 1 (unified library) is chosen with existing photos, the
setup now generates an import-photos.sh script that automates the entire
import process:
- Verifies Immich is running (API health check)
- Prompts for API key with validation
- Configures the storage template via API automatically (uses python3
for JSON manipulation, falls back to manual instructions)
- Installs immich-cli via npx if Node.js available, offers to install
Node.js if not
- Runs the upload with --recursive from the baked-in source path
- Shows photo count and progress
Also:
- Ask where existing photos currently live (separate from library path)
- Use that path for both the external library mount (Strategy 2) and
the import script source (Strategy 1)
- Post-setup instructions reduced to 3 steps: create account, get API
key, run import script
- .env comments reference the import script instead of raw CLI commands
https://claude.ai/code/session_01NAtxAkC5t6YVb3gcP1VcX8
Replace the confusing two-prompt (upload/external) configuration with a
cohesive strategy-based flow:
- One question for photo library path instead of two separate prompts
- Ask if user has existing photos, then present two clear strategies:
[1] Import everything into Immich (unified library, recommended)
[2] Keep existing photos in place (external library, read-only)
- Generate strategy-specific docker-compose.yml (no unused external
mount when not needed)
- Strategy-specific .env files with relevant instructions only
- Fix nesting issue: external library uploads now go to sibling dir
instead of subfolder (prevents duplicate scan)
- Unified post-setup instructions that match chosen strategy
https://claude.ai/code/session_01NAtxAkC5t6YVb3gcP1VcX8