Compare commits
2 Commits
ec98a83b48
...
e8a2aa453e
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e8a2aa453e | ||
|
|
80b94fb21f |
@ -40,7 +40,6 @@ CFG_GLUETUN_OPENVPN_USER=
|
|||||||
CFG_GLUETUN_OPENVPN_PASSWORD=
|
CFG_GLUETUN_OPENVPN_PASSWORD=
|
||||||
CFG_GLUETUN_WIREGUARD_PRIVATE_KEY=
|
CFG_GLUETUN_WIREGUARD_PRIVATE_KEY=
|
||||||
CFG_GLUETUN_WIREGUARD_ADDRESSES=
|
CFG_GLUETUN_WIREGUARD_ADDRESSES=
|
||||||
CFG_GLUETUN_CONTROL_SERVER_API_KEY_1=RANDOMIZEDPASSWORD1
|
|
||||||
# HEALTH_TARGETS = comma-separated host:port list pinged over HTTPS to
|
# HEALTH_TARGETS = comma-separated host:port list pinged over HTTPS to
|
||||||
# confirm the VPN tunnel is healthy. Defaults are privacy-respecting
|
# confirm the VPN tunnel is healthy. Defaults are privacy-respecting
|
||||||
# (Mullvad — your VPN provider; EFF — privacy non-profit). Override
|
# (Mullvad — your VPN provider; EFF — privacy non-profit). Override
|
||||||
|
|||||||
@ -78,7 +78,7 @@ _stoatBaseUrl()
|
|||||||
# would create directories in their place) and again once the port is known.
|
# would create directories in their place) and again once the port is known.
|
||||||
_stoatWriteUrlFiles()
|
_stoatWriteUrlFiles()
|
||||||
{
|
{
|
||||||
local app_dir="$1" base="$2" video_enabled="$3"
|
local app_dir="$1" base="$2" video_enabled="$3" rabbit_pass="$4"
|
||||||
|
|
||||||
# ws:// for http, wss:// for https — a wss:// URL on a plain-HTTP origin
|
# ws:// for http, wss:// for https — a wss:// URL on a plain-HTTP origin
|
||||||
# fails to connect and the client hangs on "connecting".
|
# fails to connect and the client hangs on "connecting".
|
||||||
@ -192,31 +192,44 @@ stoat_install_post_compose()
|
|||||||
"$app_dir/data/caddy-data" "$app_dir/data/caddy-config")
|
"$app_dir/data/caddy-data" "$app_dir/data/caddy-config")
|
||||||
checkSuccess "Creating $app_name data folders"
|
checkSuccess "Creating $app_name data folders"
|
||||||
|
|
||||||
_stoatWriteSecrets "$app_dir/secrets.env"
|
# Ordering rule for everything below: every file bind-mounted into a
|
||||||
|
# container must be written before the first step that could fail. A missing
|
||||||
# Read the LiveKit credentials back out — either the ones just generated or
|
# mount source is not a soft failure — docker either creates a directory in
|
||||||
# the ones preserved from a previous install — because livekit.yml has to
|
# its place or refuses to start the container, and both outcomes outlive the
|
||||||
# carry the same pair the API is configured with.
|
# install and break every later run.
|
||||||
local livekit_key livekit_secret
|
result=$(copyResource "$app_name" "Caddyfile" "" | runInstallWrite -a "$logs_dir/$docker_log_file" 2>&1)
|
||||||
livekit_key=$(grep -oP "REVOLT__API__LIVEKIT__NODES__WORLDWIDE__KEY='\K[^']*" "$app_dir/secrets.env" 2>/dev/null)
|
checkSuccess "Copying Caddyfile to $app_dir"
|
||||||
livekit_secret=$(grep -oP "REVOLT__API__LIVEKIT__NODES__WORLDWIDE__SECRET='\K[^']*" "$app_dir/secrets.env" 2>/dev/null)
|
|
||||||
if [[ -z "$livekit_key" || -z "$livekit_secret" ]]; then
|
|
||||||
isError "Could not read the LiveKit credentials from secrets.env — voice will not work."
|
|
||||||
return 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
local video_enabled=""
|
local video_enabled=""
|
||||||
[[ "$CFG_STOAT_ENABLE_VIDEO" != "false" ]] && video_enabled="true"
|
[[ "$CFG_STOAT_ENABLE_VIDEO" != "false" ]] && video_enabled="true"
|
||||||
|
|
||||||
# The port is not allocated yet, so this is a guess whenever there is no
|
# The port is not allocated yet, so this is a guess whenever there is no
|
||||||
# domain. The files still have to exist now: they are bind-mounted, and
|
# domain; stoat_install_post_start rewrites these once it is known.
|
||||||
# docker would silently create directories in their place otherwise.
|
|
||||||
# stoat_install_post_start rewrites them once the real port is known.
|
|
||||||
local base
|
local base
|
||||||
base=$(_stoatBaseUrl "$app_name")
|
base=$(_stoatBaseUrl "$app_name")
|
||||||
_stoatWriteUrlFiles "$app_dir" "$base" "$video_enabled"
|
_stoatWriteUrlFiles "$app_dir" "$base" "$video_enabled"
|
||||||
checkSuccess "Writing .env.web, stoat.json and Revolt.toml for $base"
|
checkSuccess "Writing .env.web, stoat.json and Revolt.toml for $base"
|
||||||
|
|
||||||
|
_stoatWriteSecrets "$app_dir/secrets.env"
|
||||||
|
|
||||||
|
# Read the LiveKit credentials back out — either the ones just generated or
|
||||||
|
# the ones preserved from a previous install — because livekit.yml has to
|
||||||
|
# carry the same pair the API is configured with.
|
||||||
|
#
|
||||||
|
# Read via runFileOp: secrets.env is chmod 600 and owned by the docker
|
||||||
|
# install user, while these hooks run as the manager, so a plain grep gets
|
||||||
|
# EACCES and silently yields nothing.
|
||||||
|
local livekit_key livekit_secret
|
||||||
|
livekit_key=$(runFileOp grep -oP "REVOLT__API__LIVEKIT__NODES__WORLDWIDE__KEY='\K[^']*" "$app_dir/secrets.env" 2>/dev/null)
|
||||||
|
livekit_secret=$(runFileOp grep -oP "REVOLT__API__LIVEKIT__NODES__WORLDWIDE__SECRET='\K[^']*" "$app_dir/secrets.env" 2>/dev/null)
|
||||||
|
if [[ -z "$livekit_key" || -z "$livekit_secret" ]]; then
|
||||||
|
# Deliberately not fatal. livekit.yml still gets written below so the
|
||||||
|
# bind mount is a file; voice is broken until the keys are fixed, but
|
||||||
|
# the other fifteen services come up and text chat works.
|
||||||
|
isError "Could not read the LiveKit credentials from secrets.env — voice will not work."
|
||||||
|
isNotice "Fix the keys in $app_dir/secrets.env and livekit.yml, then restart $app_name."
|
||||||
|
fi
|
||||||
|
|
||||||
# use_external_ip lets LiveKit discover the address to advertise for WebRTC.
|
# use_external_ip lets LiveKit discover the address to advertise for WebRTC.
|
||||||
# The port range matches the literal UDP mapping in the compose file; change
|
# The port range matches the literal UDP mapping in the compose file; change
|
||||||
# one and you must change the other.
|
# one and you must change the other.
|
||||||
@ -243,9 +256,6 @@ webhook:
|
|||||||
EOF
|
EOF
|
||||||
checkSuccess "Writing livekit.yml"
|
checkSuccess "Writing livekit.yml"
|
||||||
|
|
||||||
result=$(copyResource "$app_name" "Caddyfile" "" | runInstallWrite -a "$logs_dir/$docker_log_file" 2>&1)
|
|
||||||
checkSuccess "Copying Caddyfile to $app_dir"
|
|
||||||
|
|
||||||
runFileOp chown -R "$docker_install_user":"$docker_install_user" "$app_dir"
|
runFileOp chown -R "$docker_install_user":"$docker_install_user" "$app_dir"
|
||||||
checkSuccess "Setting ownership on the $app_name install directory"
|
checkSuccess "Setting ownership on the $app_name install directory"
|
||||||
}
|
}
|
||||||
|
|||||||
@ -88,4 +88,3 @@ CFG_TRAEFIK_PORT_3="traefik-service|http|80:80|disabled|tcp|false|false|false|HT
|
|||||||
# AUTH_PROFILE = capability tier for the WebUI auth tools (single_password | user_password | multi_user)
|
# AUTH_PROFILE = capability tier for the WebUI auth tools (single_password | user_password | multi_user)
|
||||||
CFG_TRAEFIK_AUTH_PROFILE=single_password
|
CFG_TRAEFIK_AUTH_PROFILE=single_password
|
||||||
CFG_TRAEFIK_ADMIN_USER=
|
CFG_TRAEFIK_ADMIN_USER=
|
||||||
CFG_TRAEFIK_ADMIN_PASSWORD_1=RANDOMIZEDPASSWORD1
|
|
||||||
|
|||||||
@ -160,8 +160,8 @@ are preserved from then on.
|
|||||||
|
|
||||||
The convention is now uniform: **if a config key holds a generated value, its name
|
The convention is now uniform: **if a config key holds a generated value, its name
|
||||||
ends in a slot number.** `CFG_<APP>_DB_PASSWORD` became
|
ends in a slot number.** `CFG_<APP>_DB_PASSWORD` became
|
||||||
`CFG_<APP>_DB_PASSWORD_1`, `CFG_TRAEFIK_ADMIN_PASSWORD` became
|
`CFG_<APP>_DB_PASSWORD_1`, `CFG_GITEA_ADMIN_PASSWORD` became
|
||||||
`CFG_TRAEFIK_ADMIN_PASSWORD_1`, and so on — 42 keys across the catalog. An app
|
`CFG_GITEA_ADMIN_PASSWORD_1`, and so on — 40 keys across the catalog. An app
|
||||||
that needs a second credential of the same kind just adds `_2`; nothing has to be
|
that needs a second credential of the same kind just adds `_2`; nothing has to be
|
||||||
registered, because the tag name is derived from the key.
|
registered, because the tag name is derived from the key.
|
||||||
|
|
||||||
|
|||||||
@ -36,12 +36,39 @@ authAdapterCall() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
# Persist a value to CFG_<APP>_<KEY> in the per-app config file.
|
# Persist a value to CFG_<APP>_<KEY> in the per-app config file.
|
||||||
|
#
|
||||||
|
# Adapters call with the bare name (ADMIN_PASSWORD), but a key whose value is
|
||||||
|
# generated carries a slot number (CFG_<APP>_ADMIN_PASSWORD_1). Resolve to the
|
||||||
|
# slot when the bare key isn't there, so an adapter never has to know how a
|
||||||
|
# credential is numbered — and so adding a slot to a config can't quietly
|
||||||
|
# disconnect the adapter that writes it.
|
||||||
|
#
|
||||||
|
# updateConfigOption only rewrites a key that already exists; handed a name that
|
||||||
|
# is absent it just prints a notice. That is a silent failure from the caller's
|
||||||
|
# side: the app's password really did change, but the config and the WebUI carry
|
||||||
|
# on showing the old one. Hence the explicit return 1 and warning below.
|
||||||
authPersistCfg() {
|
authPersistCfg() {
|
||||||
local app="$1" key="$2" value="$3"
|
local app="$1" key="$2" value="$3"
|
||||||
local cfg="${containers_dir}${app}/${app}.config"
|
local cfg="${containers_dir}${app}/${app}.config"
|
||||||
[[ ! -f "$cfg" ]] && cfg="${install_containers_dir}/${app}/${app}.config"
|
[[ ! -f "$cfg" ]] && cfg="${install_containers_dir}/${app}/${app}.config"
|
||||||
[[ ! -f "$cfg" ]] && return 1
|
[[ ! -f "$cfg" ]] && return 1
|
||||||
updateConfigOption "CFG_${app^^}_${key}" "$value" "$cfg"
|
|
||||||
|
local app_upper="${app^^}"
|
||||||
|
app_upper="${app_upper//-/_}"
|
||||||
|
local name="CFG_${app_upper}_${key}"
|
||||||
|
|
||||||
|
if ! grep -q "^${name}=" "$cfg" 2>/dev/null; then
|
||||||
|
local slotted
|
||||||
|
slotted=$(grep -oE "^CFG_${app_upper}_${key}_[0-9]+=" "$cfg" 2>/dev/null | head -1)
|
||||||
|
if [[ -n "$slotted" ]]; then
|
||||||
|
name="${slotted%=}"
|
||||||
|
else
|
||||||
|
isNotice "$app has no ${name} (or numbered slot) in $(basename "$cfg") — the new value was applied to the app but not recorded in its config."
|
||||||
|
return 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
updateConfigOption "$name" "$value" "$cfg"
|
||||||
}
|
}
|
||||||
|
|
||||||
# Read a tool-modal arg (pipe-encoded) and unescape pipes.
|
# Read a tool-modal arg (pipe-encoded) and unescape pipes.
|
||||||
|
|||||||
@ -525,12 +525,6 @@ PORTEOF
|
|||||||
"type": "password",
|
"type": "password",
|
||||||
"tooltip": "Password for the mailbox created on install"
|
"tooltip": "Password for the mailbox created on install"
|
||||||
},
|
},
|
||||||
"TRAEFIK_ADMIN_PASSWORD_1": {
|
|
||||||
"category": "general",
|
|
||||||
"label": "Traefik Admin Password",
|
|
||||||
"type": "password",
|
|
||||||
"tooltip": "Traefik dashboard password (auto-generated)"
|
|
||||||
},
|
|
||||||
"BOOKSTACK_APP_KEY_1": {
|
"BOOKSTACK_APP_KEY_1": {
|
||||||
"category": "advanced",
|
"category": "advanced",
|
||||||
"label": "Application Key",
|
"label": "Application Key",
|
||||||
@ -604,12 +598,6 @@ PORTEOF
|
|||||||
"type": "password",
|
"type": "password",
|
||||||
"tooltip": "Password for the seeded Authelia admin account"
|
"tooltip": "Password for the seeded Authelia admin account"
|
||||||
},
|
},
|
||||||
"GLUETUN_CONTROL_SERVER_API_KEY_1": {
|
|
||||||
"category": "general",
|
|
||||||
"label": "Control Server API Key",
|
|
||||||
"type": "password",
|
|
||||||
"tooltip": "API key for the gluetun HTTP control server (blank disables auth)"
|
|
||||||
},
|
|
||||||
"GLUETUN_VPN_SERVICE_PROVIDER": {
|
"GLUETUN_VPN_SERVICE_PROVIDER": {
|
||||||
"category": "general",
|
"category": "general",
|
||||||
"label": "VPN Provider",
|
"label": "VPN Provider",
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user