5edfed7735f07a08a71024202afd49e5a99d4ffe
9
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
bec9228c55 |
Back up existing files before every service overwrites them
Confirmed live: install_frigate()'s fresh-install path overwrote a working, hand-crafted docker-compose.yml (Frigate + mosquitto + frigate-notify) with zero backup, because that file's shape didn't match what frigate.sh's own "existing install" detection knew how to recognize. Every service's own detection is a judgment call about what counts as "already installed" and can miss a real setup built outside this repo's conventions. lib/common.sh gains backup_if_exists(FILE) — copies FILE to FILE.bak.<timestamp> if it exists, no-ops otherwise (including DRY_RUN). Applied before every service's own `cat > docker-compose.yml`/`cat > .env` write across all 60 services that do one (115 call sites), plus a matching standalone-mode stub added to every service's own bootstrap block, same convention already used for port_in_use/find_free_port. This doesn't replace a service's own update/fresh-reinstall detection — it's the safety net underneath it, so a wrong detection costs a .bak file to restore from instead of the original silently disappearing. Also fixes the actual gap that surfaced this: services/frigate.sh's Authelia offer only checked for Authelia installed locally on Frigate's own box, which is never true for a dedicated NVR box with no local Caddy either (the common shape — Caddy lives elsewhere, snippet-generation mode already handles that). Now offers Authelia protection unconditionally and, when Authelia isn't local, asks whether it lives on the same machine as Caddy (still "import authelia", since that's local to wherever Caddy ends up) or on a genuinely separate third machine (the explicit header-pinned forward_auth form, per CLAUDE.md's "forward_auth to a remote Authelia" note, needed because a bare authelia:9091 shortcut only works one hop). |
||
|
|
cd003dbaf3 |
Add Gatus auto-sync from Caddyfile, promote ensure_yq to lib/common.sh
Adds one Gatus endpoint per Caddy site block automatically, tagged group: caddy-sync — the sync only ever adds/removes entries in that exact group, so anything added by hand (the default external checks, a custom endpoint) is never touched regardless of what the Caddyfile looks like. Offered at install time (syncs once immediately) and, if systemd is available, scheduled via a timer every 15 minutes so a site added or removed later gets picked up without re-running the installer — matches the "schedule that checks the Caddyfile" shape asked for. Domain extraction tracks actual brace depth (reusing the same approach as remove_service's Caddy block removal) rather than a naive line-by-line scan, so it correctly skips the global options block and parenthesized snippet definitions like (authelia) without needing to special-case them by name. Verified end-to-end against a real Caddyfile/config.yaml fixture with the actual mikefarah/yq binary: initial sync adds the right entries and leaves the default "external" group alone, a second run with no Caddyfile changes is a true no-op (0 added, 0 removed), and changing the Caddyfile (removing one site, adding another) correctly adds the new endpoint and removes only the stale one. Also fixes a real gap surfaced while building this: ensure_yq (used by both gatus.sh now and onlyoffice.sh already) checked `command -v yq` alone, which a box can satisfy with a completely different, incompatible yq — confirmed live in this environment, Debian/Ubuntu's own `yq` apt package is kislyuk/yq (a Python jq-wrapper) which silently errors on mikefarah/yq's `e '.path' file` syntax every caller here depends on. Now checks the version string actually identifies as mikefarah's before trusting it, installing to /usr/local/bin (which precedes /usr/bin on Ubuntu's default PATH) if not. Promoted ensure_yq itself from onlyoffice.sh (its only previous user) to lib/common.sh now that gatus.sh needs the same thing, so both share one implementation. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01H4k6J1qXXyYxhGEgnJaMvn |
||
|
|
9e06ed4b83 |
Bake cross-service port collision avoidance into every service script
With 70+ services sharing a handful of common default ports (emby and jellyfin both default to 8096, changedetection and frigate both default to 5000, arm and nextcloud both default to 8080...), nothing previously checked whether a service's default port was actually free on the host. Whichever service installed second would silently write a compose file claiming an already-held port, only failing at `docker compose up` time. Adds two shared helpers to lib/common.sh: - port_in_use PORT [PROTO] — true if something's already listening - find_free_port VARNAME START [PROTO] — scans upward, writes back the first free port Every service that publishes a fixed host port now scans before writing docker-compose.yml, on every install (not just when adding an explicit additional instance). On a normal single-install host this is a silent no-op; it only changes behavior when something else already holds the port. - The 19 services already given multi-instance support this session had their port scan moved out of the "add instance" branch to run unconditionally, since the same collision risk exists on a plain first install. - 20 more services with previously-hardcoded ports gained scanning for the first time: archivebox, arm, calibre-web, changedetection, drum-rhythm-game, gatus, n8n, nextcloud, onlyoffice, stirling-pdf, uptimekuma, portainer, iopaint (both GPU/CPU compose branches), koha (paired), syncthing (paired), wg-easy (paired, plus WG_PORT env so generated peer configs keep the right Endpoint), homeassistant (bridge-mode only — host mode can only warn), frigate and frigate-audio (multi-port stacks, moved together). - caddy.sh is the deliberate exception: 80/443 stay fixed and only warn on collision, since silently moving Caddy itself would leave nothing listening where any client actually looks. - authelia.sh needs no change — it has no published host port at all. - Every service's standalone bootstrap fallback (sudo bash services/x.sh with no sibling files) got the same two helpers duplicated into its stub block, matching how every other shared helper is already handled there. Documents the full pattern in CLAUDE.md's new "Port collision avoidance" section, including the quoted-heredoc/backtick-escaping gotcha and the network_mode:host limitation (can only scan ports the app takes as a configurable env var). Verified via bash -n on every changed file, plus functional runs seeding occupied ports for each collision shape used here (single, paired, multi-port stacks) and confirming the scan/shift and generated compose/README output are correct — including the emby/jellyfin, nextcloud/arm, and frigate/changedetection collision scenarios that originally motivated this. |
||
|
|
1fc0a6edfe |
Apply the local/remote Caddy mode resolution to every service, not just traccar
traccar.sh's caddy_net wiring was fixed to mirror configure_caddy_for_service's
own mode resolution (CADDY_MODE from site config, then a local ~/docker/caddy,
then the legacy CADDY_REMOTE_HOST var) instead of only checking for the local
directory. That same bare directory check was copy-pasted into the caddy_net
wiring of every other Docker service in the repo, so a site with Caddy on a
different box would silently fail to join any of their containers to caddy_net
during setup (or, for homeassistant/koha, only get half the wiring right).
Applied the same fix mechanically across all 37 services using the standard
_CADDY_NET_BLOCK/_CADDY_NET_SECTION pattern (verified identical text via
scripted diff before touching any of them), plus by hand for:
- homeassistant.sh and koha.sh, which use their own differently-shaped
variables (HA_CADDY_NET_LINES / _CADDY_NET_ENTRY) for the same decision
- paintplus.sh and ai-stack.sh, which do a live `docker network connect`
instead of a compose network block
- watchyourlan.sh, whose Caddy note was worded for local-only setups
sms-inbound.sh got more than a mode swap: its Caddy wiring was hand-rolled
(not routed through configure_caddy_for_service) and had no remote-Caddy
path at all — a remote Caddy box would get a misleading "Caddy isn't
installed here" message instead of a snippet. Added
_sms_write_caddy_snippet(), mirroring the snippet-file pattern
configure_caddy_for_service uses everywhere else, and pointed the firewall
gate at the same three-way mode instead of a two-way dir check.
Verified: bash -n across all of services/*.sh, a scripted check that every
touched file has exactly one _CADDY_MODE resolution and no leftover bare
`[ -d "$DOCKER_DIR/caddy" ]` feeding a caddy_net decision, and spot-checked
docker compose config renders (traccar, mattermost) confirming the ${VAR}
interpolation and multi-service usage sites still resolve correctly.
|
||
|
|
fa906186c3 |
fix(services): conditional caddy_net across all Docker service scripts
Only include the caddy_net network block in generated docker-compose.yml files when ~/docker/caddy exists. Prevents "network caddy_net declared as external, but could not be found" on standalone installs without Caddy. Affected: actualbudget, archivebox, arm, audiobookshelf, calibre-web, changedetection, drum-rhythm-game, emby, fmd, frigate, frigate-audio, frigate-notify, gatus, homeassistant, immich, iopaint, jellyfin, joplin, koha, lyrion, magicmirror, mail-archiver, mattermost, mealie, meshcentral, n8n, nextcloud, ntfy, onlyoffice, portainer, stirling-pdf, syncthing, traccar, unifi, uptimekuma, vaultwarden, wg-easy Skipped: authelia (creates caddy_net itself), caddy, crowdsec, wolf, wolf-pair, and services using network_mode: host with no caddy_net. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01D8ckUJQtj1pH8jtAddBDZs |
||
|
|
7c3f101fe0 |
Add asterisk, nextcloud, onlyoffice, mattermost services + vendor/easy-asterisk
asterisk.sh (homelab): - Easy Asterisk PBX with self-hosted coturn TURN server - Vendored from outis1one/easy-asterisk v0.10.0 for offline install - LAN-only or FQDN mode (TLS + TURN relay for remote access) - Auto-answer SIP headers for intercom use case - Authelia SSO for web admin; WEB_ADMIN_AUTH_DISABLED=true when chosen - UFW rules: 5060-5061, 8080, 8088-8089, 3478, 10000-20000/udp, 49152-49252/udp - Builds custom Docker image from vendor/easy-asterisk/ nextcloud.sh (utilities): - Custom Dockerfile: nextcloud:apache + smbclient (SMB external storage) - MariaDB 10.11 sidecar with matching env vars - OVERWRITEPROTOCOL/OVERWRITECLIURL/TRUSTED_PROXIES set for Caddy - Enables files_external app after first-run init (waits up to 90s) onlyoffice.sh (utilities): - JWT generated once, preserved across re-runs - _ensure_yq: auto-installs yq v4 for FileBrowser config patching - _wire_nextcloud: idempotent occ wiring (DocumentServerUrl, jwt_secret) - _wire_filebrowser: patches config.yaml + restarts container - Caddy block overrides X-Frame-Options to allow iframe embedding mattermost.sh (utilities): - PostgreSQL 15-alpine + Mattermost Team Edition + coturn (port 3479) - 8443/udp for Calls plugin RTC server - coturn uses --use-auth-secret HMAC mode (required by Calls plugin) - SITE_URL computed from SITE_DOMAIN, promptable - UFW: 8443/udp, 3479, 49153-49352/udp vendor/easy-asterisk/: - All upstream source files vendored for offline/self-contained installs - Dockerfile, docker/entrypoint.sh, docker/coturn-entrypoint.sh - easy-asterisk-v0.10.0.sh (6929-line management script) - scripts/vpn-diagnostics.sh, scripts/dns-whitelist.sh - .env.example https://claude.ai/code/session_014CCYqVwW6d6f5dw1qRokYt |
||
|
|
e95e82be2f |
Fix functional bugs found in service audit
wg-easy: PASSWORD env var removed in v14+; generate bcrypt hash at install time via 'docker run wg-easy wgpw' and write PASSWORD_HASH instead. ntfy: write config/server.yml with base-url, cache-file, auth-file, and behind-proxy:true so push notification links work when behind Caddy. auth-default-access: deny-all (require topic auth). mealie: BASE_URL was hardcoded to http://localhost:9925; email links and OAuth redirects broke when served via Caddy. Now computed from SITE_DOMAIN and written to .env so it's easy to update. nextcloud: add OVERWRITEPROTOCOL=https, OVERWRITECLIURL, TRUSTED_PROXIES to .env so share links and internal redirects use https:// behind Caddy. onlyoffice: Caddy's default X-Frame-Options: SAMEORIGIN header blocked OnlyOffice from being embedded as an iframe in Nextcloud. Override it in the Caddy site block to allow framing. vaultwarden: remove exposed port 3012 (WebSocket — not needed since v1.29+, all handled on port 80). Publish port 8888 for direct host access instead. Remove WEBSOCKET_ENABLED=true (ignored in current versions). https://claude.ai/code/session_014CCYqVwW6d6f5dw1qRokYt |
||
|
|
0d81839c80 |
Vendor easy-asterisk source files; fix asterisk.sh and onlyoffice.sh
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 |
||
|
|
d948e86341 |
Add Nextcloud, OnlyOffice, and Mattermost services
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 |