From cd1d0e3b408c77f5129e4ac35fe26f720cbaabc8 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 12 Aug 2026 03:29:23 +0000 Subject: [PATCH 1/5] Filter turnadmin -l log noise before parsing usernames MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Live run surfaced it: this coturn build writes its own startup log lines ("INFO SQLite connection was closed.", "INFO log file opened: ...") to turnadmin -l's STDOUT, not stderr — 2>/dev/null never caught them, so they got parsed as if they were usernames, producing nonsensical "Database has user '2026-...INFO SQLite connection was closed.'" warnings on a real run. A genuine "user[realm]" line never contains a space; every log line does, so filtering on that is a simple, build-independent fix. Also diagnosed the actual underlying failure this surfaced: coturn's live user database was genuinely empty (both 'asterisk' and 'mattermost' had cached credential files but neither was registered in the DB) — exactly the container/volume-recreated-without-db drift this script's consumer cross-check exists to catch, confirmed against a real run. Co-Authored-By: Claude Sonnet 5 Claude-Session: https://claude.ai/code/session_01H4k6J1qXXyYxhGEgnJaMvn --- tools/coturn-test-check.sh | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/tools/coturn-test-check.sh b/tools/coturn-test-check.sh index d1a7f66..dfcb7ac 100755 --- a/tools/coturn-test-check.sh +++ b/tools/coturn-test-check.sh @@ -76,7 +76,14 @@ ok "Relay port range: ${COTURN_MIN_PORT}-${COTURN_MAX_PORT}" # ── Registered consumers ────────────────────────────────────────────────────── section "Registered consumers" -DB_USERS="$(docker exec coturn turnadmin -l -b /var/lib/coturn/turndb 2>/dev/null | sed -E 's/\[.*//' | awk 'NF' | sort -u)" +# turnadmin -l writes its own startup log lines ("INFO SQLite connection +# was closed.", "INFO log file opened: ...") to STDOUT on at least some +# coturn builds, not stderr — confirmed live, `2>/dev/null` alone let them +# through and got misparsed as usernames. A real "user[realm]" line never +# contains a space; every log line here does, so filtering those out is a +# safe, simple way to keep only genuine entries regardless of which coturn +# build's log-noise happens to leak onto stdout. +DB_USERS="$(docker exec coturn turnadmin -l -b /var/lib/coturn/turndb 2>/dev/null | grep -v ' ' | sed -E 's/\[.*//' | awk 'NF' | sort -u)" if [ -z "$DB_USERS" ]; then warn "No users found in coturn's own database — nothing has actually registered yet, or turnadmin -l's output format changed. Raw:" docker exec coturn turnadmin -l -b /var/lib/coturn/turndb 2>&1 | sed 's/^/ /' From f94f43786f887d79fa6a09d32f07ba48d661681d Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 12 Aug 2026 11:13:46 +0000 Subject: [PATCH 2/5] Self-heal orphaned coturn credentials in ensure_coturn_user() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Answers a direct question from this session: no, reinstalling asterisk/mattermost did NOT fix a coturn user missing from the live database, because ensure_coturn_user() only ever calls turnadmin -a in the else branch — reached only when the cache file (users/.env) is MISSING. A stale-but-present cache file (exactly what a coturn container/volume recreation without preserving ./db leaves behind, per this session's real diagnosis) looked identical to a healthy one and was trusted blindly, so every consumer's installer kept silently reusing credentials that no longer existed in coturn's database. Now checks the cached username against coturn's actual live user list on every call, and re-registers it with the same cached password if it's missing — the same self-heal pattern this repo already applies elsewhere (Beszel's compose patch, Vaultwarden's SMTP half-state, FMD's chown). Re-uses the turnadmin -l log-noise filter from tools/coturn-test-check.sh (a real "user[realm]" line never contains a space; at least one coturn build writes its own startup log lines to stdout, not stderr, so a bare 2>/dev/null doesn't catch them). Co-Authored-By: Claude Sonnet 5 Claude-Session: https://claude.ai/code/session_01H4k6J1qXXyYxhGEgnJaMvn --- lib/common.sh | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/lib/common.sh b/lib/common.sh index 421701e..fb4024b 100644 --- a/lib/common.sh +++ b/lib/common.sh @@ -1076,6 +1076,31 @@ ensure_coturn_user() { _u="$(grep '^COTURN_USER=' "$_userfile" | cut -d= -f2-)" _p="$(grep '^COTURN_PASS=' "$_userfile" | cut -d= -f2-)" COTURN_USERNAME="$_u" COTURN_PASSWORD="$_p" + + # The cache file surviving doesn't mean the username still exists in + # coturn's own live database — confirmed live: a coturn + # container/volume recreated without preserving ./db wipes the + # database while this file (a separate directory) survives + # untouched, silently orphaning every consumer's credentials until + # something re-registers them. Without this check, re-running the + # consumer's installer (fresh or update) never re-registers anything + # since it only ever hits the else branch below on a MISSING cache + # file — a stale-but-present one looked identical to a healthy one. + # A real "user[realm]" line never contains a space; turnadmin -l's + # own startup log lines do (confirmed live, at least one coturn + # build writes them to stdout, not stderr), so filtering on that + # keeps this robust across builds without needing to match a + # specific log format. + local _db_users + _db_users="$(docker exec coturn turnadmin -l -b /var/lib/coturn/turndb 2>/dev/null | grep -v ' ' | sed -E 's/\[.*//' | awk 'NF')" + if ! grep -qx "$_u" <<< "$_db_users"; then + log_warning "coturn user '$_u' ($_consumer) has cached credentials but isn't in coturn's live database — re-registering with the same password." + if docker exec coturn turnadmin -a -u "$_u" -p "$_p" -r "$_realm" -b /var/lib/coturn/turndb >/dev/null 2>&1; then + log_success "Re-registered coturn user '$_u' for $_consumer" + else + log_warning "Could not re-register coturn user '$_u' for $_consumer — is the coturn container running?" + fi + fi else COTURN_USERNAME="$_consumer" COTURN_PASSWORD="$(generate_password 24)" From d55a7cc81a53692abcb4aaa2d6d36be5559e1d46 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 12 Aug 2026 11:44:02 +0000 Subject: [PATCH 3/5] Reach the coturn self-heal check from asterisk.sh's update path too MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Direct follow-up to the previous commit's ensure_coturn_user() fix: that fix is useless for Asterisk specifically unless something actually calls ensure_coturn_user("asterisk") again, and the update ("Reinstall in place") branch returns 0 well before the fresh-install path's call to it — only "Full install" reached it, which re-prompts everything (droplet detection, domain, etc.) just to fix a credential re-registration. Added the same call to the update path, gated on NOT having an embedded coturn (checked via the existing _HAD_EMBEDDED_COTURN detection) — calling it unconditionally would silently chain-install the shared coturn service for a box deliberately running Asterisk's own dedicated coturn, exactly the kind of silent update-time migration CLAUDE.md's coturn guidance warns against. .env stays untouched either way (self-heal re-registers with the same cached password, never generates a new one). Co-Authored-By: Claude Sonnet 5 Claude-Session: https://claude.ai/code/session_01H4k6J1qXXyYxhGEgnJaMvn --- services/asterisk.sh | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/services/asterisk.sh b/services/asterisk.sh index bc71888..865da5a 100644 --- a/services/asterisk.sh +++ b/services/asterisk.sh @@ -1655,6 +1655,21 @@ install_asterisk() { log_warning "docker compose up failed — check: docker compose -f $EA_DIR/docker-compose.yml logs" fi + # Self-heal a stale/orphaned shared-coturn registration on + # every update, not just a full reinstall — the check inside + # ensure_coturn_user() is what actually re-registers a + # missing user, this just needs to reach it. Gated on NOT + # having an embedded coturn: an install with its own + # dedicated coturn deliberately never touches the shared one + # on update (see the warning above and CLAUDE.md's coturn + # migration guidance) — calling this unconditionally would + # silently chain-install services/coturn.sh for a box that + # was never using it, the exact "don't migrate silently on + # update" mistake that guidance warns against. + if [[ "$_HAD_EMBEDDED_COTURN" != true ]]; then + ensure_coturn_user "asterisk" + fi + _asterisk_run_presence_step "$EA_DIR" "$CONTAINER" _asterisk_offer_dashboard_and_trunk "$EA_DIR" From 7a1f09a0f7e3253fe41b96802f629a0fc07027b9 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 12 Aug 2026 12:47:31 +0000 Subject: [PATCH 4/5] Rename reinstall-mode prompt; make security-dashboard's "Full reinstall" a real teardown MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 Claude-Session: https://claude.ai/code/session_01H4k6J1qXXyYxhGEgnJaMvn --- docs/anveo-direct-setup-guide.md | 2 +- lib/common.sh | 8 ++--- services/asterisk.sh | 8 ++--- services/coturn.sh | 8 ++--- services/security-dashboard.sh | 53 +++++++++++++++++++++++++++++++- services/wordpress.sh | 8 ++--- 6 files changed, 69 insertions(+), 18 deletions(-) diff --git a/docs/anveo-direct-setup-guide.md b/docs/anveo-direct-setup-guide.md index f219370..45657e4 100644 --- a/docs/anveo-direct-setup-guide.md +++ b/docs/anveo-direct-setup-guide.md @@ -143,7 +143,7 @@ account default in step 6 and skip even that: sudo ./setup.sh pstn-trunk ``` -- Existing install → choose **update** (`r`) if you're just changing the +- Existing install → choose **update** (`u`) if you're just changing the DID/server, or the CLI will walk fresh prompts if none exists yet. - Provider quick-pick: **1) Anveo Direct** — pre-fills `sbc.anveo.com` and Anveo's 4 published signaling IPs (only one of which the hostname diff --git a/lib/common.sh b/lib/common.sh index fb4024b..016aaf5 100644 --- a/lib/common.sh +++ b/lib/common.sh @@ -718,12 +718,12 @@ prompt_reinstall_mode() { return fi echo " Existing install detected. Choose:" - echo " r) Reinstall in place — refresh vendor files/config, keep existing settings" - echo " f) Full install — re-run every prompt from scratch" + echo " u) Update — refresh vendor files/config, keep existing settings" + echo " f) Full reinstall — re-run every prompt from scratch" echo " c) Cancel — leave everything as-is [default]" - read -p " Choice [r/f/c, Enter=cancel]: " response + read -p " Choice [u/f/c, Enter=cancel]: " response case "${response,,}" in - r) eval "$varname='update'" ;; + u) eval "$varname='update'" ;; f) eval "$varname='fresh'" ;; *) eval "$varname='cancel'" ;; esac diff --git a/services/asterisk.sh b/services/asterisk.sh index 865da5a..4ff649f 100644 --- a/services/asterisk.sh +++ b/services/asterisk.sh @@ -82,12 +82,12 @@ if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then return fi echo " Existing install detected. Choose:" - echo " r) Reinstall in place — refresh vendor files/config, keep existing settings" - echo " f) Full install — re-run every prompt from scratch" + echo " u) Update — refresh vendor files/config, keep existing settings" + echo " f) Full reinstall — re-run every prompt from scratch" echo " c) Cancel — leave everything as-is [default]" - read -r -p " Choice [r/f/c, Enter=cancel]: " _r + read -r -p " Choice [u/f/c, Enter=cancel]: " _r case "${_r,,}" in - r) eval "$_var='update'" ;; + u) eval "$_var='update'" ;; f) eval "$_var='fresh'" ;; *) eval "$_var='cancel'" ;; esac diff --git a/services/coturn.sh b/services/coturn.sh index 19b3fdc..a0ce841 100644 --- a/services/coturn.sh +++ b/services/coturn.sh @@ -87,12 +87,12 @@ if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then local _var="$1" _r if [[ "${UNATTENDED:-false}" == "true" ]]; then eval "$_var='cancel'"; return; fi echo " Existing install detected. Choose:" - echo " r) Reinstall in place — refresh vendor files, keep existing settings" - echo " f) Full install — re-run every prompt from scratch" + echo " u) Update — refresh vendor files, keep existing settings" + echo " f) Full reinstall — re-run every prompt from scratch" echo " c) Cancel — leave everything as-is [default]" - read -r -p " Choice [r/f/c, Enter=cancel]: " _r + read -r -p " Choice [u/f/c, Enter=cancel]: " _r case "${_r,,}" in - r) eval "$_var='update'" ;; + u) eval "$_var='update'" ;; f) eval "$_var='fresh'" ;; *) eval "$_var='cancel'" ;; esac diff --git a/services/security-dashboard.sh b/services/security-dashboard.sh index 789f3ca..40bd0ff 100644 --- a/services/security-dashboard.sh +++ b/services/security-dashboard.sh @@ -184,7 +184,24 @@ install_security-dashboard() { log_info "Leaving the existing install as-is." return 0 ;; - fresh) ;; + fresh) + echo "" + log_warning "Full reinstall stops the dashboard and removes its systemd unit," + log_warning "sudoers grant, Caddy block, service user, and app files, then sets" + log_warning "it up again from scratch — every prompt below runs as if this were" + log_warning "a brand new install." + local _WIPE_ADMINS="" + prompt_yn " Also delete dashboard-admins.conf (per-admin Calls/Texts/Voicemail scoping)? (y/n):" "n" _WIPE_ADMINS + + local _ADMINS_BACKUP="" + if [[ ! "$_WIPE_ADMINS" =~ ^[Yy]$ ]] && [ -f "$APP_DIR/dashboard-admins.conf" ]; then + _ADMINS_BACKUP="$(mktemp)" + cp "$APP_DIR/dashboard-admins.conf" "$_ADMINS_BACKUP" + log_info "Preserving dashboard-admins.conf across the reinstall." + fi + + _secdash_teardown "$APP_DIR" "$SVC_USER" "$DASHBOARD_PORT" + ;; esac fi @@ -197,6 +214,11 @@ install_security-dashboard() { _secdash_grant_asterisk_access "$SVC_USER" "$ASTERISK_LOG_DIR" "$ASTERISK_CONFIG_DIR" "$ASTERISK_EA_CONFIG_DIR" "$ASTERISK_SPOOL_DIR" mkdir -p "$APP_DIR" + if [ -n "${_ADMINS_BACKUP:-}" ]; then + cp "$_ADMINS_BACKUP" "$APP_DIR/dashboard-admins.conf" + rm -f "$_ADMINS_BACKUP" + log_success "Restored dashboard-admins.conf" + fi _secdash_write_app "$APP_DIR" chown -R "$SVC_USER:$SVC_USER" "$APP_DIR" _secdash_write_asn_helper "$APP_DIR" @@ -974,6 +996,35 @@ _secdash_remove_caddy_block() { log_info "Removed the existing dashboard Caddy block (regenerating it fresh)." } +# Full teardown for "Full reinstall" — stops the service and removes +# everything a fresh install recreates: systemd unit, sudoers grant, Caddy +# site block, the secdash system user, and the app directory. Non-Docker +# service (systemd + /opt, not a container), so lib/common.sh's +# remove_service() (Docker-only, $DOCKER_DIR/) doesn't apply here — +# this is the equivalent for this one service. Callers are responsible for +# backing up/restoring anything under $_app_dir they want to survive (see +# the dashboard-admins.conf handling around the "fresh" case in +# install_security-dashboard() — this function does not know which files, +# if any, the caller wants to keep). +_secdash_teardown() { + local _app_dir="$1" _svc_user="$2" _port="$3" + + systemctl stop security-dashboard 2>/dev/null || true + systemctl disable security-dashboard 2>/dev/null || true + rm -f /etc/systemd/system/security-dashboard.service + systemctl daemon-reload + + rm -f /etc/sudoers.d/security-dashboard + + _secdash_remove_caddy_block "$_port" + + id "$_svc_user" &>/dev/null && userdel "$_svc_user" 2>/dev/null + + rm -rf "$_app_dir" + + log_success "Removed security-dashboard's systemd unit, sudoers grant, Caddy block, user, and app files." +} + # Root-owned helper for editing CrowdSec's Asterisk-scenario YAMLs — the # secdash service user (--shell /usr/sbin/nologin, no special file grants) # cannot write /etc/crowdsec/scenarios/*.yaml directly (root:root, mode diff --git a/services/wordpress.sh b/services/wordpress.sh index 85b092b..7438e0f 100644 --- a/services/wordpress.sh +++ b/services/wordpress.sh @@ -95,12 +95,12 @@ if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then local _var="$1" _r if [[ "${UNATTENDED:-false}" == "true" ]]; then eval "$_var='cancel'"; return; fi echo " Existing install detected. Choose:" - echo " r) Reinstall in place — refresh image/compose, keep database and settings" - echo " f) Full install — re-run every prompt from scratch" + echo " u) Update — refresh image/compose, keep database and settings" + echo " f) Full reinstall — re-run every prompt from scratch" echo " c) Cancel — leave everything as-is [default]" - read -r -p " Choice [r/f/c, Enter=cancel]: " _r + read -r -p " Choice [u/f/c, Enter=cancel]: " _r case "${_r,,}" in - r) eval "$_var='update'" ;; + u) eval "$_var='update'" ;; f) eval "$_var='fresh'" ;; *) eval "$_var='cancel'" ;; esac From aa65b5ef5b9baada440cae779f8f2a0ca23a9173 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 12 Aug 2026 13:07:38 +0000 Subject: [PATCH 5/5] Make "Full reinstall" a real teardown for asterisk, mattermost, and coturn MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Extends the security-dashboard prototype to the shared-coturn trio, since these three are exactly the case that pattern was built for — a fresh reinstall of any of them today just overwrote files in place without stopping old containers first, and coturn's own fresh path never made an informed choice about the consumer credentials/database it happens to leave alone (safe today, but by omission rather than design). - asterisk.sh / mattermost.sh: "Full reinstall" now stops the existing containers (`docker compose down`) before falling through to the normal install flow, and asks a single explicit question — delete stored data (PBX config/spool/voicemail for Asterisk; Postgres db/uploads/config/ plugins for Mattermost) — defaulting to preserve. Their shared-coturn TURN credential is deliberately left alone either way (reused from cache via ensure_coturn_user(), same as update) — it's not this service's own data, and coturn already handles that continuity. Mattermost's existing "_db_has_data" check already reads the filesystem to decide whether to reuse or regenerate DB_PASS, so the wipe/preserve choice composes with that for free — no separate flag needed. Asterisk's warns to re-run pstn-trunk afterward if data is wiped, since that's what actually goes stale (its dialplan patch), not the fabricated "AMI secret" framing an earlier draft of this warning used before I checked the actual code. - coturn.sh: "Full reinstall" now lists which consumers are currently registered (from users/*.env) and asks explicitly whether to also wipe TURN credentials and the user database, instead of silently preserving them as an unexamined side effect of never deleting the directory. Defaults to preserve. If the operator does choose to wipe, the running container is restarted afterward — it holds the old, now-deleted turndb file open, so new turnadmin writes to the fresh file would otherwise go unseen until a restart anyway. Every affected consumer already self-heals a missing credential on its own next Update run via ensure_coturn_user()'s existing cache-miss path — no changes needed there, just confirmed it covers this case. Co-Authored-By: Claude Sonnet 5 Claude-Session: https://claude.ai/code/session_01H4k6J1qXXyYxhGEgnJaMvn --- services/asterisk.sh | 21 ++++++++++++++++++++- services/coturn.sh | 21 +++++++++++++++++++++ services/mattermost.sh | 14 ++++++++++++++ 3 files changed, 55 insertions(+), 1 deletion(-) diff --git a/services/asterisk.sh b/services/asterisk.sh index 4ff649f..0cfa883 100644 --- a/services/asterisk.sh +++ b/services/asterisk.sh @@ -1692,7 +1692,26 @@ install_asterisk() { return 0 ;; fresh) - log_info "Proceeding with a full fresh reinstall — every prompt below runs from scratch." + echo "" + log_warning "Full reinstall stops the existing containers and re-runs every" + log_warning "prompt below from scratch (domain, networking, firewall, Caddy/" + log_warning "Authelia). The TURN credential registered with the shared coturn" + log_warning "service is reused as-is — no need to touch coturn for this." + local _WIPE_PBX_DATA="" + prompt_yn " Also delete stored PBX data (extensions, voicemail, recordings, spool)? (y/n):" "n" _WIPE_PBX_DATA + + log_info "Stopping the existing containers..." + (cd "$EA_DIR" && docker compose down 2>/dev/null) + + if [[ "$_WIPE_PBX_DATA" =~ ^[Yy]$ ]]; then + rm -rf "$EA_DIR/config/asterisk" "$EA_DIR/spool" "$EA_DIR/logs" "$EA_DIR/lib" + log_warning "Deleted config/asterisk, spool, logs, and lib — extensions," + log_warning "voicemail, and call recordings are gone." + if declare -F install_pstn-trunk >/dev/null 2>&1 || [ -f "$EA_DIR/pstn-trunk-usage-alert.sh" ]; then + log_warning "PSTN trunk patches config/asterisk's dialplan — re-run" + log_warning "'sudo ./setup.sh pstn-trunk' afterward to restore it." + fi + fi ;; esac fi diff --git a/services/coturn.sh b/services/coturn.sh index a0ce841..08dbb94 100644 --- a/services/coturn.sh +++ b/services/coturn.sh @@ -186,6 +186,27 @@ install_coturn() { log_warning "change the host/port/realm below, every already-registered consumer" log_warning "(Asterisk, Mattermost, ...) keeps pointing at the OLD values in its own" log_warning ".env until you re-run that service's installer too." + + local _consumers="" + [ -d "$DIR/users" ] && _consumers="$(find "$DIR/users" -maxdepth 1 -name '*.env' -printf '%f\n' 2>/dev/null | sed 's/\.env$//' | tr '\n' ' ')" + if [ -n "$_consumers" ]; then + echo "" + log_info "Registered consumers: $_consumers" + local _WIPE_USERS="" + prompt_yn " Also delete all TURN user credentials and the user database (forces every consumer above to re-register)? (y/n):" "n" _WIPE_USERS + if [[ "$_WIPE_USERS" =~ ^[Yy]$ ]]; then + rm -rf "$DIR/users" "$DIR/db" + mkdir -p "$DIR/db" "$DIR/users" + # The running container (if any) still holds the old, + # now-deleted turndb file open — new turnadmin writes + # to the fresh file at that path go unseen until the + # server process restarts and reopens it. + docker restart coturn >/dev/null 2>&1 + log_warning "Deleted TURN credentials and the user database." + log_warning "Re-run each consumer's installer in Update mode afterward —" + log_warning "ensure_coturn_user() auto-recovers a fresh credential for it." + fi + fi ;; esac fi diff --git a/services/mattermost.sh b/services/mattermost.sh index 67363fd..7ccb3a6 100644 --- a/services/mattermost.sh +++ b/services/mattermost.sh @@ -314,6 +314,20 @@ install_mattermost() { log_warning "the shared coturn service — the Calls plugin's TURN config in System" log_warning "Console will need updating to the new credentials afterward (see below)." fi + echo "" + log_warning "Full reinstall stops the existing containers and re-runs every prompt" + log_warning "below from scratch. The TURN credential registered with the shared" + log_warning "coturn service is reused as-is — no need to touch coturn for this." + local _WIPE_MM_DATA="" + prompt_yn " Also delete stored data (Postgres database, uploaded files, config, plugins)? (y/n):" "n" _WIPE_MM_DATA + + log_info "Stopping the existing containers..." + (cd "$DIR" && docker compose down 2>/dev/null) + + if [[ "$_WIPE_MM_DATA" =~ ^[Yy]$ ]]; then + rm -rf "$DIR/db" "$DIR/data" "$DIR/logs" "$DIR/config" "$DIR/plugins" + log_warning "Deleted the Postgres database, uploaded files, config, and plugins." + fi ;; esac fi