a212be09c381b29a7b9f5dd2ceee6c6ab56082c5
6
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). |
||
|
|
7a1f09a0f7 |
Rename reinstall-mode prompt; make security-dashboard's "Full reinstall" a real teardown
Two-part change discussed and scoped in this session before touching
anything:
1. Rename "Reinstall in place" (r) -> "Update" (u) and "Full install" (f)
-> "Full reinstall" everywhere the prompt appears: lib/common.sh's
shared prompt_reinstall_mode(), plus the three services that carry
their own duplicated standalone-stub copy of it for standalone
execution (asterisk.sh, coturn.sh, wordpress.sh — per this repo's
documented standalone-bootstrap pattern). Internal state values
(update/fresh/cancel) are unchanged, so no other service's case
statement needed touching. docs/anveo-direct-setup-guide.md's `r`
reference updated to `u` to match. attic/asterisk-digital-ocean.sh
deliberately left alone — this repo's own policy is to not backport
fixes into attic/.
2. security-dashboard.sh's "Full reinstall" now does a real teardown
before reinstalling — stops and removes the systemd unit, sudoers
grant, Caddy site block, and secdash system user, then proceeds
through the normal fresh-install flow — instead of just overwriting
files in place while leaving the old service running underneath.
Prototype for a pattern discussed for other services later: split the
destructive question out explicitly ("also delete
dashboard-admins.conf — per-admin extension scoping?", default n) so
full reinstall doesn't silently discard state a plain "start over"
request wouldn't expect to lose. Verified the backup/restore mechanics
(mktemp, copy out before teardown, copy back after) against a mock
under `set -u` for both the preserve and wipe paths before shipping.
Update mode was already the strongest existing example of surfacing
newer optional prompts (its "Reconfigure Caddy protection?" /
"Reconfigure per-admin scoping?" sub-prompts already cover every setting
fresh-install offers) — no changes needed there for this service.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01H4k6J1qXXyYxhGEgnJaMvn
|
||
|
|
abd1bcd35d |
Fix wordpress.sh picking an already-occupied port
Reported live: a fresh site's container failed to start with "address already in use" on its assigned port. wordpress.sh scanned for a free port by grepping `docker ps -a`'s port list — that only reflects ports Docker itself currently has bound, so it's blind to ports held by non-Docker processes or anything Docker isn't reporting cleanly at that instant. Every other service in this repo scans with find_free_port (checks actual OS-level listening sockets via ss) per CLAUDE.md's "Port collision avoidance" section; wordpress.sh was the one holdout still using its own weaker check. Switched to the shared helper, already available in this file's own standalone stub and via lib/common.sh — no new dependency, just using what was already sitting there unused. |
||
|
|
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. |
||
|
|
a5d57050b3 |
wordpress: switch to dedicated MariaDB per site (was shared)
Reconsidered after the shared-MariaDB design's real cost became clear: Kopia's generic backup (services/backup.sh) stops a service's container to snapshot it, so a shared MariaDB instance would back up -- and would have to be restored -- as one unit covering every site at once. Restoring just one site's database to an earlier point meant restoring the whole shared snapshot to a temporary location first and manually extracting that site's data back out, not a direct restore. Each site now gets its own dedicated MariaDB container embedded in its own docker-compose.yml (same pattern as services/nextcloud.sh) instead of registering a database on a shared instance: - Removed _wordpress_ensure_shared_db() and the wordpress-db/ wordpress_net shared resources entirely. - Each site's compose file gets a `db` service (container <site>-db) on an explicitly-named per-site default network (<site>_net), so wp-cli's one-off container reliably joins the right network without depending on Docker Compose's implicit naming convention. - DB creation goes through the mariadb image's own MYSQL_DATABASE/ MYSQL_USER/MYSQL_PASSWORD env vars on first boot (same as nextcloud.sh) instead of an imperative `docker exec mysql -e "CREATE DATABASE..."` against a shared container. - Root and site DB passwords are both reused across reruns (read from the existing .env), verified via a real update-mode rerun. Tradeoff, stated in both the script's header comment and the generated per-site README: more RAM per site (~100-150MB for a full MariaDB container instead of a slice of one shared instance) in exchange for independent backup/restore. Data was already fully isolated either way (separate database + user, always required since WordPress's schema uses generic table names) -- the shared-vs-dedicated choice was only ever about the container/process, not the data. Re-verified end-to-end against the fake docker shim: distinct ports, distinct dedicated DB containers/networks per site, correct compose/ .env structure, credentials preserved across an update-mode rerun. docs/vps-sizing-recommendations.md: updated to match -- WordPress capacity recomputed for dedicated-per-site MariaDB (~580MB headroom at 4 sites, ~976MB at 2, vs. the shared design's ~700MB/~950MB). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TBtExJcqxnokyZZKmphdug |
||
|
|
a26d1831ee |
Add services/wordpress.sh — multi-site WordPress with shared MariaDB
New service: self-hosted WordPress, sized for running several independent sites the way a hosting company would, not just one blog. - Multi-site from the start: every site requires a name (no unnamed "first instance" special case like mattermost's — there's no backward-compat reason to special-case one here) and gets its own directory/container/port, but all sites share ONE MariaDB container (chain-installed on first site, reused by every other one) instead of a dedicated database container per site — same resource-sharing idea as services/coturn.sh, just scoped to WordPress's own sites rather than shared across different services. Each site gets its own database + user within that shared instance. - E-commerce is just WooCommerce, a normal WordPress plugin — no separate infrastructure. PHP memory_limit/upload_max_filesize/ post_max_size are pre-tuned (256M/64M/64M) so a product-catalog import doesn't hit default-image limits on the first try. - wp-cli (official wordpress:cli image, run as a one-off container sharing the site's html volume) does the initial WordPress core install non-interactively — title, admin account — so there's no browser setup wizard to remember per site. Falls back to printing the exact manual command if the site wasn't ready in time. - Auto-scans for a free host port per site (multiple sites can't all bind 8090), matching the "auto-scanned free ports for extras" idea already used by mattermost's multi-instance support. - DB and admin passwords are reused across reruns (checked against the DB-password-regeneration bug class already fixed elsewhere in this repo, e.g. PR #265) — verified via a real update-mode rerun that the credential doesn't change. - setup.sh: is_installed() gets a wordpress case — every site is named from the first one on, so there's never a plain $DOCKER_DIR/wordpress directory the default case could match against. - README.md: added to the utilities services table + copiable list per CLAUDE.md's three-step rule for new services. Also fixed `coturn` being in the homelab row's prose but missing from the copiable list block below it — a pre-existing gap from when coturn.sh was merged. Verified end-to-end via non-interactive dry runs against a fake docker shim (no live daemon in this environment): 3 sites installed in sequence get 3 distinct databases, 3 distinct auto-scanned ports, the shared DB is only set up once, and an update-mode rerun preserves the existing DB password rather than regenerating it. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TBtExJcqxnokyZZKmphdug |