diff --git a/production/scripts/docker-prod-common.sh b/production/scripts/docker-prod-common.sh index 1066c57..c02e696 100755 --- a/production/scripts/docker-prod-common.sh +++ b/production/scripts/docker-prod-common.sh @@ -71,6 +71,39 @@ export_env_value_if_unset() { fi } +export_compose_env_from_file() { + local line key value + + while IFS= read -r line || [[ -n "${line}" ]]; do + line="${line%$'\r'}" + + [[ -z "${line//[[:space:]]/}" || "${line}" =~ ^[[:space:]]*# ]] && continue + + line="${line#"${line%%[![:space:]]*}"}" + line="${line#export }" + + [[ "${line}" == *"="* ]] || continue + + key="${line%%=*}" + value="${line#*=}" + key="${key//[[:space:]]/}" + value="${value#"${value%%[![:space:]]*}"}" + value="${value%"${value##*[![:space:]]}"}" + + if [[ "${value}" == \"*\" && "${value}" == *\" ]]; then + value="${value#\"}" + value="${value%\"}" + elif [[ "${value}" == \'*\' && "${value}" == *\' ]]; then + value="${value#\'}" + value="${value%\'}" + fi + + if [[ "${key}" =~ ^[A-Za-z_][A-Za-z0-9_]*$ ]]; then + export "${key}=${value}" + fi + done < "${ENV_FILE}" +} + load_prod_env_exports() { local key @@ -148,10 +181,12 @@ ensure_api_uploads_volume() { } prod_compose() { + export_compose_env_from_file APP_ENV_FILE="${ENV_FILE}" DOCKER_PROD_API_UPLOADS_VOLUME="${API_UPLOADS_VOLUME}" docker compose -p "${PROJECT_NAME}" --env-file "${ENV_FILE}" -f "${PROD_COMPOSE_FILE}" "$@" } traefik_compose() { + export_compose_env_from_file docker compose --env-file "${ENV_FILE}" -f "${TRAEFIK_COMPOSE_FILE}" "$@" } diff --git a/scripts/docker-prod-common.sh b/scripts/docker-prod-common.sh index e061356..a7193cf 100644 --- a/scripts/docker-prod-common.sh +++ b/scripts/docker-prod-common.sh @@ -66,10 +66,44 @@ export_env_value_if_unset() { fi } +export_compose_env_from_file() { + local line key value + + while IFS= read -r line || [[ -n "${line}" ]]; do + line="${line%$'\r'}" + + [[ -z "${line//[[:space:]]/}" || "${line}" =~ ^[[:space:]]*# ]] && continue + + line="${line#"${line%%[![:space:]]*}"}" + line="${line#export }" + + [[ "${line}" == *"="* ]] || continue + + key="${line%%=*}" + value="${line#*=}" + key="${key//[[:space:]]/}" + value="${value#"${value%%[![:space:]]*}"}" + value="${value%"${value##*[![:space:]]}"}" + + if [[ "${value}" == \"*\" && "${value}" == *\" ]]; then + value="${value#\"}" + value="${value%\"}" + elif [[ "${value}" == \'*\' && "${value}" == *\' ]]; then + value="${value#\'}" + value="${value%\'}" + fi + + if [[ "${key}" =~ ^[A-Za-z_][A-Za-z0-9_]*$ ]]; then + export "${key}=${value}" + fi + done < "${ENV_FILE}" +} + load_prod_env_exports() { local key for key in \ + ACME_EMAIL \ APP_IMAGE \ APP_VERSION \ IMAGE_TAG \ @@ -84,8 +118,9 @@ load_prod_env_exports() { } validate_prod_env_file() { - local api_domain public_site_domain cors_origins portainer_domain postgres_password redis_password jwt_secret + local acme_email api_domain public_site_domain cors_origins portainer_domain postgres_password redis_password jwt_secret + acme_email="$(read_env_value ACME_EMAIL)" api_domain="$(read_env_value API_DOMAIN)" public_site_domain="$(read_env_value PUBLIC_SITE_DOMAIN)" cors_origins="$(read_env_value CORS_ORIGINS)" @@ -94,6 +129,11 @@ validate_prod_env_file() { redis_password="$(read_env_value REDIS_PASSWORD)" jwt_secret="$(read_env_value JWT_SECRET)" + if [[ -z "${acme_email}" || "${acme_email}" != *@* || "${acme_email}" == *example.com* ]]; then + echo "Invalid ACME_EMAIL in ${ENV_FILE}. Set it to a real contact email for Let's Encrypt, not example.com." >&2 + exit 1 + fi + if [[ -z "${api_domain}" || "${api_domain}" == *example.com* ]]; then echo "Invalid API_DOMAIN in ${ENV_FILE}. Set it to the real production API hostname, not example.com." >&2 exit 1 @@ -144,18 +184,22 @@ ensure_dynamic_dir() { } prod_compose() { + export_compose_env_from_file APP_ENV_FILE="${ENV_FILE}" DOCKER_PROD_API_UPLOADS_VOLUME="${API_UPLOADS_VOLUME}" docker compose -p "${PROJECT_NAME}" --env-file "${ENV_FILE}" -f "${PROD_COMPOSE_FILE}" "$@" } portainer_compose() { + export_compose_env_from_file docker compose -p "${PORTAINER_PROJECT_NAME}" --env-file "${ENV_FILE}" -f "${PORTAINER_COMPOSE_FILE}" "$@" } registry_compose() { + export_compose_env_from_file docker compose -p "${REGISTRY_PROJECT_NAME}" --env-file "${ENV_FILE}" -f "${REGISTRY_COMPOSE_FILE}" "$@" } traefik_compose() { + export_compose_env_from_file docker compose --env-file "${ENV_FILE}" -f "${TRAEFIK_COMPOSE_FILE}" "$@" }