fix(deploy): .env генерируется через подстановку @KEY@, а не через heredoc
Условия и подстановки внутри heredoc выполнялись shell при генерации файла и попадали в .env как код — docker compose не мог его прочитать. Теперь шаблон пишется с quoted heredoc, значения подставляются sed.
This commit is contained in:
+165
-79
@@ -588,107 +588,193 @@ write_env_file() {
|
|||||||
log_file_only "DRY-RUN: .env не записывается"
|
log_file_only "DRY-RUN: .env не записывается"
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Значения подставляются через sed, а не через расширение heredoc: иначе
|
||||||
|
# shell выполняет условия и подстановки прямо в тексте файла (уже ломало .env).
|
||||||
local tmp
|
local tmp
|
||||||
tmp="$(mktemp)"
|
tmp="$(mktemp)"
|
||||||
cat >"$tmp" <<EOF
|
cat >"$tmp" <<'ENVEOF'
|
||||||
# glchat — окружение инстанса. Сгенерировано deploy/install.sh.
|
# glchat — окружение инстанса. Сгенерировано deploy/install.sh.
|
||||||
# Секреты: не коммитить, не публиковать, не пересылать. Права: 600.
|
# Секреты: не коммитить, не публиковать, не пересылать. Права: 600.
|
||||||
|
|
||||||
# --- инстанс ---
|
# --- инстанс ---
|
||||||
DOMAIN=${DOMAIN}
|
DOMAIN=@DOMAIN@
|
||||||
FILES_DOMAIN=${FILES_DOMAIN_RESOLVED}
|
FILES_DOMAIN=@FILES_DOMAIN@
|
||||||
INSTANCE_NAME=${INSTANCE_NAME}
|
INSTANCE_NAME=@INSTANCE_NAME@
|
||||||
MAIN_GUILD_NAME=${MAIN_GUILD_NAME}
|
MAIN_GUILD_NAME=@MAIN_GUILD_NAME@
|
||||||
PROFILE=${PROFILE_RESOLVED}
|
PROFILE=@PROFILE@
|
||||||
PROXY_MODE=${PROXY_MODE}
|
PROXY_MODE=@PROXY_MODE@
|
||||||
APP_VERSION=${IMAGE_TAG}
|
APP_VERSION=@IMAGE_TAG@
|
||||||
IMAGE_TAG=${IMAGE_TAG}
|
IMAGE_TAG=@IMAGE_TAG@
|
||||||
APP_IMAGE=${APP_IMAGE}
|
APP_IMAGE=@APP_IMAGE@
|
||||||
CADDY_IMAGE_TAG=${CADDY_IMAGE_TAG}
|
CADDY_IMAGE_TAG=@CADDY_IMAGE_TAG@
|
||||||
LIVEKIT_IMAGE_TAG=${LIVEKIT_IMAGE_TAG}
|
LIVEKIT_IMAGE_TAG=@LIVEKIT_IMAGE_TAG@
|
||||||
|
LOG_LEVEL=@LOG_LEVEL@
|
||||||
|
|
||||||
# --- TLS ---
|
# --- TLS ---
|
||||||
# TLS считается включённым и когда сертификаты обслуживает внешний прокси
|
TLS_ENABLED=@TLS_ENABLED@
|
||||||
# (--external-proxy --tls-terminated-by-proxy): клиентские ссылки должны быть https/wss.
|
SKIP_TLS=@SKIP_TLS@
|
||||||
if [ "$SKIP_TLS" = "1" ] && [ "$TLS_BY_PROXY" != "true" ]; then
|
TLS_BY_PROXY=@TLS_BY_PROXY@
|
||||||
TLS_ENABLED=false
|
|
||||||
else
|
|
||||||
TLS_ENABLED=true
|
|
||||||
fi
|
|
||||||
SKIP_TLS=${SKIP_TLS}
|
|
||||||
TLS_BY_PROXY=${TLS_BY_PROXY}
|
|
||||||
|
|
||||||
# --- интерполяция compose (пути и профиль) ---
|
# --- интерполяция compose (пути, адреса привязки, профиль) ---
|
||||||
GLCHAT_DATA_DIR=${GLCHAT_DATA_DIR}
|
GLCHAT_DATA_DIR=@GLCHAT_DATA_DIR@
|
||||||
GLCHAT_CADDY_PROFILE=${CADDY_PROFILE}
|
GLCHAT_CADDY_PROFILE=@CADDY_PROFILE@
|
||||||
GLCHAT_TURN_CERT_DIR=${GLCHAT_TURN_CERT_DIR}
|
GLCHAT_TURN_CERT_DIR=@GLCHAT_TURN_CERT_DIR@
|
||||||
GLCHAT_APP_BIND=${GLCHAT_APP_BIND}
|
GLCHAT_APP_BIND=@GLCHAT_APP_BIND@
|
||||||
GLCHAT_LIVEKIT_BIND=${GLCHAT_LIVEKIT_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}
|
|
||||||
|
|
||||||
# --- порты ---
|
# --- порты ---
|
||||||
APP_PORT=${APP_PORT}
|
APP_PORT=@APP_PORT@
|
||||||
LIVEKIT_WS_PORT=${LIVEKIT_WS_PORT}
|
LIVEKIT_WS_PORT=@LIVEKIT_WS_PORT@
|
||||||
LIVEKIT_TCP_PORT=${LIVEKIT_TCP_PORT}
|
LIVEKIT_TCP_PORT=@LIVEKIT_TCP_PORT@
|
||||||
LIVEKIT_UDP_PORT=${LIVEKIT_UDP_PORT}
|
LIVEKIT_UDP_PORT=@LIVEKIT_UDP_PORT@
|
||||||
TURN_UDP_PORT=${TURN_UDP_PORT}
|
HTTP_PORT=@HTTP_PORT@
|
||||||
TURN_TLS_PORT=${TURN_TLS_PORT}
|
HTTPS_PORT=@HTTPS_PORT@
|
||||||
HTTP_PORT=${HTTP_PORT}
|
SSH_PORT=@SSH_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}
|
SESSION_PEPPER=@SESSION_PEPPER@
|
||||||
MASTER_KEY=${MASTER_KEY}
|
MASTER_KEY=@MASTER_KEY@
|
||||||
TOTP_ENCRYPTION_KEY=${TOTP_ENCRYPTION_KEY}
|
TOTP_ENCRYPTION_KEY=@TOTP_ENCRYPTION_KEY@
|
||||||
WEBHOOK_SECRET=${WEBHOOK_SECRET}
|
WEBHOOK_SECRET=@WEBHOOK_SECRET@
|
||||||
LIVEKIT_API_KEY=${LIVEKIT_API_KEY}
|
LIVEKIT_API_KEY=@LIVEKIT_API_KEY@
|
||||||
LIVEKIT_API_SECRET=${LIVEKIT_API_SECRET}
|
LIVEKIT_API_SECRET=@LIVEKIT_API_SECRET@
|
||||||
AGE_RECIPIENT=${AGE_RECIPIENT:-}
|
TURN_SECRET=@TURN_SECRET@
|
||||||
|
AGE_RECIPIENT=@AGE_RECIPIENT@
|
||||||
|
|
||||||
# --- профиль производительности ---
|
# --- профиль производительности ---
|
||||||
SQLITE_READ_POOL=${PROFILE_SQLITE_READ_POOL}
|
SQLITE_READ_POOL=@SQLITE_READ_POOL@
|
||||||
SQLITE_CACHE_SIZE=-${PROFILE_SQLITE_CACHE_MB}000
|
SQLITE_CACHE_SIZE=@SQLITE_CACHE_SIZE@
|
||||||
SQLITE_MMAP_SIZE=$((PROFILE_SQLITE_MMAP_MB * 1024 * 1024))
|
SQLITE_MMAP_SIZE=@SQLITE_MMAP_SIZE@
|
||||||
GOMAXPROCS=${PROFILE_GOMAXPROCS}
|
GOMAXPROCS=@GOMAXPROCS@
|
||||||
LRU_CACHE_ENTRIES=${PROFILE_LRU_ENTRIES}
|
LRU_CACHE_ENTRIES=@LRU_CACHE_ENTRIES@
|
||||||
MAX_UPLOAD_SIZE=$((EFFECTIVE_UPLOAD_MB * 1024 * 1024))
|
MAX_UPLOAD_SIZE=@MAX_UPLOAD_SIZE@
|
||||||
PROFILE_UPLOAD_MB=${EFFECTIVE_UPLOAD_MB}
|
PROFILE_UPLOAD_MB=@PROFILE_UPLOAD_MB@
|
||||||
APP_CPUS=${PROFILE_APP_CPUS}
|
APP_CPUS=@APP_CPUS@
|
||||||
APP_MEMORY_LIMIT=${PROFILE_APP_LIMIT}
|
APP_MEMORY_LIMIT=@APP_MEMORY_LIMIT@
|
||||||
LIVEKIT_CPUS=${PROFILE_LIVEKIT_CPUS}
|
LIVEKIT_CPUS=@LIVEKIT_CPUS@
|
||||||
LIVEKIT_MEMORY_LIMIT=${PROFILE_LIVEKIT_LIMIT}
|
LIVEKIT_MEMORY_LIMIT=@LIVEKIT_MEMORY_LIMIT@
|
||||||
CADDY_CPUS=1.0
|
CADDY_CPUS=1.0
|
||||||
CADDY_MEMORY_LIMIT=256m
|
CADDY_MEMORY_LIMIT=256m
|
||||||
LIVEKIT_MAX_PARTICIPANTS=${PROFILE_LIVEKIT_MAX_PARTICIPANTS}
|
LIVEKIT_MAX_PARTICIPANTS=@LIVEKIT_MAX_PARTICIPANTS@
|
||||||
LIVEKIT_MAX_VIDEO=${PROFILE_LIVEKIT_MAX_VIDEO}
|
LIVEKIT_MAX_VIDEO=@LIVEKIT_MAX_VIDEO@
|
||||||
LIVEKIT_DISABLE_SIMULCAST=${PROFILE_LIVEKIT_DISABLE_SIMULCAST}
|
LIVEKIT_DISABLE_SIMULCAST=@LIVEKIT_DISABLE_SIMULCAST@
|
||||||
LIVEKIT_USE_EXTERNAL_IP=${PROFILE_LIVEKIT_USE_EXTERNAL_IP}
|
LIVEKIT_USE_EXTERNAL_IP=@LIVEKIT_USE_EXTERNAL_IP@
|
||||||
SHARE_SOFT_LIMIT=${PROFILE_SHARE_SOFT}
|
SHARE_SOFT_LIMIT=@SHARE_SOFT@
|
||||||
SHARE_MAX_LIMIT=${PROFILE_SHARE_MAX}
|
SHARE_MAX_LIMIT=@SHARE_MAX@
|
||||||
BACKUP_KEEP_DAYS=${PROFILE_BACKUP_KEEP}
|
BACKUP_KEEP_DAYS=@BACKUP_KEEP@
|
||||||
SWAP_SIZE_GB=${PROFILE_SWAP_GB}
|
SWAP_SIZE_GB=@SWAP_SIZE@
|
||||||
|
|
||||||
# --- функции ---
|
# --- функции ---
|
||||||
REGISTRATION_ENABLED=${REGISTRATION_ENABLED}
|
REGISTRATION_ENABLED=@REGISTRATION_ENABLED@
|
||||||
ANTI_BOT_ENABLED=${ANTI_BOT_ENABLED:-false}
|
ANTI_BOT_ENABLED=@ANTI_BOT_ENABLED@
|
||||||
TURN_ENABLED=${TURN_ENABLED}
|
FAIL2BAN_ENABLED=@FAIL2BAN_ENABLED@
|
||||||
TURN_EXTERNAL_TLS=${TURN_EXTERNAL_TLS}
|
UFW_ENABLED=@UFW_ENABLED@
|
||||||
FAIL2BAN_ENABLED=${ENABLE_FAIL2BAN}
|
NFTABLES_ENABLED=@NFTABLES_ENABLED@
|
||||||
UFW_ENABLED=${ENABLE_UFW}
|
SSH_HARDENING=@SSH_HARDENING@
|
||||||
NFTABLES_ENABLED=${ENABLE_NFTABLES}
|
|
||||||
SSH_HARDENING=${SSH_HARDENING}
|
|
||||||
LOG_LEVEL=${LOG_LEVEL}
|
|
||||||
|
|
||||||
# --- первичный администратор (используется один раз при bootstrap) ---
|
# --- первичный администратор (используется один раз при bootstrap) ---
|
||||||
ADMIN_EMAIL=${ADMIN_EMAIL}
|
ADMIN_EMAIL=@ADMIN_EMAIL@
|
||||||
ADMIN_PASSWORD=${ADMIN_PASSWORD}
|
ADMIN_PASSWORD=@ADMIN_PASSWORD@
|
||||||
EOF
|
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"
|
install -m 600 "$tmp" "$GLCHAT_ENV_FILE"
|
||||||
rm -f "$tmp"
|
rm -f "$tmp" "$tmp.bak"
|
||||||
ok ".env записан (права 600)"
|
ok ".env записан (права 600)"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user