fix and update
This commit is contained in:
218
install.sh
218
install.sh
@@ -10,7 +10,7 @@
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_VERSION="2.3.1"
|
||||
SCRIPT_VERSION="2.3.3"
|
||||
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
cd "$ROOT_DIR"
|
||||
|
||||
@@ -35,6 +35,8 @@ OFFLINE="${OFFLINE:-0}"
|
||||
NGINX_MODE="${NGINX_MODE:-auto}"
|
||||
SKIP_DOCKER_PRUNE="${SKIP_DOCKER_PRUNE:-0}"
|
||||
DOCKER_PRUNE_AGGRESSIVE="${DOCKER_PRUNE_AGGRESSIVE:-0}"
|
||||
# Принудительный Docker Nginx (контейнер lendry-id-nginx) — включается в --fix-all
|
||||
FORCE_DOCKER_NGINX="${FORCE_DOCKER_NGINX:-0}"
|
||||
|
||||
CLI_DOMAIN_API=""
|
||||
CLI_DOMAIN_FRONTEND=""
|
||||
@@ -265,10 +267,65 @@ docker_nginx_ports_available() {
|
||||
! port_in_use "$http" && ! port_in_use "$https"
|
||||
}
|
||||
|
||||
# Снимает конфиги IdP с системного Nginx (sites-enabled), не трогая ./nginx/conf.d
|
||||
disable_host_nginx_lendry() {
|
||||
log "Отключение конфигов IdP в системном Nginx (/etc/nginx)..."
|
||||
run_root rm -f "${NGINX_ENABLED}/${NGINX_PREFIX}-"*.conf 2>/dev/null || true
|
||||
if system_nginx_is_active; then
|
||||
run_root nginx -t >/dev/null 2>&1 && run_root systemctl reload nginx 2>/dev/null || true
|
||||
fi
|
||||
}
|
||||
|
||||
# --fix-all: всегда Docker Nginx (lendry-id-nginx), не системный на 80/443
|
||||
ensure_docker_nginx_mode_for_fix_all() {
|
||||
load_env
|
||||
FORCE_DOCKER_NGINX=1
|
||||
NGINX_MODE="docker"
|
||||
env_set NGINX_MODE "docker"
|
||||
|
||||
log "Переключение на Docker Nginx (контейнер lendry-id-nginx)..."
|
||||
|
||||
disable_host_nginx_lendry
|
||||
|
||||
NGINX_HTTP_PORT="${NGINX_HTTP_PORT:-$(env_get NGINX_HTTP_PORT 80)}"
|
||||
NGINX_HTTPS_PORT="${NGINX_HTTPS_PORT:-$(env_get NGINX_HTTPS_PORT 443)}"
|
||||
[[ -n "$CLI_NGINX_HTTP_PORT" ]] && NGINX_HTTP_PORT="$CLI_NGINX_HTTP_PORT"
|
||||
[[ -n "$CLI_NGINX_HTTPS_PORT" ]] && NGINX_HTTPS_PORT="$CLI_NGINX_HTTPS_PORT"
|
||||
|
||||
if system_nginx_is_active \
|
||||
|| port_in_use "$NGINX_HTTP_PORT" \
|
||||
|| port_in_use "$NGINX_HTTPS_PORT"; then
|
||||
log "Остановка системного Nginx (освобождение портов ${NGINX_HTTP_PORT}/${NGINX_HTTPS_PORT})..."
|
||||
run_root systemctl stop nginx 2>/dev/null || run_root service nginx stop 2>/dev/null || true
|
||||
sleep 2
|
||||
fi
|
||||
|
||||
docker_cmd rm -f lendry-id-nginx 2>/dev/null || true
|
||||
|
||||
env_set NGINX_HTTP_PORT "$NGINX_HTTP_PORT"
|
||||
env_set NGINX_HTTPS_PORT "$NGINX_HTTPS_PORT"
|
||||
|
||||
if port_in_use "$NGINX_HTTP_PORT" || port_in_use "$NGINX_HTTPS_PORT"; then
|
||||
warn "Порты ${NGINX_HTTP_PORT}/${NGINX_HTTPS_PORT} всё ещё заняты после остановки system nginx"
|
||||
if has_cmd ss; then
|
||||
ss -tlnp 2>/dev/null | grep -E ":${NGINX_HTTP_PORT}\s|:${NGINX_HTTPS_PORT}\s" || true
|
||||
fi
|
||||
fail "Освободите порты ${NGINX_HTTP_PORT}/${NGINX_HTTPS_PORT} и повторите: ./install.sh --fix-all"
|
||||
fi
|
||||
|
||||
ok "NGINX_MODE=docker — порты ${NGINX_HTTP_PORT}/${NGINX_HTTPS_PORT} готовы для lendry-id-nginx"
|
||||
}
|
||||
|
||||
# Не даём контейнерному nginx занять 80/443, если их уже держит системный nginx
|
||||
# или явно выбран NGINX_MODE=host (типичная причина «address already in use»).
|
||||
ensure_docker_nginx_not_conflicting() {
|
||||
load_env
|
||||
|
||||
if [[ "${FORCE_DOCKER_NGINX:-0}" -eq 1 ]]; then
|
||||
NGINX_MODE="docker"
|
||||
return 0
|
||||
fi
|
||||
|
||||
resolve_nginx_mode_and_ports
|
||||
|
||||
local http="${NGINX_HTTP_PORT:-80}"
|
||||
@@ -313,6 +370,20 @@ prepare_compose_stack() {
|
||||
|
||||
resolve_nginx_mode_and_ports() {
|
||||
load_env
|
||||
|
||||
if [[ "${FORCE_DOCKER_NGINX:-0}" -eq 1 ]]; then
|
||||
NGINX_MODE="docker"
|
||||
NGINX_HTTP_PORT="${NGINX_HTTP_PORT:-$(env_get NGINX_HTTP_PORT 80)}"
|
||||
NGINX_HTTPS_PORT="${NGINX_HTTPS_PORT:-$(env_get NGINX_HTTPS_PORT 443)}"
|
||||
[[ -n "$CLI_NGINX_HTTP_PORT" ]] && NGINX_HTTP_PORT="$CLI_NGINX_HTTP_PORT"
|
||||
[[ -n "$CLI_NGINX_HTTPS_PORT" ]] && NGINX_HTTPS_PORT="$CLI_NGINX_HTTPS_PORT"
|
||||
env_set NGINX_MODE "docker"
|
||||
env_set NGINX_HTTP_PORT "${NGINX_HTTP_PORT}"
|
||||
env_set NGINX_HTTPS_PORT "${NGINX_HTTPS_PORT}"
|
||||
log "Nginx: mode=docker (принудительно), HTTP=${NGINX_HTTP_PORT}, HTTPS=${NGINX_HTTPS_PORT}"
|
||||
return 0
|
||||
fi
|
||||
|
||||
detect_nginx_mode
|
||||
|
||||
if system_nginx_is_active || lendry_host_nginx_configured; then
|
||||
@@ -835,6 +906,10 @@ derive_public_urls() {
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ "$ssl_type" == "letsencrypt" || "$ssl_type" == "selfsigned" || "$ssl_type" == "custom" ]]; then
|
||||
env_set FEDCM_COOKIE_SECURE "true"
|
||||
fi
|
||||
|
||||
SSL_TYPE="$ssl_type"
|
||||
USE_NGINX_SSL=$([[ "$ssl_type" == "none" ]] && echo false || echo true)
|
||||
|
||||
@@ -1212,6 +1287,10 @@ persist_domain_env() {
|
||||
env_set MINIO_PUBLIC_ENDPOINT "${MINIO_PUBLIC_ENDPOINT:-localhost:9000}"
|
||||
env_set MINIO_USE_SSL "${MINIO_USE_SSL:-false}"
|
||||
|
||||
if [[ "$(env_get USE_NGINX_SSL false)" == "true" ]]; then
|
||||
env_set FEDCM_COOKIE_SECURE "true"
|
||||
fi
|
||||
|
||||
if [[ "$(env_get INSTALL_MODE local)" == "intranet" && -z "$(env_get LDAP_USE_HOST_NETWORK "")" ]]; then
|
||||
env_set LDAP_USE_HOST_NETWORK "true"
|
||||
fi
|
||||
@@ -1915,31 +1994,27 @@ EOF
|
||||
}
|
||||
|
||||
# Блок location / для отдельного домена API (api.example.com).
|
||||
# Так как фронтенд и API на разных доменах (split-domain), браузер шлёт
|
||||
# cross-origin запросы и preflight (OPTIONS). Nginx сам отвечает на preflight
|
||||
# и проставляет CORS-заголовки, отражая Origin (нужно для credentials: cookie/JWT).
|
||||
# Заголовки CORS от upstream скрываем, чтобы не было дублей Access-Control-Allow-Origin.
|
||||
# CORS полностью на api-gateway (enableCors) — nginx только проксирует,
|
||||
# иначе add_header/if в nginx ломают ответы на авторизованные cross-origin запросы (502).
|
||||
build_nginx_api_upstream_block() {
|
||||
local upstream
|
||||
if [[ "$NGINX_MODE" == "docker" ]]; then
|
||||
upstream="api-gateway:3000"
|
||||
else
|
||||
upstream="127.0.0.1:3000"
|
||||
fi
|
||||
cat <<EOF
|
||||
upstream ${NGINX_PREFIX}_api {
|
||||
server ${upstream};
|
||||
keepalive 64;
|
||||
}
|
||||
EOF
|
||||
}
|
||||
|
||||
build_nginx_api_location_block() {
|
||||
local proxy_api
|
||||
proxy_api="$(render_proxy_root api)"
|
||||
cat <<EOF
|
||||
location / {
|
||||
if (\$request_method = OPTIONS) {
|
||||
add_header Access-Control-Allow-Origin \$http_origin always;
|
||||
add_header Access-Control-Allow-Credentials true always;
|
||||
add_header Access-Control-Allow-Methods "GET, POST, PUT, PATCH, DELETE, OPTIONS" always;
|
||||
add_header Access-Control-Allow-Headers "Authorization, Content-Type, X-Requested-With, Accept, Origin, X-CSRF-Token" always;
|
||||
add_header Access-Control-Max-Age 86400 always;
|
||||
add_header Content-Length 0;
|
||||
return 204;
|
||||
}
|
||||
|
||||
proxy_hide_header Access-Control-Allow-Origin;
|
||||
proxy_hide_header Access-Control-Allow-Credentials;
|
||||
add_header Access-Control-Allow-Origin \$http_origin always;
|
||||
add_header Access-Control-Allow-Credentials true always;
|
||||
|
||||
${proxy_api}
|
||||
proxy_pass http://${NGINX_PREFIX}_api;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Connection "";
|
||||
${nginx_proxy_headers}
|
||||
@@ -1951,14 +2026,16 @@ write_nginx_site_api() {
|
||||
local domain="$1"
|
||||
local ssl_type="${2:-none}"
|
||||
local ws_on_api="${3:-true}"
|
||||
local conf ws_block http_preamble ssl_block api_location
|
||||
local conf ws_block http_preamble ssl_block api_upstream api_location
|
||||
conf="$(nginx_conf_target api)"
|
||||
ws_block="$(build_ws_block "$ws_on_api")"
|
||||
http_preamble="$(nginx_http_server_preamble "$domain" "$ssl_type")"
|
||||
api_upstream="$(build_nginx_api_upstream_block)"
|
||||
api_location="$(build_nginx_api_location_block)"
|
||||
|
||||
if [[ "$ssl_type" == "none" ]]; then
|
||||
nginx_write_conf "$conf" <<EOF
|
||||
${api_upstream}
|
||||
server {
|
||||
listen 80;
|
||||
listen [::]:80;
|
||||
@@ -1971,6 +2048,7 @@ EOF
|
||||
else
|
||||
ssl_block="$(nginx_ssl_directives "$domain" "$ssl_type")"
|
||||
nginx_write_conf "$conf" <<EOF
|
||||
${api_upstream}
|
||||
${http_preamble}server {
|
||||
listen 443 ssl http2;
|
||||
listen [::]:443 ssl http2;
|
||||
@@ -2269,7 +2347,7 @@ EOF
|
||||
remove_nginx_configs() {
|
||||
log "Удаление конфигов Nginx IdP..."
|
||||
rm -f "${LOCAL_CONF_DIR}/${NGINX_PREFIX}-"*.conf 2>/dev/null || true
|
||||
if [[ "$NGINX_MODE" == "host" ]]; then
|
||||
if [[ "$NGINX_MODE" == "host" ]] || [[ "${FORCE_DOCKER_NGINX:-0}" -eq 1 ]]; then
|
||||
run_root rm -f \
|
||||
"${NGINX_ENABLED}/${NGINX_PREFIX}-"*.conf \
|
||||
"${NGINX_AVAILABLE}/${NGINX_PREFIX}-"*.conf 2>/dev/null || true
|
||||
@@ -2636,7 +2714,6 @@ check_https_api_with_origin() {
|
||||
code="$(curl -sk --max-time 5 -o /dev/null -w '%{http_code}' -H "Origin: ${origin}" "https://${api_domain}/notifications/unread-count" 2>/dev/null || echo 000)"
|
||||
if [[ "$code" == "401" || "$code" == "403" ]]; then
|
||||
echo -e " ${GREEN}✔${NC} HTTPS API + Origin (без токена): /notifications/unread-count → ${code}"
|
||||
return 0
|
||||
elif [[ "$code" == "502" ]]; then
|
||||
echo -e " ${RED}✘${NC} HTTPS API + Origin: /notifications/unread-count → 502 (upstream api-gateway)"
|
||||
echo " Проверьте: curl -s http://127.0.0.1:3000/health/ready && docker compose logs --tail=50 api-gateway sso-core"
|
||||
@@ -2645,6 +2722,30 @@ check_https_api_with_origin() {
|
||||
echo -e " ${YELLOW}!${NC} HTTPS API + Origin: /notifications/unread-count → HTTP ${code} (ожидалось 401)"
|
||||
return 1
|
||||
fi
|
||||
|
||||
local test_token
|
||||
test_token="$(env_get IDP_TEST_BEARER_TOKEN "")"
|
||||
if [[ -n "$test_token" ]]; then
|
||||
code="$(curl -sk --max-time 8 -o /dev/null -w '%{http_code}' \
|
||||
-H "Origin: ${origin}" \
|
||||
-H "Authorization: Bearer ${test_token}" \
|
||||
-H "Content-Type: application/json" \
|
||||
"https://${api_domain}/notifications/unread-count" 2>/dev/null || echo 000)"
|
||||
if [[ "$code" == "200" || "$code" == "403" ]]; then
|
||||
echo -e " ${GREEN}✔${NC} HTTPS API + Bearer token: /notifications/unread-count → ${code}"
|
||||
elif [[ "$code" == "502" ]]; then
|
||||
echo -e " ${RED}✘${NC} HTTPS API + Bearer token → 502 (как в браузере)"
|
||||
echo " docker compose logs --tail=80 api-gateway sso-core"
|
||||
return 1
|
||||
else
|
||||
echo -e " ${YELLOW}!${NC} HTTPS API + Bearer token → HTTP ${code}"
|
||||
fi
|
||||
else
|
||||
echo -e " ${YELLOW}!${NC} Для проверки с токеном: IDP_TEST_BEARER_TOKEN=<jwt> ./install.sh --fix-all"
|
||||
echo " (скопируйте lendry_access_token из DevTools → Application → Local Storage на sso)"
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
# Диагностика типичных проблем: 502 на /idp-api, конфликт nginx, порты upstream.
|
||||
@@ -2990,15 +3091,14 @@ action_fix_all_errors() {
|
||||
|
||||
echo ""
|
||||
echo -e "${BOLD}Комплексное исправление ошибок IdP${NC}"
|
||||
echo " (502 Bad Gateway, /idp-api, конфликт Nginx, порты 3000/3002/3003)"
|
||||
echo " (502 Bad Gateway, /idp-api, Docker Nginx lendry-id-nginx, порты upstream)"
|
||||
echo ""
|
||||
|
||||
log "Шаг 1/6: диагностика..."
|
||||
diagnose_common_issues || true
|
||||
|
||||
log "Шаг 2/6: определение режима Nginx и устранение конфликта портов 80/443..."
|
||||
resolve_nginx_mode_and_ports
|
||||
ensure_docker_nginx_not_conflicting
|
||||
log "Шаг 2/6: Docker Nginx — остановка system nginx, освобождение 80/443..."
|
||||
ensure_docker_nginx_mode_for_fix_all
|
||||
write_compose_override
|
||||
ensure_split_domain_public_urls
|
||||
|
||||
@@ -3014,40 +3114,30 @@ action_fix_all_errors() {
|
||||
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
|
||||
log "Шаг 5/6: Docker Nginx — конфиги в ./nginx/conf.d и контейнер lendry-id-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
|
||||
apply_intranet_selfsigned_runtime
|
||||
compose_build_and_up nginx ldap-auth
|
||||
wait_for_service "nginx" 45
|
||||
if ! docker_nginx_container_running; then
|
||||
fail "Контейнер lendry-id-nginx не запущен. Проверьте: docker compose --profile proxy logs nginx"
|
||||
fi
|
||||
ok "Docker Nginx запущен — проверьте: docker ps | grep lendry-id-nginx"
|
||||
|
||||
log "Шаг 6/6: финальная проверка..."
|
||||
diagnose_common_issues || true
|
||||
@@ -3096,7 +3186,7 @@ show_menu() {
|
||||
echo " 6) Удалить конфиги Nginx IdP"
|
||||
echo " 7) Сброс PostgreSQL (если ошибка P1000 / пароль БД)"
|
||||
echo " 8) Очистить Docker (образы/кеш, без пересборки)"
|
||||
echo " 9) Исправить все ошибки (502, /idp-api, Nginx, порты)"
|
||||
echo " 9) Исправить все ошибки (502, Docker Nginx, порты upstream)"
|
||||
echo " 0) Выход"
|
||||
echo ""
|
||||
|
||||
|
||||
Reference in New Issue
Block a user