fix(matrix,stoat): derive the public host without reading the compose

Both hooks read their host (and matrix its database password) back out of the
deployed docker-compose.yml. That cannot work: install_post_compose runs after
the compose TEMPLATE is copied but before dockerConfigSetupFileWithData fills
the tags, so at that point the file still holds raw placeholders. Matrix aborted
with "Database password was not generated in the compose file" even though the
password had been generated correctly — it just was not in the compose yet.

Derive the host from port_subdomains[0] + domain_full instead, both already in
scope from variables_init_app, applying the same empty/@/root rule as
tagsProcessorPortSubdomains so the computed name and the Traefik rule generated
later cannot drift apart. Matrix takes its database password from
CFG_MATRIX_DB_PASSWORD_1, which is where the secret is generated and remembered
and is the same variable the compose tag is filled from a step later.

The error messages now name the actual missing thing — the domain — rather than
blaming the compose file.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
librelad 2026-08-18 19:55:32 +01:00
parent 751a4578d6
commit a0f0bc087e
2 changed files with 33 additions and 20 deletions

View File

@ -53,21 +53,21 @@ matrix_install_post_compose()
echo ""
local server_name
server_name=$(_matrixServerName "$app_name")
server_name=$(_matrixServerName)
if [[ -z "$server_name" ]]; then
isError "Could not determine the homeserver name from the compose file — aborting Synapse configuration."
isNotice "Check that CFG_MATRIX_PORT_1 is public and Traefik-managed, then reinstall."
isError "No domain is configured — cannot determine the Matrix server_name."
isNotice "Set CFG_DOMAIN_${CFG_MATRIX_DOMAIN:-1} (General → Network), then reinstall."
return 1
fi
# Must match the password the compose handed to Postgres. Read it back from
# the deployed compose rather than from CFG_MATRIX_DB_PASSWORD_1: this hook
# runs after templating, so the compose is the settled value, and it stays
# correct even on an install whose config still holds the placeholder.
local db_password
db_password=$(tagsManagerGetTagContent "$app_dir/docker-compose.yml" "MATRIX_DB_PASSWORD_1_TAG")
if [[ -z "$db_password" || "$db_password" == "MATRIX_DB_PASSWORD_1_DATA" ]]; then
isError "Database password was not generated in the compose file — aborting Synapse configuration."
# Same value the compose will hand to Postgres. Taken from the config rather
# than the compose because the compose is not substituted yet at this point;
# the config is where the secret is generated and remembered, and the
# #LIBREPORTAL|MATRIX_DB_PASSWORD_1_TAG| line is filled from this very
# variable a step later, so the two cannot disagree.
local db_password="$CFG_MATRIX_DB_PASSWORD_1"
if [[ -z "$db_password" || "$db_password" == RANDOMIZEDPASSWORD* ]]; then
isError "CFG_MATRIX_DB_PASSWORD_1 was not generated — aborting Synapse configuration."
return 1
fi
@ -216,7 +216,7 @@ matrix_install_post()
{
local app_name="$1"
local server_name
server_name=$(_matrixServerName "$app_name")
server_name=$(_matrixServerName)
local admin_user="${CFG_MATRIX_ADMIN_USERNAME:-admin}"
echo ""

View File

@ -22,12 +22,25 @@ stoat_install_pre()
fi
}
# The public host, read back from the deployed compose once tag substitution has
# filled it in. Everything else in this file is derived from it.
# The public host every generated file is derived from.
#
# Computed from the port arrays and $domain_full that variables_init_app puts in
# scope, NOT read back from the deployed compose: install_post_compose runs
# before dockerConfigSetupFileWithData, so the compose still holds raw
# placeholders at this point. port_subdomains[0] is CFG_STOAT_PORT_1 (the Caddy
# router); the empty/@/root cases mirror tagsProcessorPortSubdomains so this and
# the Traefik rule generated later cannot drift apart.
_stoatDomain()
{
local app_name="$1"
tagsManagerGetTagContent "$containers_dir$app_name/docker-compose.yml" "DOMAINSUBNAME_TAG_1"
local sub="${port_subdomains[0]}"
[[ -z "$domain_full" ]] && return 1
if [[ "$sub" == "@" || "$sub" == "root" ]]; then
echo "$domain_full"
elif [[ -n "$sub" ]]; then
echo "${sub}.${domain_full}"
else
echo "stoat.${domain_full}"
fi
}
# Generate secrets.env if it does not already exist. Returns without touching an
@ -83,10 +96,10 @@ stoat_install_post_compose()
echo ""
local domain
domain=$(_stoatDomain "$app_name")
domain=$(_stoatDomain)
if [[ -z "$domain" ]]; then
isError "Could not determine the public host from the compose file — aborting Stoat configuration."
isNotice "Check that CFG_STOAT_PORT_1 is public and Traefik-managed, then reinstall."
isError "No domain is configured — cannot determine the public host for Stoat."
isNotice "Set CFG_DOMAIN_${CFG_STOAT_DOMAIN:-1} (General → Network), then reinstall."
return 1
fi
@ -203,7 +216,7 @@ stoat_install_post()
{
local app_name="$1"
local domain
domain=$(_stoatDomain "$app_name")
domain=$(_stoatDomain)
echo ""
isNotice "Stoat first run:"