296 lines
9.2 KiB
Bash
Executable File
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."
|