fix and update

This commit is contained in:
lendry
2026-06-29 17:17:19 +03:00
parent 3fd5509186
commit e3c418d921

View File

@@ -10,7 +10,7 @@
set -euo pipefail set -euo pipefail
SCRIPT_VERSION="2.2.5" SCRIPT_VERSION="2.3.0"
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
cd "$ROOT_DIR" cd "$ROOT_DIR"
@@ -73,6 +73,7 @@ ${BOLD}Lendry ID v${SCRIPT_VERSION}${NC} — установка и управл
./install.sh --restart Перезапуск контейнеров ./install.sh --restart Перезапуск контейнеров
./install.sh --docker-prune Только очистка Docker (без пересборки) ./install.sh --docker-prune Только очистка Docker (без пересборки)
./install.sh --fix-proxy Исправить 502: host Nginx + порты 3000/3002/3003 ./install.sh --fix-proxy Исправить 502: host Nginx + порты 3000/3002/3003
./install.sh --fix-all Комплексное исправление: 502, прокси, порты, Nginx
./install.sh --status Статус сервисов ./install.sh --status Статус сервисов
./install.sh --reset-db Сброс PostgreSQL (новый пароль из .env, данные удалятся) ./install.sh --reset-db Сброс PostgreSQL (новый пароль из .env, данные удалятся)
./install.sh --remove-nginx Удалить конфиги Nginx IdP ./install.sh --remove-nginx Удалить конфиги Nginx IdP
@@ -146,6 +147,7 @@ parse_args() {
--skip-docker-prune) SKIP_DOCKER_PRUNE=1; shift ;; --skip-docker-prune) SKIP_DOCKER_PRUNE=1; shift ;;
--docker-prune-aggressive) DOCKER_PRUNE_AGGRESSIVE=1; shift ;; --docker-prune-aggressive) DOCKER_PRUNE_AGGRESSIVE=1; shift ;;
--fix-proxy) ACTION="fix-proxy"; shift ;; --fix-proxy) ACTION="fix-proxy"; shift ;;
--fix-all) ACTION="fix-all"; shift ;;
--status) ACTION="status"; shift ;; --status) ACTION="status"; shift ;;
--reset-db) ACTION="reset-db"; shift ;; --reset-db) ACTION="reset-db"; shift ;;
--local) INSTALL_LOCAL=1; shift ;; --local) INSTALL_LOCAL=1; shift ;;
@@ -253,6 +255,45 @@ lendry_host_nginx_configured() {
|| [[ -L "${NGINX_ENABLED}/${NGINX_PREFIX}-frontend.conf" ]] || [[ -L "${NGINX_ENABLED}/${NGINX_PREFIX}-frontend.conf" ]]
} }
docker_nginx_container_running() {
docker_cmd ps -q -f name=lendry-id-nginx 2>/dev/null | grep -q .
}
docker_nginx_ports_available() {
local http="${NGINX_HTTP_PORT:-80}"
local https="${NGINX_HTTPS_PORT:-443}"
! port_in_use "$http" && ! port_in_use "$https"
}
# Не даём контейнерному nginx занять 80/443, если их уже держит системный nginx
# или явно выбран NGINX_MODE=host (типичная причина «address already in use»).
ensure_docker_nginx_not_conflicting() {
load_env
resolve_nginx_mode_and_ports
local http="${NGINX_HTTP_PORT:-80}"
local https="${NGINX_HTTPS_PORT:-443}"
local ports_busy=0
port_in_use "$http" && ports_busy=1
port_in_use "$https" && ports_busy=1
if [[ "$ports_busy" -eq 1 ]] && [[ "$(env_get NGINX_MODE docker)" == "docker" ]]; then
if host_nginx_available || system_nginx_is_active || lendry_host_nginx_configured; then
warn "Порты ${http}/${https} заняты системным Nginx — переключаем NGINX_MODE на host"
warn "Контейнер lendry-id-nginx не будет запущен (используйте системный Nginx)"
NGINX_MODE="host"
env_set NGINX_MODE "host"
else
warn "Порты ${http}/${https} заняты другим процессом — Docker Nginx не сможет стартовать"
warn "Освободите порты или укажите другие: --nginx-http-port / --nginx-https-port"
fi
fi
if [[ "$(env_get NGINX_MODE docker)" == "host" ]] || [[ "$ports_busy" -eq 1 ]]; then
stop_docker_nginx
fi
}
stop_docker_nginx() { stop_docker_nginx() {
local cid local cid
cid="$(docker_cmd ps -q -f name=lendry-id-nginx 2>/dev/null || true)" cid="$(docker_cmd ps -q -f name=lendry-id-nginx 2>/dev/null || true)"
@@ -267,10 +308,7 @@ stop_docker_nginx() {
prepare_compose_stack() { prepare_compose_stack() {
resolve_nginx_mode_and_ports resolve_nginx_mode_and_ports
write_compose_override write_compose_override
load_env ensure_docker_nginx_not_conflicting
if [[ "$(env_get NGINX_MODE docker)" == "host" ]]; then
stop_docker_nginx
fi
} }
resolve_nginx_mode_and_ports() { resolve_nginx_mode_and_ports() {
@@ -299,7 +337,7 @@ resolve_nginx_mode_and_ports() {
if [[ "$NGINX_MODE" == "docker" ]]; then if [[ "$NGINX_MODE" == "docker" ]]; then
if port_in_use "$NGINX_HTTP_PORT" || port_in_use "$NGINX_HTTPS_PORT"; then if port_in_use "$NGINX_HTTP_PORT" || port_in_use "$NGINX_HTTPS_PORT"; then
if host_nginx_available && [[ "$NGINX_HTTP_PORT" == "80" ]]; then if host_nginx_available || system_nginx_is_active || lendry_host_nginx_configured; then
warn "Порт ${NGINX_HTTP_PORT}/${NGINX_HTTPS_PORT} занят — переключаемся на системный Nginx (host)" warn "Порт ${NGINX_HTTP_PORT}/${NGINX_HTTPS_PORT} занят — переключаемся на системный Nginx (host)"
NGINX_MODE="host" NGINX_MODE="host"
env_set NGINX_MODE "host" env_set NGINX_MODE "host"
@@ -350,6 +388,9 @@ compose_uses_proxy_profile() {
[[ -n "$(env_get DOMAIN_API "")" ]] || return 1 [[ -n "$(env_get DOMAIN_API "")" ]] || return 1
[[ "$(env_get INSTALL_MODE local)" == "local" ]] && return 1 [[ "$(env_get INSTALL_MODE local)" == "local" ]] && return 1
[[ "$(env_get NGINX_MODE docker)" == "docker" ]] || return 1 [[ "$(env_get NGINX_MODE docker)" == "docker" ]] || return 1
if ! docker_nginx_ports_available; then
return 1
fi
return 0 return 0
} }
@@ -529,9 +570,27 @@ compose_build_and_up() {
fi fi
configure_docker_build_env configure_docker_build_env
ensure_docker_nginx_not_conflicting
build_compose_stack_cmd build_compose_stack_cmd
compose_build_parallel_flags compose_build_parallel_flags
if [[ ${#services[@]} -gt 0 ]]; then
local -a filtered=()
local svc
for svc in "${services[@]}"; do
if [[ "$svc" == "nginx" ]] && ! compose_uses_proxy_profile; then
warn "Пропуск сервиса nginx: порты заняты или NGINX_MODE=host — используйте системный Nginx"
continue
fi
filtered+=("$svc")
done
services=("${filtered[@]}")
if [[ ${#services[@]} -eq 0 ]]; then
warn "Нет сервисов для запуска после проверки конфликта Nginx"
return 0
fi
fi
if [[ "${SKIP_DOCKER_PRUNE:-0}" -ne 1 ]]; then if [[ "${SKIP_DOCKER_PRUNE:-0}" -ne 1 ]]; then
docker_prune_before_rebuild "${DOCKER_PRUNE_AGGRESSIVE:-0}" docker_prune_before_rebuild "${DOCKER_PRUNE_AGGRESSIVE:-0}"
fi fi
@@ -548,6 +607,8 @@ compose_build_and_up() {
docker_cmd "${COMPOSE_STACK_CMD[@]}" up -d --remove-orphans docker_cmd "${COMPOSE_STACK_CMD[@]}" up -d --remove-orphans
fi fi
ensure_docker_nginx_not_conflicting
if [[ "${SKIP_DOCKER_PRUNE:-0}" -ne 1 ]]; then if [[ "${SKIP_DOCKER_PRUNE:-0}" -ne 1 ]]; then
docker_prune_after_rebuild docker_prune_after_rebuild
fi fi
@@ -2309,9 +2370,7 @@ setup_nginx_proxy() {
resolve_nginx_mode_and_ports resolve_nginx_mode_and_ports
write_compose_override write_compose_override
if [[ "$(env_get NGINX_MODE docker)" == "host" ]]; then ensure_docker_nginx_not_conflicting
stop_docker_nginx
fi
install_nginx_certbot install_nginx_certbot
local ssl_type local ssl_type
@@ -2494,11 +2553,90 @@ check_local_upstream() {
local label="$1" url="$2" local label="$1" url="$2"
if curl -fsS --max-time 3 "$url" >/dev/null 2>&1; then if curl -fsS --max-time 3 "$url" >/dev/null 2>&1; then
echo -e " ${GREEN}${NC} ${label}: ${url}" echo -e " ${GREEN}${NC} ${label}: ${url}"
return 0
else else
echo -e " ${RED}${NC} ${label}: ${url} — недоступен" echo -e " ${RED}${NC} ${label}: ${url} — недоступен"
return 1
fi fi
} }
# Диагностика типичных проблем: 502 на /idp-api, конфликт nginx, порты upstream.
diagnose_common_issues() {
load_env
local issues=0
echo ""
echo -e "${BOLD}Диагностика${NC}"
echo ""
if docker_nginx_container_running; then
if [[ "$(env_get NGINX_MODE docker)" == "host" ]] \
|| port_in_use "${NGINX_HTTP_PORT:-80}" \
|| port_in_use "${NGINX_HTTPS_PORT:-443}"; then
echo -e " ${RED}${NC} Конфликт: контейнер lendry-id-nginx запущен при занятых портах 80/443 или NGINX_MODE=host"
echo " Решение: ./install.sh --fix-all"
issues=$((issues + 1))
else
echo -e " ${GREEN}${NC} Docker Nginx: запущен (режим docker)"
fi
elif [[ "$(env_get NGINX_MODE docker)" == "docker" ]] && compose_uses_proxy_profile; then
echo -e " ${YELLOW}!${NC} Docker Nginx не запущен (ожидался в режиме docker)"
issues=$((issues + 1))
elif [[ "$(env_get NGINX_MODE docker)" == "host" ]]; then
if system_nginx_is_active; then
echo -e " ${GREEN}${NC} Системный Nginx: активен"
elif host_nginx_available; then
echo -e " ${YELLOW}!${NC} Системный Nginx установлен, но не активен — sudo systemctl start nginx"
issues=$((issues + 1))
else
echo -e " ${RED}${NC} NGINX_MODE=host, но системный Nginx не найден"
issues=$((issues + 1))
fi
fi
if [[ "$(env_get NGINX_MODE docker)" == "host" ]] \
&& [[ "$(env_get INSTALL_MODE local)" != "local" ]] \
&& [[ -n "$(env_get DOMAIN_API "")" ]]; then
local port
for port in 3000 3002 3003; do
if ! port_in_use "$port"; then
echo -e " ${RED}${NC} Порт 127.0.0.1:${port} не слушается — host Nginx получит 502"
issues=$((issues + 1))
fi
done
check_local_upstream "API /health" "http://127.0.0.1:3000/health" || issues=$((issues + 1))
check_local_upstream "Frontend" "http://127.0.0.1:3002" || issues=$((issues + 1))
check_local_upstream "Docs" "http://127.0.0.1:3003/docs" || issues=$((issues + 1))
if has_cmd nginx && [[ -f "${NGINX_ENABLED}/${NGINX_PREFIX}-frontend.conf" ]]; then
if run_root nginx -T 2>/dev/null | grep -q 'proxy_pass http://api-gateway:'; then
echo -e " ${RED}${NC} В конфиге host Nginx указан docker-hostname api-gateway — хост его не резолвит"
echo " Решение: ./install.sh --fix-all (перегенерирует proxy_pass на 127.0.0.1)"
issues=$((issues + 1))
elif run_root nginx -T 2>/dev/null | grep -q 'proxy_pass http://127.0.0.1:3000'; then
echo -e " ${GREEN}${NC} /idp-api проксируется на 127.0.0.1:3000"
fi
fi
fi
if docker_cmd ps --format '{{.Names}} {{.Status}}' 2>/dev/null | grep -E 'api-gateway.*(Restarting|unhealthy)' >/dev/null 2>&1; then
echo -e " ${RED}${NC} api-gateway unhealthy или перезапускается — проверьте: docker compose logs api-gateway"
issues=$((issues + 1))
elif docker_cmd ps --format '{{.Names}} {{.Status}}' 2>/dev/null | grep -q 'lendry-id-api-gateway.*Up'; then
echo -e " ${GREEN}${NC} api-gateway: контейнер запущен"
fi
echo ""
if [[ "$issues" -eq 0 ]]; then
ok "Критических проблем не обнаружено"
else
warn "Обнаружено проблем: ${issues}. Запустите: ./install.sh --fix-all"
fi
echo ""
return "$issues"
}
show_upstream_health() { show_upstream_health() {
load_env load_env
[[ "$(env_get NGINX_MODE docker)" != "host" ]] && return 0 [[ "$(env_get NGINX_MODE docker)" != "host" ]] && return 0
@@ -2538,14 +2676,14 @@ show_status() {
echo "" echo ""
if docker_cmd ps -q -f name=lendry-id-nginx 2>/dev/null | grep -q .; then if docker_cmd ps -q -f name=lendry-id-nginx 2>/dev/null | grep -q .; then
if [[ "$(env_get NGINX_MODE docker)" == "host" ]]; then if [[ "$(env_get NGINX_MODE docker)" == "host" ]]; then
warn "КОНФЛИКТ: контейнер lendry-id-nginx запущен при NGINX_MODE=host — выполните: ./install.sh --fix-proxy" warn "КОНФЛИКТ: контейнер lendry-id-nginx запущен при NGINX_MODE=host — выполните: ./install.sh --fix-all"
else else
echo " Docker Nginx: запущен (режим docker; curl 127.0.0.1:3002 не нужен)" echo " Docker Nginx: запущен (режим docker; curl 127.0.0.1:3002 не нужен)"
fi fi
fi fi
if [[ "$(env_get NGINX_MODE docker)" == "host" ]]; then if [[ "$(env_get NGINX_MODE docker)" == "host" ]]; then
docker_cmd port lendry-id-frontend 3000/tcp 2>/dev/null | sed 's/^/ frontend port: /' || \ docker_cmd port lendry-id-frontend 3000/tcp 2>/dev/null | sed 's/^/ frontend port: /' || \
warn "frontend не публикует 3000/tcp на хост — выполните: ./install.sh --fix-proxy" warn "frontend не публикует 3000/tcp на хост — выполните: ./install.sh --fix-all"
fi fi
echo "" echo ""
show_upstream_health show_upstream_health
@@ -2689,17 +2827,17 @@ action_fix_host_proxy() {
log "Исправление прокси (host Nginx + порты 127.0.0.1)..." log "Исправление прокси (host Nginx + порты 127.0.0.1)..."
log "Шаг 1/4: остановка Docker Nginx..." log "Шаг 1/5: остановка Docker Nginx и проверка портов..."
stop_docker_nginx ensure_docker_nginx_not_conflicting
log "Шаг 2/4: compose override (LDAP / Nginx)..." log "Шаг 2/5: compose override (LDAP / Nginx)..."
write_compose_override write_compose_override
log "Шаг 3/4: пересоздание api-gateway, frontend, docs, media-ws..." log "Шаг 3/5: пересоздание api-gateway, frontend, docs, media-ws..."
compose_build_and_up "${HOST_EDGE_SERVICES[@]}" compose_build_and_up "${HOST_EDGE_SERVICES[@]}"
ensure_host_upstreams ensure_host_upstreams
log "Шаг 4/4: конфиги системного Nginx..." log "Шаг 4/5: конфиги системного Nginx..."
refresh_host_nginx_configs refresh_host_nginx_configs
apply_intranet_selfsigned_runtime apply_intranet_selfsigned_runtime
@@ -2708,6 +2846,83 @@ action_fix_host_proxy() {
compose_build_and_up ldap-auth sso-core compose_build_and_up ldap-auth sso-core
ok "Прокси исправлен — проверьте: curl -I http://127.0.0.1:3002" ok "Прокси исправлен — проверьте: curl -I http://127.0.0.1:3002"
diagnose_common_issues || true
show_status
}
# Комплексное исправление: 502 на /idp-api, конфликт Docker/host Nginx, порты upstream,
# пересборка api-gateway после смены IP контейнера, актуализация конфигов Nginx.
action_fix_all_errors() {
[[ -f .env ]] || fail "Файл .env не найден — сначала выполните ./install.sh --install"
load_env
NON_INTERACTIVE=1
echo ""
echo -e "${BOLD}Комплексное исправление ошибок IdP${NC}"
echo " (502 Bad Gateway, /idp-api, конфликт Nginx, порты 3000/3002/3003)"
echo ""
log "Шаг 1/6: диагностика..."
diagnose_common_issues || true
log "Шаг 2/6: определение режима Nginx и устранение конфликта портов 80/443..."
resolve_nginx_mode_and_ports
ensure_docker_nginx_not_conflicting
write_compose_override
log "Шаг 3/6: пересборка api-gateway и sso-core..."
compose_build_and_up api-gateway sso-core
wait_for_service "sso-core" 120
wait_for_service "api-gateway" 90
log "Шаг 4/6: пересоздание edge-сервисов (frontend, docs, media-ws)..."
compose_build_and_up "${HOST_EDGE_SERVICES[@]}"
wait_for_service "frontend" 60
wait_for_service "docs" 60
if [[ "$(env_get NGINX_MODE docker)" == "host" ]]; then
log "Шаг 5/6: host Nginx — порты 127.0.0.1 и конфиги..."
ensure_host_upstreams
refresh_host_nginx_configs
apply_intranet_selfsigned_runtime
compose_build_and_up ldap-auth
else
log "Шаг 5/6: Docker Nginx — перегенерация конфигов и перезапуск..."
local ssl_type
ssl_type="$(env_get SSL_TYPE none)"
case "$ssl_type" in
none) write_nginx_http_only || warn "Не удалось записать HTTP-конфиги Nginx" ;;
selfsigned)
generate_all_self_signed_certs
write_all_nginx_configs "selfsigned" || warn "Не удалось обновить конфиги Nginx"
;;
custom)
install_custom_certificates
write_all_nginx_configs "custom" || warn "Не удалось обновить конфиги Nginx"
;;
letsencrypt)
write_all_nginx_configs "letsencrypt" || warn "Не удалось обновить конфиги Nginx"
;;
esac
if compose_uses_proxy_profile; then
compose_build_and_up nginx
wait_for_service "nginx" 30
else
warn "Docker Nginx не запущен — порты 80/443 заняты; используется системный Nginx"
env_set NGINX_MODE "host"
NGINX_MODE="host"
refresh_host_nginx_configs
fi
fi
log "Шаг 6/6: финальная проверка..."
diagnose_common_issues || true
ok "Исправление завершено"
echo ""
echo " Проверьте в браузере страницу после авторизации — запросы к /idp-api/* должны отвечать 200."
echo " Если ошибки остались: docker compose logs --tail=80 api-gateway"
echo ""
show_status show_status
} }
@@ -2739,11 +2954,12 @@ show_menu() {
echo " 6) Удалить конфиги Nginx IdP" echo " 6) Удалить конфиги Nginx IdP"
echo " 7) Сброс PostgreSQL (если ошибка P1000 / пароль БД)" echo " 7) Сброс PostgreSQL (если ошибка P1000 / пароль БД)"
echo " 8) Очистить Docker (образы/кеш, без пересборки)" echo " 8) Очистить Docker (образы/кеш, без пересборки)"
echo " 9) Исправить все ошибки (502, /idp-api, Nginx, порты)"
echo " 0) Выход" echo " 0) Выход"
echo "" echo ""
local choice local choice
read -r -p "Выберите пункт [0-8]: " choice read -r -p "Выберите пункт [0-9]: " choice
case "$choice" in case "$choice" in
1) NON_INTERACTIVE=0; action_full_install ;; 1) NON_INTERACTIVE=0; action_full_install ;;
@@ -2754,6 +2970,7 @@ show_menu() {
6) remove_nginx_configs; ok "Готово" ;; 6) remove_nginx_configs; ok "Готово" ;;
7) action_reset_db; action_restart ;; 7) action_reset_db; action_restart ;;
8) action_docker_prune ;; 8) action_docker_prune ;;
9) action_fix_all_errors ;;
0) exit 0 ;; 0) exit 0 ;;
*) warn "Неверный пункт" ;; *) warn "Неверный пункт" ;;
esac esac
@@ -2775,6 +2992,7 @@ main() {
restart) action_restart ;; restart) action_restart ;;
docker-prune) action_docker_prune ;; docker-prune) action_docker_prune ;;
fix-proxy) action_fix_host_proxy ;; fix-proxy) action_fix_host_proxy ;;
fix-all) action_fix_all_errors ;;
status) show_status ;; status) show_status ;;
reset-db) action_reset_db ;; reset-db) action_reset_db ;;
remove-nginx) remove_nginx_configs ;; remove-nginx) remove_nginx_configs ;;