lib/common.sh: configure_caddy_for_service now pre-fills the domain prompt
with $DEFAULT_SUBDOMAIN.$SITE_DOMAIN when a site domain has been configured
(setup.sh configure / ~/docker/.config). No more typing the full domain for
every service — just press Enter to accept the default.
services/mattermost.sh: remove redundant custom Caddy/domain block added in
the previous commit. MATTERMOST_SITE_URL is already computed from SITE_DOMAIN
before configure_caddy_for_service is called, so the simple call is sufficient.
https://claude.ai/code/session_014CCYqVwW6d6f5dw1qRokYt
Mattermost Calls:
- Add 8443/udp to compose ports for the Calls plugin RTC server (WebRTC
direct path; coturn relay is only the fallback, not the sole path)
- Add 8443/udp to UFW rules and router port-forward table
- Warn that WebRTC requires HTTPS — calls silently fail over HTTP
- Prompt for Caddy domain and update MATTERMOST_SITE_URL in .env to match
the HTTPS URL before Caddy is wired (previously SITEURL was written before
the domain was known, leaving it as http://localhost:8065)
- Update README with RTC server address field and corrected port table
Asterisk web admin:
- No built-in auth: add Authelia SSO check matching CLAUDE.md pattern
- Set WEB_ADMIN_AUTH_DISABLED=true in .env when Authelia handles auth
(prevents double-login prompts)
https://claude.ai/code/session_014CCYqVwW6d6f5dw1qRokYt
- Replace symlink with real cp for easy-asterisk-v0.10.0.sh: Docker COPY
doesn't reliably follow symlinks; using a real copy is safer.
- Add ./easy-asterisk.sh:/usr/local/bin/easy-asterisk:ro bind mount so the
management script can be updated without rebuilding the image.
- Add TURN_SERVER to .env (empty in LAN-only mode, domain:3478 in FQDN mode)
and reference it in compose instead of building the value inline — fixes
malformed "":3478 in LAN-only mode.
- Add provisioning ports 8088/8089 to UFW rules; these are Asterisk's built-in
HTTP server for Linphone XML provisioning (not the web admin, not Caddy).
- Document in README that Caddy has no role in calls: SIP/RTP use host
networking. Caddy only proxies the web admin (8080). Provisioning ports
(8088/8089) must be accessed directly, not through Caddy.
https://claude.ai/code/session_014CCYqVwW6d6f5dw1qRokYt
vendor/easy-asterisk/: All source files from outis1one/easy-asterisk v0.10.0
vendored so the repo is self-contained — no internet required at install time.
Includes the real Dockerfile (FROM ubuntu:24.04 + full Asterisk stack),
entrypoint.sh (IP detection, TLS cert gen, pjsip/rtp config, web admin),
coturn-entrypoint.sh (robust IP detection wrapper), and the management
script + diagnostic utilities.
services/asterisk.sh: Rewritten to copy from vendor/ instead of downloading
at runtime. Uses the upstream Dockerfile verbatim. Symlinks
easy-asterisk-v0.10.0.sh → easy-asterisk.sh for build context compatibility.
services/onlyoffice.sh: Complete rewrite with correct standalone bootstrap.
_ensure_yq() installs yq v4 automatically (arch-aware). JWT secret is
preserved across re-runs so rotating is explicit. _wire_nextcloud() and
_wire_filebrowser() run on every install invocation (idempotent), skipping
gracefully when containers aren't running rather than failing.
https://claude.ai/code/session_014CCYqVwW6d6f5dw1qRokYt
Nextcloud: custom Dockerfile (nextcloud:apache + smbclient) for SMB external
storage support without AIO. All data uses bind mounts so Kopia/Borg coverage
is automatic. Enables files_external app after first boot.
OnlyOffice: JWT-secured document server wired to Nextcloud via occ commands
and FileBrowser Quantum config.yaml if both are installed. Port 8082.
Mattermost: Team Edition + PostgreSQL + dedicated coturn on port 3479 (does
not conflict with Easy Asterisk's coturn on 3478). Bind mounts throughout.
UFW rules and router port-forward instructions printed at install time.
https://claude.ai/code/session_014CCYqVwW6d6f5dw1qRokYt
Integrates https://github.com/outis1one/easy-asterisk into the post-install
system. Downloads the management script and coturn entrypoint at install time,
generates docker-compose.yml with host-networking Asterisk + coturn, writes
a randomised TURN password, and opens UFW ports for SIP/RTP/TURN.
Interactive FQDN setup chooses between LAN-only (UDP, no TLS) and FQDN mode
(TLS+SRTP+TURN) and prints required router port-forward instructions.
https://claude.ai/code/session_014CCYqVwW6d6f5dw1qRokYt
Apt-based service for Android/iPhone ↔ Linux integration: shared
clipboard, notifications, file transfer, remote input. Works on Ubuntu
(GNOME) and Linux Mint Cinnamon. Opens UFW ports 1714-1764 automatically.
https://claude.ai/code/session_014CCYqVwW6d6f5dw1qRokYt
Docker-based Syncthing with PUID/PGID ownership, caddy_net integration,
and standalone bootstrap support. Exposes web UI on 8384 and sync
protocol on 22000 (tcp+udp) and discovery on 21027/udp.
https://claude.ai/code/session_014CCYqVwW6d6f5dw1qRokYt
Each service can now be run directly with sudo bash <service>.sh on any
machine with Docker installed, without needing the full post-install repo.
Uses the shared bootstrap pattern from docs/standalone-template.sh.
All 42 applicable service files now support standalone execution.
https://claude.ai/code/session_014CCYqVwW6d6f5dw1qRokYt
Each service can now be run directly with sudo bash <service>.sh on any
machine with Docker installed, without needing the full post-install repo.
Uses the shared bootstrap pattern from docs/standalone-template.sh.
https://claude.ai/code/session_014CCYqVwW6d6f5dw1qRokYt
Each service can now be run directly with sudo bash <service>.sh on any
machine with Docker installed, without needing the full post-install repo.
Uses the shared bootstrap pattern from docs/standalone-template.sh.
https://claude.ai/code/session_014CCYqVwW6d6f5dw1qRokYt
Each service can now be run directly with sudo bash <service>.sh on any
machine with Docker installed, without needing the full post-install repo.
Uses the shared bootstrap pattern from docs/standalone-template.sh.
https://claude.ai/code/session_014CCYqVwW6d6f5dw1qRokYt
Each service can now be run directly with sudo bash <service>.sh on any
machine with Docker installed, without needing the full post-install repo.
Uses the shared bootstrap pattern from docs/standalone-template.sh.
https://claude.ai/code/session_014CCYqVwW6d6f5dw1qRokYt
Each service can now be run directly with sudo bash <service>.sh on any
machine with Docker installed, without needing the full post-install repo.
Uses the shared bootstrap pattern from docs/standalone-template.sh.
https://claude.ai/code/session_014CCYqVwW6d6f5dw1qRokYt
Each service can now be run directly with sudo bash <service>.sh on any
machine with Docker installed, without needing the full post-install repo.
Uses the shared bootstrap pattern from docs/standalone-template.sh.
All 42 applicable service files now support standalone execution.
https://claude.ai/code/session_014CCYqVwW6d6f5dw1qRokYt
Each service can now be run directly with sudo bash <service>.sh on any
machine with Docker installed, without needing the full post-install repo.
Uses the shared bootstrap pattern from docs/standalone-template.sh.
https://claude.ai/code/session_014CCYqVwW6d6f5dw1qRokYt
Each service can now be run directly with sudo bash <service>.sh on any
machine with Docker installed, without needing the full post-install repo.
Uses the shared bootstrap pattern from docs/standalone-template.sh.
https://claude.ai/code/session_014CCYqVwW6d6f5dw1qRokYt
Each service can now be run directly with sudo bash <service>.sh on any
machine with Docker installed, without needing the full post-install repo.
Uses the shared bootstrap pattern from docs/standalone-template.sh.
https://claude.ai/code/session_014CCYqVwW6d6f5dw1qRokYt
Each service can now be run directly with sudo bash <service>.sh on any
machine with Docker installed, without needing the full post-install repo.
Uses the shared bootstrap pattern from docs/standalone-template.sh.
https://claude.ai/code/session_014CCYqVwW6d6f5dw1qRokYt
Each service can now be run directly with sudo bash <service>.sh on any
machine with Docker installed, without needing the full post-install repo.
Uses the shared bootstrap pattern from docs/standalone-template.sh.
https://claude.ai/code/session_014CCYqVwW6d6f5dw1qRokYt
Each service can now be run directly with sudo bash <service>.sh on any
machine with Docker installed, without needing the full post-install repo.
Uses the shared bootstrap pattern from docs/standalone-template.sh.
https://claude.ai/code/session_014CCYqVwW6d6f5dw1qRokYt
- Swaps image from filebrowser/filebrowser to gtstef/filebrowser:stable
- Uses ./data:/home/filebrowser/data volume layout (Quantum convention)
- Generates data/config.yaml instead of settings.json + database.db
- Mounts primary path as /files with defaultEnabled: true
- Deploys fbq-add-source.sh for adding extra directories post-install
- Updates README with Quantum-specific instructions
docs: save standalone bootstrap as docs/standalone-template.sh
Preserves the full standalone pattern from filebrowser.sh as the
reference template for adding standalone support to other services.
https://claude.ai/code/session_014CCYqVwW6d6f5dw1qRokYt
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
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
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
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
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
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
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
- 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
- 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: timing (duration), service count, and pre-flight disk check (< 512 MB warns)
- backup workers: ntfy notifications include count, duration, and per-failure detail
- 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
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
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
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
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
- 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
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
- 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
- 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
- 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
- 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
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