diff --git a/deploy/install.sh b/deploy/install.sh index b9584de..ab758cf 100755 --- a/deploy/install.sh +++ b/deploy/install.sh @@ -588,107 +588,193 @@ write_env_file() { log_file_only "DRY-RUN: .env не записывается" return 0 fi + + # Значения подставляются через sed, а не через расширение heredoc: иначе + # shell выполняет условия и подстановки прямо в тексте файла (уже ломало .env). local tmp tmp="$(mktemp)" - cat >"$tmp" <"$tmp" <<'ENVEOF' # glchat — окружение инстанса. Сгенерировано deploy/install.sh. # Секреты: не коммитить, не публиковать, не пересылать. Права: 600. # --- инстанс --- -DOMAIN=${DOMAIN} -FILES_DOMAIN=${FILES_DOMAIN_RESOLVED} -INSTANCE_NAME=${INSTANCE_NAME} -MAIN_GUILD_NAME=${MAIN_GUILD_NAME} -PROFILE=${PROFILE_RESOLVED} -PROXY_MODE=${PROXY_MODE} -APP_VERSION=${IMAGE_TAG} -IMAGE_TAG=${IMAGE_TAG} -APP_IMAGE=${APP_IMAGE} -CADDY_IMAGE_TAG=${CADDY_IMAGE_TAG} -LIVEKIT_IMAGE_TAG=${LIVEKIT_IMAGE_TAG} +DOMAIN=@DOMAIN@ +FILES_DOMAIN=@FILES_DOMAIN@ +INSTANCE_NAME=@INSTANCE_NAME@ +MAIN_GUILD_NAME=@MAIN_GUILD_NAME@ +PROFILE=@PROFILE@ +PROXY_MODE=@PROXY_MODE@ +APP_VERSION=@IMAGE_TAG@ +IMAGE_TAG=@IMAGE_TAG@ +APP_IMAGE=@APP_IMAGE@ +CADDY_IMAGE_TAG=@CADDY_IMAGE_TAG@ +LIVEKIT_IMAGE_TAG=@LIVEKIT_IMAGE_TAG@ +LOG_LEVEL=@LOG_LEVEL@ # --- TLS --- -# TLS считается включённым и когда сертификаты обслуживает внешний прокси -# (--external-proxy --tls-terminated-by-proxy): клиентские ссылки должны быть https/wss. -if [ "$SKIP_TLS" = "1" ] && [ "$TLS_BY_PROXY" != "true" ]; then - TLS_ENABLED=false -else - TLS_ENABLED=true -fi -SKIP_TLS=${SKIP_TLS} -TLS_BY_PROXY=${TLS_BY_PROXY} +TLS_ENABLED=@TLS_ENABLED@ +SKIP_TLS=@SKIP_TLS@ +TLS_BY_PROXY=@TLS_BY_PROXY@ -# --- интерполяция compose (пути и профиль) --- -GLCHAT_DATA_DIR=${GLCHAT_DATA_DIR} -GLCHAT_CADDY_PROFILE=${CADDY_PROFILE} -GLCHAT_TURN_CERT_DIR=${GLCHAT_TURN_CERT_DIR} -GLCHAT_APP_BIND=${GLCHAT_APP_BIND} -GLCHAT_LIVEKIT_BIND=${GLCHAT_LIVEKIT_BIND} -TURN_RELAY_HOST=${TURN_RELAY_HOST_RESOLVED} -TURN_RELAY_PORT=${TURN_RELAY_PORT} -TURN_RELAY_TLS_PORT=${TURN_RELAY_TLS_PORT} -TURN_SECRET=${TURN_SECRET_RESOLVED} +# --- интерполяция compose (пути, адреса привязки, профиль) --- +GLCHAT_DATA_DIR=@GLCHAT_DATA_DIR@ +GLCHAT_CADDY_PROFILE=@CADDY_PROFILE@ +GLCHAT_TURN_CERT_DIR=@GLCHAT_TURN_CERT_DIR@ +GLCHAT_APP_BIND=@GLCHAT_APP_BIND@ +GLCHAT_LIVEKIT_BIND=@GLCHAT_LIVEKIT_BIND@ # --- порты --- -APP_PORT=${APP_PORT} -LIVEKIT_WS_PORT=${LIVEKIT_WS_PORT} -LIVEKIT_TCP_PORT=${LIVEKIT_TCP_PORT} -LIVEKIT_UDP_PORT=${LIVEKIT_UDP_PORT} -TURN_UDP_PORT=${TURN_UDP_PORT} -TURN_TLS_PORT=${TURN_TLS_PORT} -HTTP_PORT=${HTTP_PORT} -HTTPS_PORT=${HTTPS_PORT} -SSH_PORT=${SSH_PORT} +APP_PORT=@APP_PORT@ +LIVEKIT_WS_PORT=@LIVEKIT_WS_PORT@ +LIVEKIT_TCP_PORT=@LIVEKIT_TCP_PORT@ +LIVEKIT_UDP_PORT=@LIVEKIT_UDP_PORT@ +HTTP_PORT=@HTTP_PORT@ +HTTPS_PORT=@HTTPS_PORT@ +SSH_PORT=@SSH_PORT@ + +# --- TURN --- +TURN_ENABLED=@TURN_ENABLED@ +TURN_DOMAIN=@TURN_DOMAIN@ +TURN_UDP_PORT=@TURN_UDP_PORT@ +TURN_TLS_PORT=@TURN_TLS_PORT@ +TURN_EXTERNAL_TLS=@TURN_EXTERNAL_TLS@ +TURN_RELAY_START=@TURN_RELAY_START@ +TURN_RELAY_END=@TURN_RELAY_END@ +TURN_RELAY_HOST=@TURN_RELAY_HOST@ +TURN_RELAY_PORT=@TURN_RELAY_PORT@ +TURN_RELAY_TLS_PORT=@TURN_RELAY_TLS_PORT@ # --- секреты (генерируются один раз) --- -SESSION_PEPPER=${SESSION_PEPPER} -MASTER_KEY=${MASTER_KEY} -TOTP_ENCRYPTION_KEY=${TOTP_ENCRYPTION_KEY} -WEBHOOK_SECRET=${WEBHOOK_SECRET} -LIVEKIT_API_KEY=${LIVEKIT_API_KEY} -LIVEKIT_API_SECRET=${LIVEKIT_API_SECRET} -AGE_RECIPIENT=${AGE_RECIPIENT:-} +SESSION_PEPPER=@SESSION_PEPPER@ +MASTER_KEY=@MASTER_KEY@ +TOTP_ENCRYPTION_KEY=@TOTP_ENCRYPTION_KEY@ +WEBHOOK_SECRET=@WEBHOOK_SECRET@ +LIVEKIT_API_KEY=@LIVEKIT_API_KEY@ +LIVEKIT_API_SECRET=@LIVEKIT_API_SECRET@ +TURN_SECRET=@TURN_SECRET@ +AGE_RECIPIENT=@AGE_RECIPIENT@ # --- профиль производительности --- -SQLITE_READ_POOL=${PROFILE_SQLITE_READ_POOL} -SQLITE_CACHE_SIZE=-${PROFILE_SQLITE_CACHE_MB}000 -SQLITE_MMAP_SIZE=$((PROFILE_SQLITE_MMAP_MB * 1024 * 1024)) -GOMAXPROCS=${PROFILE_GOMAXPROCS} -LRU_CACHE_ENTRIES=${PROFILE_LRU_ENTRIES} -MAX_UPLOAD_SIZE=$((EFFECTIVE_UPLOAD_MB * 1024 * 1024)) -PROFILE_UPLOAD_MB=${EFFECTIVE_UPLOAD_MB} -APP_CPUS=${PROFILE_APP_CPUS} -APP_MEMORY_LIMIT=${PROFILE_APP_LIMIT} -LIVEKIT_CPUS=${PROFILE_LIVEKIT_CPUS} -LIVEKIT_MEMORY_LIMIT=${PROFILE_LIVEKIT_LIMIT} +SQLITE_READ_POOL=@SQLITE_READ_POOL@ +SQLITE_CACHE_SIZE=@SQLITE_CACHE_SIZE@ +SQLITE_MMAP_SIZE=@SQLITE_MMAP_SIZE@ +GOMAXPROCS=@GOMAXPROCS@ +LRU_CACHE_ENTRIES=@LRU_CACHE_ENTRIES@ +MAX_UPLOAD_SIZE=@MAX_UPLOAD_SIZE@ +PROFILE_UPLOAD_MB=@PROFILE_UPLOAD_MB@ +APP_CPUS=@APP_CPUS@ +APP_MEMORY_LIMIT=@APP_MEMORY_LIMIT@ +LIVEKIT_CPUS=@LIVEKIT_CPUS@ +LIVEKIT_MEMORY_LIMIT=@LIVEKIT_MEMORY_LIMIT@ CADDY_CPUS=1.0 CADDY_MEMORY_LIMIT=256m -LIVEKIT_MAX_PARTICIPANTS=${PROFILE_LIVEKIT_MAX_PARTICIPANTS} -LIVEKIT_MAX_VIDEO=${PROFILE_LIVEKIT_MAX_VIDEO} -LIVEKIT_DISABLE_SIMULCAST=${PROFILE_LIVEKIT_DISABLE_SIMULCAST} -LIVEKIT_USE_EXTERNAL_IP=${PROFILE_LIVEKIT_USE_EXTERNAL_IP} -SHARE_SOFT_LIMIT=${PROFILE_SHARE_SOFT} -SHARE_MAX_LIMIT=${PROFILE_SHARE_MAX} -BACKUP_KEEP_DAYS=${PROFILE_BACKUP_KEEP} -SWAP_SIZE_GB=${PROFILE_SWAP_GB} +LIVEKIT_MAX_PARTICIPANTS=@LIVEKIT_MAX_PARTICIPANTS@ +LIVEKIT_MAX_VIDEO=@LIVEKIT_MAX_VIDEO@ +LIVEKIT_DISABLE_SIMULCAST=@LIVEKIT_DISABLE_SIMULCAST@ +LIVEKIT_USE_EXTERNAL_IP=@LIVEKIT_USE_EXTERNAL_IP@ +SHARE_SOFT_LIMIT=@SHARE_SOFT@ +SHARE_MAX_LIMIT=@SHARE_MAX@ +BACKUP_KEEP_DAYS=@BACKUP_KEEP@ +SWAP_SIZE_GB=@SWAP_SIZE@ # --- функции --- -REGISTRATION_ENABLED=${REGISTRATION_ENABLED} -ANTI_BOT_ENABLED=${ANTI_BOT_ENABLED:-false} -TURN_ENABLED=${TURN_ENABLED} -TURN_EXTERNAL_TLS=${TURN_EXTERNAL_TLS} -FAIL2BAN_ENABLED=${ENABLE_FAIL2BAN} -UFW_ENABLED=${ENABLE_UFW} -NFTABLES_ENABLED=${ENABLE_NFTABLES} -SSH_HARDENING=${SSH_HARDENING} -LOG_LEVEL=${LOG_LEVEL} +REGISTRATION_ENABLED=@REGISTRATION_ENABLED@ +ANTI_BOT_ENABLED=@ANTI_BOT_ENABLED@ +FAIL2BAN_ENABLED=@FAIL2BAN_ENABLED@ +UFW_ENABLED=@UFW_ENABLED@ +NFTABLES_ENABLED=@NFTABLES_ENABLED@ +SSH_HARDENING=@SSH_HARDENING@ # --- первичный администратор (используется один раз при bootstrap) --- -ADMIN_EMAIL=${ADMIN_EMAIL} -ADMIN_PASSWORD=${ADMIN_PASSWORD} -EOF +ADMIN_EMAIL=@ADMIN_EMAIL@ +ADMIN_PASSWORD=@ADMIN_PASSWORD@ +ENVEOF + + local pairs=( + "DOMAIN=${DOMAIN}" + "FILES_DOMAIN=${FILES_DOMAIN_RESOLVED}" + "INSTANCE_NAME=${INSTANCE_NAME}" + "MAIN_GUILD_NAME=${MAIN_GUILD_NAME}" + "PROFILE=${PROFILE_RESOLVED}" + "PROXY_MODE=${PROXY_MODE}" + "IMAGE_TAG=${IMAGE_TAG}" + "APP_IMAGE=${APP_IMAGE}" + "CADDY_IMAGE_TAG=${CADDY_IMAGE_TAG}" + "LIVEKIT_IMAGE_TAG=${LIVEKIT_IMAGE_TAG}" + "LOG_LEVEL=${LOG_LEVEL}" + "TLS_ENABLED=${TLS_ENABLED}" + "SKIP_TLS=${SKIP_TLS}" + "TLS_BY_PROXY=${TLS_BY_PROXY}" + "GLCHAT_DATA_DIR=${GLCHAT_DATA_DIR}" + "CADDY_PROFILE=${CADDY_PROFILE}" + "GLCHAT_TURN_CERT_DIR=${TURN_CERT_DIR}" + "GLCHAT_APP_BIND=${APP_BIND_ADDR}" + "GLCHAT_LIVEKIT_BIND=${LIVEKIT_BIND_ADDR}" + "APP_PORT=${APP_PORT}" + "LIVEKIT_WS_PORT=${LIVEKIT_WS_PORT}" + "LIVEKIT_TCP_PORT=${LIVEKIT_TCP_PORT}" + "LIVEKIT_UDP_PORT=${LIVEKIT_UDP_PORT}" + "HTTP_PORT=${HTTP_PORT}" + "HTTPS_PORT=${HTTPS_PORT}" + "SSH_PORT=${SSH_PORT}" + "TURN_ENABLED=${TURN_ENABLED}" + "TURN_DOMAIN=${TURN_DOMAIN_RESOLVED}" + "TURN_UDP_PORT=${TURN_UDP_PORT}" + "TURN_TLS_PORT=${TURN_TLS_PORT}" + "TURN_EXTERNAL_TLS=${TURN_EXTERNAL_TLS}" + "TURN_RELAY_START=${TURN_RELAY_START}" + "TURN_RELAY_END=${TURN_RELAY_END}" + "TURN_RELAY_HOST=${TURN_RELAY_HOST_RESOLVED}" + "TURN_RELAY_PORT=${TURN_RELAY_PORT}" + "TURN_RELAY_TLS_PORT=${TURN_RELAY_TLS_PORT}" + "SESSION_PEPPER=${SESSION_PEPPER}" + "MASTER_KEY=${MASTER_KEY}" + "TOTP_ENCRYPTION_KEY=${TOTP_ENCRYPTION_KEY}" + "WEBHOOK_SECRET=${WEBHOOK_SECRET}" + "LIVEKIT_API_KEY=${LIVEKIT_API_KEY}" + "LIVEKIT_API_SECRET=${LIVEKIT_API_SECRET}" + "TURN_SECRET=${TURN_SECRET_RESOLVED}" + "AGE_RECIPIENT=${AGE_RECIPIENT:-}" + "SQLITE_READ_POOL=${PROFILE_SQLITE_READ_POOL}" + "SQLITE_CACHE_SIZE=-${PROFILE_SQLITE_CACHE_MB}000" + "SQLITE_MMAP_SIZE=$((PROFILE_SQLITE_MMAP_MB * 1024 * 1024))" + "GOMAXPROCS=${PROFILE_GOMAXPROCS}" + "LRU_CACHE_ENTRIES=${PROFILE_LRU_ENTRIES}" + "MAX_UPLOAD_SIZE=$((EFFECTIVE_UPLOAD_MB * 1024 * 1024))" + "PROFILE_UPLOAD_MB=${EFFECTIVE_UPLOAD_MB}" + "APP_CPUS=${PROFILE_APP_CPUS}" + "APP_MEMORY_LIMIT=${PROFILE_APP_LIMIT}" + "LIVEKIT_CPUS=${PROFILE_LIVEKIT_CPUS}" + "LIVEKIT_MEMORY_LIMIT=${PROFILE_LIVEKIT_LIMIT}" + "LIVEKIT_MAX_PARTICIPANTS=${PROFILE_LIVEKIT_MAX_PARTICIPANTS}" + "LIVEKIT_MAX_VIDEO=${PROFILE_LIVEKIT_MAX_VIDEO}" + "LIVEKIT_DISABLE_SIMULCAST=${PROFILE_LIVEKIT_DISABLE_SIMULCAST}" + "LIVEKIT_USE_EXTERNAL_IP=${PROFILE_LIVEKIT_USE_EXTERNAL_IP}" + "SHARE_SOFT=${PROFILE_SHARE_SOFT}" + "SHARE_MAX=${PROFILE_SHARE_MAX}" + "BACKUP_KEEP=${PROFILE_BACKUP_KEEP}" + "SWAP_SIZE=${PROFILE_SWAP_GB}" + "REGISTRATION_ENABLED=${REGISTRATION_ENABLED}" + "ANTI_BOT_ENABLED=${ANTI_BOT_ENABLED:-false}" + "FAIL2BAN_ENABLED=${ENABLE_FAIL2BAN}" + "UFW_ENABLED=${ENABLE_UFW}" + "NFTABLES_ENABLED=${ENABLE_NFTABLES}" + "SSH_HARDENING=${SSH_HARDENING}" + "ADMIN_EMAIL=${ADMIN_EMAIL}" + "ADMIN_PASSWORD=${ADMIN_PASSWORD}" + ) + + local sed_args=() + local pair key value + for pair in "${pairs[@]}"; do + key="${pair%%=*}" + value="${pair#*=}" + sed_args+=(-e "s@@${key}@@${value}@g") + done + sed -i.bak "${sed_args[@]}" "$tmp" + install -m 600 "$tmp" "$GLCHAT_ENV_FILE" - rm -f "$tmp" + rm -f "$tmp" "$tmp.bak" ok ".env записан (права 600)" }