Files

296 lines
9.2 KiB
Bash
Executable File

#!/usr/bin/env bash
set -euo pipefail
repo_root="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
env_file="${repo_root}/.env.devprod"
source "${repo_root}/scripts/lib-compose-project.sh"
usage() {
cat <<USAGE
Usage: ./start-devprod.sh [options]
Starts the devprod stack using existing values in .env.devprod.
For first-time configuration, use:
./scripts/install-production-docker.sh --guided
Or fully automatic bootstrap:
./scripts/install-production-docker.sh --one-click
Options:
--mode ssl|nossl Compose mode (default: nossl)
--ssl Alias for --mode ssl
--nossl Alias for --mode nossl
--extauth Force-enable external-auth profile
--no-extauth Force-disable external-auth profile
-h, --help Show this help
USAGE
}
read_kv() {
local key="$1"
local line
line="$(grep -m1 -E "^${key}=" "${env_file}" || true)"
if [[ -z "${line}" ]]; then
return 1
fi
echo "${line#*=}"
}
resolve_path_from_env() {
local key="$1"
local default_path="$2"
local value
value="$(read_kv "${key}" || true)"
value="${value:-${default_path}}"
if [[ "${value}" == /* ]]; then
echo "${value}"
else
echo "${repo_root}/${value}"
fi
}
verify_cron_container_user() {
local cron_uid
cron_uid="$(docker compose -f "${compose_file}" --env-file "${env_file}" exec -T cron id -u 2>/dev/null | tr -d '\r[:space:]' || true)"
if [[ "${cron_uid}" == "33" ]]; then
echo "Cron container user verified: 33 (www-data)."
return 0
fi
echo "Warning: cron container is running as UID ${cron_uid:-unknown}, expected 33 (www-data)."
echo "Recreate cron container to apply compose user settings:"
echo " docker compose -f ${compose_file} --env-file ${env_file} up -d --force-recreate --no-deps cron"
return 1
}
mode="nossl"
extauth="auto"
while [[ $# -gt 0 ]]; do
case "$1" in
--mode)
mode="${2:-}"
shift 2
;;
--mode=*)
mode="${1#*=}"
shift
;;
--ssl)
mode="ssl"
shift
;;
--nossl)
mode="nossl"
shift
;;
--extauth)
extauth="1"
shift
;;
--no-extauth)
extauth="0"
shift
;;
-h|--help)
usage
exit 0
;;
*)
echo "Unknown option: $1"
usage
exit 1
;;
esac
done
if [[ "${mode}" != "ssl" && "${mode}" != "nossl" ]]; then
echo "Invalid mode: ${mode}"
usage
exit 1
fi
if [[ ! -f "${env_file}" ]]; then
echo "Missing ${env_file}."
echo "Run: ./scripts/install-production-docker.sh --guided"
exit 1
fi
if ! export_compose_project_name_from_env "${env_file}"; then
warn_missing_compose_project_name "${env_file}"
fi
compose_file="${repo_root}/docker-compose.devprod.nossl.yml"
if [[ "${mode}" == "ssl" ]]; then
compose_file="${repo_root}/docker-compose.devprod.yml"
fi
nextcloud_custom_apps_path="$(resolve_path_from_env "NEXTCLOUD_CUSTOM_APPS_PATH" "./nextcloud/custom_apps")"
mkdir -p "${repo_root}/nextcloud/html" "${repo_root}/nextcloud/data" "${nextcloud_custom_apps_path}" "${repo_root}/qortal/data"
if [[ -x "${repo_root}/scripts/ensure-user-oidc-app.sh" ]]; then
NEXTCLOUD_CUSTOM_APPS_PATH="${nextcloud_custom_apps_path}" "${repo_root}/scripts/ensure-user-oidc-app.sh"
fi
if [[ -x "${repo_root}/scripts/ensure-qortal-integration-app.sh" ]]; then
NEXTCLOUD_CUSTOM_APPS_PATH="${nextcloud_custom_apps_path}" "${repo_root}/scripts/ensure-qortal-integration-app.sh"
fi
if [[ -x "${repo_root}/scripts/ensure-qortal-settings.sh" ]]; then
"${repo_root}/scripts/ensure-qortal-settings.sh"
fi
if [[ -x "${repo_root}/scripts/ensure-qortal-start-args.sh" ]]; then
"${repo_root}/scripts/ensure-qortal-start-args.sh" "${env_file}"
fi
if [[ -x "${repo_root}/scripts/select-qortal-p2p-port.sh" ]]; then
"${repo_root}/scripts/select-qortal-p2p-port.sh" "${env_file}"
fi
if [[ -f "${repo_root}/scripts/ensure-broker-internal-token.sh" ]]; then
bash "${repo_root}/scripts/ensure-broker-internal-token.sh" "${env_file}"
fi
if [[ -x "${repo_root}/scripts/ensure-oidc-signing-key.sh" ]]; then
"${repo_root}/scripts/ensure-oidc-signing-key.sh" "${env_file}"
fi
if [[ -x "${repo_root}/scripts/sync-public-env-urls.sh" ]]; then
"${repo_root}/scripts/sync-public-env-urls.sh" \
--env-file "${env_file}" \
--mode "${mode}"
fi
broker_internal_api_token="$(read_kv "BROKER_INTERNAL_API_TOKEN" || true)"
if [[ -z "${broker_internal_api_token}" ]]; then
echo "BROKER_INTERNAL_API_TOKEN is missing in ${env_file}"
echo "Run: bash scripts/ensure-broker-internal-token.sh ${env_file}"
exit 1
fi
export BROKER_INTERNAL_API_TOKEN="${broker_internal_api_token}"
broker_cors_allowed_origins="$(read_kv "BROKER_CORS_ALLOWED_ORIGINS" || true)"
export BROKER_CORS_ALLOWED_ORIGINS="${broker_cors_allowed_origins:-}"
echo "Broker auth env loaded from ${env_file}: token_set=yes cors_origins=${broker_cors_allowed_origins:-<empty>}"
current_profiles=""
if command -v rg >/dev/null 2>&1; then
profiles_line="$(rg -m1 '^COMPOSE_PROFILES=' "${env_file}" || true)"
else
profiles_line="$(grep -m1 -E '^COMPOSE_PROFILES=' "${env_file}" || true)"
fi
if [[ -n "${profiles_line}" ]]; then
current_profiles="${profiles_line#COMPOSE_PROFILES=}"
fi
if [[ "${extauth}" == "1" ]]; then
if [[ -z "${current_profiles}" ]]; then
current_profiles="external-auth"
elif [[ ",${current_profiles}," != *",external-auth,"* ]]; then
current_profiles="${current_profiles},external-auth"
fi
elif [[ "${extauth}" == "0" ]]; then
filtered=()
IFS=',' read -r -a profile_parts <<< "${current_profiles}"
for p in "${profile_parts[@]}"; do
p_trimmed="$(echo "${p}" | tr -d '[:space:]')"
[[ -z "${p_trimmed}" ]] && continue
[[ "${p_trimmed}" == "external-auth" ]] && continue
filtered+=("${p_trimmed}")
done
current_profiles="$(IFS=','; echo "${filtered[*]}")"
else
external_auth_base_url="$(read_kv "QORTAL_EXTERNAL_AUTH_BASE_URL" || true)"
if [[ "${external_auth_base_url}" == *"external_auth"* ]]; then
if [[ -z "${current_profiles}" ]]; then
current_profiles="external-auth"
elif [[ ",${current_profiles}," != *",external-auth,"* ]]; then
current_profiles="${current_profiles},external-auth"
fi
fi
fi
if [[ -n "${current_profiles}" ]]; then
export COMPOSE_PROFILES="${current_profiles}"
else
unset COMPOSE_PROFILES || true
fi
echo "Using compose file: ${compose_file}"
echo "Using profiles: ${COMPOSE_PROFILES:-<none>}"
echo "Starting stack..."
if [[ "${mode}" == "ssl" ]]; then
if [[ -n "${COMPOSE_PROFILES:-}" ]]; then
(cd "${repo_root}" && COMPOSE_PROFILES="${COMPOSE_PROFILES}" make up-devprod)
else
(cd "${repo_root}" && make up-devprod)
fi
else
if [[ -n "${COMPOSE_PROFILES:-}" ]]; then
(cd "${repo_root}" && COMPOSE_PROFILES="${COMPOSE_PROFILES}" make up-devprod-nossl)
else
(cd "${repo_root}" && make up-devprod-nossl)
fi
fi
if [[ -x "${repo_root}/scripts/ensure-nextcloud-apps-writable.sh" ]]; then
if ! "${repo_root}/scripts/ensure-nextcloud-apps-writable.sh" --mode "${mode}" --env-file "${env_file}"; then
echo "Warning: could not guarantee Nextcloud apps directory writeability."
echo "Apps page and app install/update operations may fail until fixed."
fi
fi
verify_cron_container_user || true
cron_mode_status=1
for _ in $(seq 1 18); do
if docker compose -f "${compose_file}" --env-file "${env_file}" exec -T --user www-data app php occ status >/dev/null 2>&1; then
if docker compose -f "${compose_file}" --env-file "${env_file}" exec -T --user www-data app php occ config:system:set backgroundjobs_mode --value=cron >/dev/null 2>&1; then
cron_mode_status=0
fi
break
fi
sleep 5
done
if [[ "${cron_mode_status}" -eq 0 ]]; then
echo "Nextcloud background jobs mode set to cron."
else
echo "Warning: could not set Nextcloud background jobs mode to cron yet."
echo "Run manually once OCC is ready:"
echo " docker compose -f ${compose_file} --env-file ${env_file} exec -T --user www-data app php occ config:system:set backgroundjobs_mode --value=cron"
fi
nextcloud_url_sync_status=0
if [[ -x "${repo_root}/scripts/ensure-nextcloud-url-config.sh" ]]; then
set +e
"${repo_root}/scripts/ensure-nextcloud-url-config.sh" \
--compose-file "${compose_file}" \
--env-file "${env_file}"
nextcloud_url_sync_status=$?
set -e
fi
if [[ "${nextcloud_url_sync_status}" -eq 0 ]]; then
echo "Nextcloud URL config synchronized from ${env_file}."
else
echo "Warning: could not synchronize Nextcloud URL config from ${env_file}."
echo "Run manually once OCC is ready:"
echo " ./scripts/ensure-nextcloud-url-config.sh --compose-file ${compose_file} --env-file ${env_file}"
fi
qortal_runtime_sync_status=0
if [[ -x "${repo_root}/scripts/ensure-qortal-integration-runtime-config.sh" ]]; then
set +e
"${repo_root}/scripts/ensure-qortal-integration-runtime-config.sh" \
--compose-file "${compose_file}" \
--env-file "${env_file}" >/dev/null 2>&1
qortal_runtime_sync_status=$?
set -e
fi
if [[ "${qortal_runtime_sync_status}" -eq 0 ]]; then
echo "NuQloud identity provider runtime config synchronized from ${env_file}."
else
echo "Warning: could not synchronize NuQloud identity provider runtime config yet."
echo "Run manually once OCC and broker are ready:"
echo " ./scripts/ensure-qortal-integration-runtime-config.sh --compose-file ${compose_file} --env-file ${env_file}"
fi
echo
echo "Done."