319 lines
8.4 KiB
Bash
Executable File
319 lines
8.4 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
repo_root="$(cd "${script_dir}/.." && pwd)"
|
|
|
|
global_caddy_dir="/srv/global-caddy"
|
|
container_name="global_caddy"
|
|
upstream_host="host.docker.internal"
|
|
bootstrap_mode="auto"
|
|
public_https_port="443"
|
|
instance_dirs=()
|
|
|
|
usage() {
|
|
cat <<'USAGE'
|
|
Usage: ./scripts/setup-shared-host-global-caddy.sh [options]
|
|
|
|
Configures one shared/global Caddy container for multiple repo-based cloud instances
|
|
running the no-SSL stack on the same host.
|
|
|
|
Options:
|
|
--instance-dir <path> Cloud repo directory to configure (repeatable)
|
|
--global-caddy-dir <path> Shared Caddy config dir (default: /srv/global-caddy)
|
|
--container-name <name> Shared Caddy container name (default: global_caddy)
|
|
--upstream-host <host> Upstream host for global Caddy (default: host.docker.internal)
|
|
--public-https-port <n> Public HTTPS port served by shared Caddy (default: 443)
|
|
--bootstrap Force bootstrap/start behavior for the shared Caddy target
|
|
--no-bootstrap Assume shared Caddy already exists
|
|
-h, --help Show this help
|
|
|
|
If no --instance-dir values are supplied, the script prompts for them interactively.
|
|
USAGE
|
|
}
|
|
|
|
resolve_path() {
|
|
local raw_path="$1"
|
|
if [[ "${raw_path}" == /* ]]; then
|
|
echo "${raw_path}"
|
|
else
|
|
echo "${PWD}/${raw_path}"
|
|
fi
|
|
}
|
|
|
|
read_kv() {
|
|
local env_file="$1"
|
|
local key="$2"
|
|
local line
|
|
line="$(grep -m1 -E "^${key}=" "${env_file}" || true)"
|
|
if [[ -z "${line}" ]]; then
|
|
return 1
|
|
fi
|
|
echo "${line#*=}"
|
|
}
|
|
|
|
set_kv() {
|
|
local env_file="$1"
|
|
local key="$2"
|
|
local value="$3"
|
|
local esc
|
|
esc="${value//\\/\\\\}"
|
|
esc="${esc//&/\\&}"
|
|
esc="${esc//|/\\|}"
|
|
if grep -q -E "^${key}=" "${env_file}"; then
|
|
sed -i -E "s|^${key}=.*|${key}=${esc}|" "${env_file}"
|
|
else
|
|
printf '\n%s=%s\n' "${key}" "${value}" >> "${env_file}"
|
|
fi
|
|
}
|
|
|
|
trim_csv() {
|
|
local raw="${1:-}"
|
|
local cleaned
|
|
cleaned="$(echo "${raw}" | tr -d '[:space:]')"
|
|
cleaned="${cleaned#,}"
|
|
cleaned="${cleaned%,}"
|
|
echo "${cleaned}"
|
|
}
|
|
|
|
profile_enabled() {
|
|
local profiles="$1"
|
|
local name="$2"
|
|
[[ ",${profiles}," == *",${name},"* ]]
|
|
}
|
|
|
|
prompt_instance_dirs() {
|
|
local answer=""
|
|
echo "Enter cloud repo directories one per line. Leave blank when finished."
|
|
while true; do
|
|
read -r -p "Instance repo directory: " answer || true
|
|
answer="${answer//[$'\r\n']}"
|
|
if [[ -z "${answer}" ]]; then
|
|
break
|
|
fi
|
|
instance_dirs+=("$(resolve_path "${answer}")")
|
|
done
|
|
}
|
|
|
|
run_in_repo() {
|
|
local repo_dir="$1"
|
|
shift
|
|
(cd "${repo_dir}" && "$@")
|
|
}
|
|
|
|
configure_instance_env() {
|
|
local repo_dir="$1"
|
|
local env_file="${repo_dir}/.env.devprod"
|
|
local profiles gateway_url
|
|
|
|
profiles="$(trim_csv "$(read_kv "${env_file}" "COMPOSE_PROFILES" || true)")"
|
|
set_kv "${env_file}" "EXTERNAL_PROXY_MODE" "global-caddy"
|
|
set_kv "${env_file}" "PUBLIC_HTTPS_PORT" "${public_https_port}"
|
|
set_kv "${env_file}" "DEVPROD_HTTP_BIND_HOST" "0.0.0.0"
|
|
set_kv "${env_file}" "DEVPROD_BROKER_BIND_HOST" "0.0.0.0"
|
|
|
|
if profile_enabled "${profiles}" "office"; then
|
|
set_kv "${env_file}" "COLLABORA_BIND_HOST" "0.0.0.0"
|
|
fi
|
|
if profile_enabled "${profiles}" "recording"; then
|
|
set_kv "${env_file}" "TALK_RECORDING_BIND_HOST" "0.0.0.0"
|
|
fi
|
|
|
|
gateway_url="$(read_kv "${env_file}" "QORTAL_PUBLIC_GATEWAY_URL" || true)"
|
|
if [[ -z "${gateway_url}" ]]; then
|
|
gateway_url="$(read_kv "${env_file}" "QORTAL_GATEWAY_PUBLIC_URL" || true)"
|
|
fi
|
|
if [[ -z "${gateway_url}" ]]; then
|
|
gateway_url="$(read_kv "${env_file}" "QORTAL_GATEWAY_URL" || true)"
|
|
fi
|
|
|
|
if [[ -z "${gateway_url}" && -t 0 ]]; then
|
|
read -r -p "Optional public Qortal gateway URL for ${repo_dir} (blank to skip): " gateway_url || true
|
|
gateway_url="${gateway_url//[$'\r\n']}"
|
|
if [[ -n "${gateway_url}" ]]; then
|
|
set_kv "${env_file}" "QORTAL_PUBLIC_GATEWAY_URL" "${gateway_url}"
|
|
fi
|
|
fi
|
|
|
|
if [[ -n "${gateway_url}" ]]; then
|
|
set_kv "${env_file}" "QORTAL_NODE_GATEWAY_BIND_HOST" "0.0.0.0"
|
|
fi
|
|
}
|
|
|
|
ensure_instance_layout() {
|
|
local repo_dir="$1"
|
|
local required=(
|
|
".env.devprod"
|
|
"stop-devprod.sh"
|
|
"recreate-devprod.sh"
|
|
"scripts/register-global-caddy-proxy.sh"
|
|
"scripts/ensure-nextcloud-url-config.sh"
|
|
)
|
|
local path
|
|
|
|
if [[ ! -d "${repo_dir}" ]]; then
|
|
echo "Instance repo directory not found: ${repo_dir}"
|
|
exit 1
|
|
fi
|
|
|
|
for path in "${required[@]}"; do
|
|
if [[ ! -e "${repo_dir}/${path}" ]]; then
|
|
echo "Missing required file in ${repo_dir}: ${path}"
|
|
exit 1
|
|
fi
|
|
done
|
|
}
|
|
|
|
while [[ $# -gt 0 ]]; do
|
|
case "$1" in
|
|
--instance-dir)
|
|
instance_dirs+=("$(resolve_path "${2:-}")")
|
|
shift 2
|
|
;;
|
|
--instance-dir=*)
|
|
instance_dirs+=("$(resolve_path "${1#*=}")")
|
|
shift
|
|
;;
|
|
--global-caddy-dir)
|
|
global_caddy_dir="$(resolve_path "${2:-}")"
|
|
shift 2
|
|
;;
|
|
--global-caddy-dir=*)
|
|
global_caddy_dir="$(resolve_path "${1#*=}")"
|
|
shift
|
|
;;
|
|
--container-name)
|
|
container_name="${2:-}"
|
|
shift 2
|
|
;;
|
|
--container-name=*)
|
|
container_name="${1#*=}"
|
|
shift
|
|
;;
|
|
--upstream-host)
|
|
upstream_host="${2:-}"
|
|
shift 2
|
|
;;
|
|
--upstream-host=*)
|
|
upstream_host="${1#*=}"
|
|
shift
|
|
;;
|
|
--public-https-port)
|
|
public_https_port="${2:-}"
|
|
shift 2
|
|
;;
|
|
--public-https-port=*)
|
|
public_https_port="${1#*=}"
|
|
shift
|
|
;;
|
|
--bootstrap)
|
|
bootstrap_mode="1"
|
|
shift
|
|
;;
|
|
--no-bootstrap)
|
|
bootstrap_mode="0"
|
|
shift
|
|
;;
|
|
-h|--help)
|
|
usage
|
|
exit 0
|
|
;;
|
|
*)
|
|
echo "Unknown option: $1"
|
|
usage
|
|
exit 1
|
|
;;
|
|
esac
|
|
done
|
|
|
|
if [[ "${#instance_dirs[@]}" -eq 0 ]]; then
|
|
if [[ -t 0 ]]; then
|
|
prompt_instance_dirs
|
|
fi
|
|
fi
|
|
|
|
if [[ "${#instance_dirs[@]}" -eq 0 ]]; then
|
|
echo "No instance directories provided."
|
|
usage
|
|
exit 1
|
|
fi
|
|
|
|
if [[ "${bootstrap_mode}" == "auto" ]]; then
|
|
if [[ -f "${global_caddy_dir}/docker-compose.yml" ]]; then
|
|
bootstrap_mode="0"
|
|
else
|
|
bootstrap_mode="1"
|
|
fi
|
|
fi
|
|
|
|
echo "Shared Caddy target: ${global_caddy_dir}"
|
|
echo "Shared Caddy container: ${container_name}"
|
|
echo "Upstream host: ${upstream_host}"
|
|
echo "Public HTTPS port: ${public_https_port}"
|
|
echo "Bootstrap shared Caddy: ${bootstrap_mode}"
|
|
echo
|
|
|
|
for repo_dir in "${instance_dirs[@]}"; do
|
|
ensure_instance_layout "${repo_dir}"
|
|
echo "Configuring instance: ${repo_dir}"
|
|
|
|
configure_instance_env "${repo_dir}"
|
|
|
|
echo " Stopping bundled SSL stack if present..."
|
|
run_in_repo "${repo_dir}" ./stop-devprod.sh --ssl || true
|
|
|
|
echo " Recreating no-SSL stack..."
|
|
run_in_repo "${repo_dir}" ./recreate-devprod.sh --nossl
|
|
|
|
echo " Registering instance in shared Caddy..."
|
|
if [[ "${bootstrap_mode}" == "1" ]]; then
|
|
run_in_repo "${repo_dir}" ./scripts/register-global-caddy-proxy.sh \
|
|
--env-file .env.devprod \
|
|
--target-dir "${global_caddy_dir}" \
|
|
--upstream-host "${upstream_host}" \
|
|
--bootstrap \
|
|
--start \
|
|
--reload \
|
|
--container-name "${container_name}"
|
|
bootstrap_mode="0"
|
|
else
|
|
run_in_repo "${repo_dir}" ./scripts/register-global-caddy-proxy.sh \
|
|
--env-file .env.devprod \
|
|
--target-dir "${global_caddy_dir}" \
|
|
--upstream-host "${upstream_host}" \
|
|
--reload \
|
|
--container-name "${container_name}"
|
|
fi
|
|
|
|
echo " Syncing Nextcloud URL/proxy config..."
|
|
run_in_repo "${repo_dir}" ./scripts/ensure-nextcloud-url-config.sh \
|
|
--compose-file docker-compose.devprod.nossl.yml \
|
|
--env-file .env.devprod
|
|
|
|
if [[ -x "${repo_dir}/scripts/ensure-qortal-integration-runtime-config.sh" ]]; then
|
|
echo " Syncing qortal_integration runtime config..."
|
|
run_in_repo "${repo_dir}" ./scripts/ensure-qortal-integration-runtime-config.sh \
|
|
--compose-file docker-compose.devprod.nossl.yml \
|
|
--env-file .env.devprod
|
|
fi
|
|
|
|
if [[ -x "${repo_dir}/scripts/ensure-nextcloud-office-config.sh" ]]; then
|
|
echo " Validating Office/Collabora configuration..."
|
|
run_in_repo "${repo_dir}" ./scripts/ensure-nextcloud-office-config.sh \
|
|
--compose-file docker-compose.devprod.nossl.yml \
|
|
--env-file .env.devprod
|
|
fi
|
|
|
|
if [[ -x "${repo_dir}/scripts/ensure-nextcloud-talk-config.sh" ]]; then
|
|
echo " Validating Talk HPB/recording configuration..."
|
|
run_in_repo "${repo_dir}" ./scripts/ensure-nextcloud-talk-config.sh \
|
|
--compose-file docker-compose.devprod.nossl.yml \
|
|
--env-file .env.devprod
|
|
fi
|
|
|
|
echo " Completed: ${repo_dir}"
|
|
echo
|
|
done
|
|
|
|
echo "Shared-host global Caddy setup complete."
|