feat(deploy): адрес привязки для прокси по туннелю и загрузка сертификата TURN с внешнего узла
- compose: app и LiveKit публикуются на GLCHAT_APP_BIND/GLCHAT_LIVEKIT_BIND (по умолчанию 127.0.0.1, для схемы «VPS-прокси + домашний сервер» — адрес в WireGuard) - install.sh: --app-bind-addr/--livekit-bind-addr, --turn-cert-remote* для загрузки сертификата по SSH, glchat-cert-refresh умеет тянуть его с внешнего узла
This commit is contained in:
@@ -34,7 +34,7 @@ services:
|
||||
environment:
|
||||
<<: *app-env
|
||||
ports:
|
||||
- "127.0.0.1:${APP_PORT}:8080"
|
||||
- "${GLCHAT_APP_BIND}:${APP_PORT}:8080"
|
||||
volumes:
|
||||
- "${GLCHAT_DATA_DIR}/db:/app/data/db"
|
||||
- "${GLCHAT_DATA_DIR}/files:/app/data/files"
|
||||
|
||||
@@ -35,7 +35,7 @@ services:
|
||||
environment:
|
||||
<<: *app-env
|
||||
ports:
|
||||
- "127.0.0.1:${APP_PORT}:8080"
|
||||
- "${GLCHAT_APP_BIND}:${APP_PORT}:8080"
|
||||
volumes:
|
||||
- "${GLCHAT_DATA_DIR}/db:/app/data/db"
|
||||
- "${GLCHAT_DATA_DIR}/files:/app/data/files"
|
||||
@@ -65,9 +65,10 @@ services:
|
||||
environment:
|
||||
LIVEKIT_KEYS: "${LIVEKIT_API_KEY}: ${LIVEKIT_API_SECRET}"
|
||||
ports:
|
||||
- "127.0.0.1:${LIVEKIT_WS_PORT}:7880"
|
||||
- "${LIVEKIT_TCP_PORT}:7881"
|
||||
- "${LIVEKIT_UDP_PORT}:7882/udp"
|
||||
- "${GLCHAT_LIVEKIT_BIND}:${LIVEKIT_WS_PORT}:7880"
|
||||
# Медиапорты: тот же адрес привязки (для инстанса за NAT это адрес туннеля).
|
||||
- "${GLCHAT_LIVEKIT_BIND}:${LIVEKIT_TCP_PORT}:7881"
|
||||
- "${GLCHAT_LIVEKIT_BIND}:${LIVEKIT_UDP_PORT}:7882/udp"
|
||||
volumes:
|
||||
- ./livekit/livekit.yaml:/etc/livekit.yaml:ro
|
||||
- ${GLCHAT_TURN_CERT_DIR}:/etc/certs:ro
|
||||
|
||||
+82
-4
@@ -61,6 +61,13 @@ TURN_RELAY_HOST="${TURN_RELAY_HOST:-}"
|
||||
TURN_RELAY_PORT="${TURN_RELAY_PORT:-3478}"
|
||||
TURN_RELAY_TLS_PORT="${TURN_RELAY_TLS_PORT:-5349}"
|
||||
TLS_BY_PROXY="${TLS_BY_PROXY:-false}"
|
||||
APP_BIND_ADDR="${APP_BIND_ADDR:-127.0.0.1}"
|
||||
LIVEKIT_BIND_ADDR="${LIVEKIT_BIND_ADDR:-127.0.0.1}"
|
||||
TURN_CERT_REMOTE="${TURN_CERT_REMOTE:-}"
|
||||
TURN_CERT_REMOTE_CRT="${TURN_CERT_REMOTE_CRT:-}"
|
||||
TURN_CERT_REMOTE_KEY="${TURN_CERT_REMOTE_KEY:-}"
|
||||
TURN_CERT_SSH_KEY="${TURN_CERT_SSH_KEY:-}"
|
||||
TURN_CERT_SSH_PORT="${TURN_CERT_SSH_PORT:-22}"
|
||||
TURN_TLS_PORT="${TURN_TLS_PORT:-5349}"
|
||||
PROXY_MODE="${PROXY_MODE:-embedded}"
|
||||
PROFILE="${PROFILE:-auto}"
|
||||
@@ -126,6 +133,14 @@ install.sh — установка glchat (AGENT.md 10).
|
||||
--turn-relay-tls-port <port> TLS-порт внешнего релея (по умолчанию 5349)
|
||||
--tls-terminated-by-proxy TLS терминирует внешний прокси: свои 80/443 не занимаем,
|
||||
но ссылки в API отдаются как https/wss
|
||||
--app-bind-addr <addr> адрес app (по умолчанию 127.0.0.1); для прокси по
|
||||
WireGuard укажите адрес в туннеле, например 10.77.0.13
|
||||
--livekit-bind-addr <addr> адрес LiveKit (по умолчанию 127.0.0.1)
|
||||
--turn-cert-remote <user@host> тянуть сертификат TURN/TLS с внешнего узла по SSH
|
||||
--turn-cert-remote-crt <путь> путь к сертификату на внешнем узле
|
||||
--turn-cert-remote-key <путь> путь к ключу на внешнем узле
|
||||
--turn-cert-ssh-key <файл> приватный SSH-ключ для загрузки сертификата
|
||||
--turn-cert-ssh-port <порт> SSH-порт внешнего узла (по умолчанию 22)
|
||||
--turn-tls <port> TURN TLS (по умолчанию 5349)
|
||||
--external-proxy не занимать 80/443: отдать маршруты внешнему прокси (AGENT.md 10.13)
|
||||
--no-files-subdomain не использовать files.<domain> (fallback /files/*)
|
||||
@@ -177,6 +192,13 @@ parse_args() {
|
||||
--turn-relay-port) TURN_RELAY_PORT="${2:?}"; shift 2 ;;
|
||||
--turn-relay-tls-port) TURN_RELAY_TLS_PORT="${2:?}"; shift 2 ;;
|
||||
--tls-terminated-by-proxy) TLS_BY_PROXY="true"; shift ;;
|
||||
--app-bind-addr) APP_BIND_ADDR="${2:?}"; shift 2 ;;
|
||||
--livekit-bind-addr) LIVEKIT_BIND_ADDR="${2:?}"; shift 2 ;;
|
||||
--turn-cert-remote) TURN_CERT_REMOTE="${2:?}"; shift 2 ;;
|
||||
--turn-cert-remote-crt) TURN_CERT_REMOTE_CRT="${2:?}"; shift 2 ;;
|
||||
--turn-cert-remote-key) TURN_CERT_REMOTE_KEY="${2:?}"; shift 2 ;;
|
||||
--turn-cert-ssh-key) TURN_CERT_SSH_KEY="${2:?}"; shift 2 ;;
|
||||
--turn-cert-ssh-port) TURN_CERT_SSH_PORT="${2:?}"; shift 2 ;;
|
||||
--turn-tls) TURN_TLS_PORT="${2:?}"; shift 2 ;;
|
||||
--profile) PROFILE="${2:?}"; shift 2 ;;
|
||||
--max-upload) MAX_UPLOAD_MB="${2:?}"; shift 2 ;;
|
||||
@@ -293,10 +315,13 @@ resolve_derived_values() {
|
||||
GLCHAT_DATA_DIR="${GLCHAT_DATA_DIR}"
|
||||
GLCHAT_CADDY_PROFILE="${CADDY_PROFILE}"
|
||||
GLCHAT_TURN_CERT_DIR="${TURN_CERT_DIR}"
|
||||
GLCHAT_APP_BIND="${APP_BIND_ADDR}"
|
||||
GLCHAT_LIVEKIT_BIND="${LIVEKIT_BIND_ADDR}"
|
||||
export FILES_DOMAIN_RESOLVED CADDY_PROFILE LIVEKIT_PUBLISH TURN_EXTERNAL_TLS \
|
||||
livekit_extra_codecs \
|
||||
PROFILE_LIVEKIT_DISABLE_SIMULCAST PROFILE_LIVEKIT_USE_EXTERNAL_IP \
|
||||
GLCHAT_DATA_DIR GLCHAT_CADDY_PROFILE GLCHAT_TURN_CERT_DIR \
|
||||
GLCHAT_APP_BIND GLCHAT_LIVEKIT_BIND \
|
||||
TURN_DOMAIN_RESOLVED TURN_CERT_DIR TURN_RELAY_HOST_RESOLVED TURN_SECRET_RESOLVED
|
||||
}
|
||||
|
||||
@@ -317,8 +342,10 @@ validate_inputs() {
|
||||
fi
|
||||
# LiveKit требует сертификат для TURN/TLS (проверено на v1.9.7: без него
|
||||
# сервер не стартует). Либо передаём файлы, либо отключаем TURN.
|
||||
if [ "$TURN_ENABLED" = "true" ] && [ "$DRY_RUN" != "1" ] && [ -z "$TURN_CERT_SRC" ]; then
|
||||
die "TURN включён, но не задан сертификат: передайте --turn-cert/--turn-key или запустите с --no-turn"
|
||||
if [ "$TURN_ENABLED" = "true" ] && [ "$DRY_RUN" != "1" ] &&
|
||||
[ -z "$TURN_CERT_SRC" ] && [ -z "$TURN_CERT_REMOTE" ] &&
|
||||
[ ! -f "${TARGET_DIR}/certs/turn.crt" ]; then
|
||||
die "TURN включён, но сертификат не задан: используйте --turn-cert/--turn-key, --turn-cert-remote или --no-turn"
|
||||
fi
|
||||
}
|
||||
|
||||
@@ -548,6 +575,8 @@ TLS_BY_PROXY=${TLS_BY_PROXY}
|
||||
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}
|
||||
@@ -722,6 +751,28 @@ turn_shared_secret() {
|
||||
|
||||
# install_turn_certificate копирует сертификат TURN/TLS туда, где его читает
|
||||
# контейнер LiveKit. Продление выполняет glchat-cert-refresh.timer.
|
||||
fetch_remote_turn_certificate() {
|
||||
[ -n "$TURN_CERT_REMOTE" ] || return 1
|
||||
local ssh_opts=(-o BatchMode=yes -o StrictHostKeyChecking=accept-new -p "$TURN_CERT_SSH_PORT")
|
||||
[ -n "$TURN_CERT_SSH_KEY" ] && ssh_opts+=(-i "$TURN_CERT_SSH_KEY")
|
||||
command -v ssh >/dev/null 2>&1 || {
|
||||
warn "ssh не найден: не могу забрать сертификат с ${TURN_CERT_REMOTE}"
|
||||
return 1
|
||||
}
|
||||
ssh "${ssh_opts[@]}" "$TURN_CERT_REMOTE" "cat '${TURN_CERT_REMOTE_CRT}'" >"${TURN_CERT_DIR}/turn.crt" 2>/dev/null || {
|
||||
warn "не удалось получить сертификат с ${TURN_CERT_REMOTE}:${TURN_CERT_REMOTE_CRT}"
|
||||
rm -f "${TURN_CERT_DIR}/turn.crt"
|
||||
return 1
|
||||
}
|
||||
ssh "${ssh_opts[@]}" "$TURN_CERT_REMOTE" "cat '${TURN_CERT_REMOTE_KEY}'" >"${TURN_CERT_DIR}/turn.key" 2>/dev/null || {
|
||||
warn "не удалось получить ключ с ${TURN_CERT_REMOTE}:${TURN_CERT_REMOTE_KEY}"
|
||||
rm -f "${TURN_CERT_DIR}/turn.key"
|
||||
return 1
|
||||
}
|
||||
chmod 640 "${TURN_CERT_DIR}/turn.crt" "${TURN_CERT_DIR}/turn.key"
|
||||
return 0
|
||||
}
|
||||
|
||||
install_turn_certificate() {
|
||||
[ "$TURN_ENABLED" = "true" ] || return 0
|
||||
if [ "$DRY_RUN" = "1" ]; then
|
||||
@@ -730,6 +781,11 @@ install_turn_certificate() {
|
||||
fi
|
||||
mkdir -p "$TURN_CERT_DIR"
|
||||
chmod 750 "$TURN_CERT_DIR"
|
||||
if [ -n "$TURN_CERT_REMOTE" ]; then
|
||||
fetch_remote_turn_certificate && ok "сертификат TURN/TLS загружен с ${TURN_CERT_REMOTE}" ||
|
||||
warn "сертификат TURN/TLS не загружен: TURN не запустится"
|
||||
return 0
|
||||
fi
|
||||
if [ -n "$TURN_CERT_SRC" ]; then
|
||||
install -m 640 "$TURN_CERT_SRC" "${TURN_CERT_DIR}/turn.crt"
|
||||
install -m 640 "${TURN_CERT_SRC_KEY:?нужен --turn-key}" "${TURN_CERT_DIR}/turn.key"
|
||||
@@ -776,6 +832,7 @@ render_all_templates() {
|
||||
"CADDY_IMAGE_TAG=${CADDY_IMAGE_TAG}" "LIVEKIT_IMAGE_TAG=${LIVEKIT_IMAGE_TAG}" \
|
||||
"GLCHAT_CADDY_PROFILE=${CADDY_PROFILE}" \
|
||||
"GLCHAT_TURN_CERT_DIR=${TURN_CERT_DIR}" \
|
||||
"GLCHAT_APP_BIND=${APP_BIND_ADDR}" "GLCHAT_LIVEKIT_BIND=${LIVEKIT_BIND_ADDR}" \
|
||||
"LIVEKIT_API_KEY=${LIVEKIT_API_KEY}" "LIVEKIT_API_SECRET=${LIVEKIT_API_SECRET}" \
|
||||
"HTTP_PORT=${HTTP_PORT}" "HTTPS_PORT=${HTTPS_PORT}"
|
||||
|
||||
@@ -833,21 +890,42 @@ render_all_templates() {
|
||||
# install_cert_refresh копирует обновлённый сертификат TURN и перезапускает LiveKit.
|
||||
install_cert_refresh() {
|
||||
[ "$TURN_ENABLED" = "true" ] || return 0
|
||||
[ -n "$TURN_CERT_SRC" ] || return 0
|
||||
[ -n "$TURN_CERT_SRC" ] || [ -n "$TURN_CERT_REMOTE" ] || return 0
|
||||
[ "$DRY_RUN" = "1" ] && return 0
|
||||
|
||||
cat >/usr/local/sbin/glchat-cert-refresh <<EOF
|
||||
#!/usr/bin/env bash
|
||||
# Сгенерировано deploy/install.sh: копирует свежий сертификат TURN/TLS
|
||||
# из внешнего ACME-хранилища и перезапускает LiveKit при изменении.
|
||||
# из внешнего ACME-хранилища (локально или по SSH) и перезапускает LiveKit
|
||||
# при изменении.
|
||||
set -eu
|
||||
SRC_CRT="${TURN_CERT_SRC}"
|
||||
SRC_KEY="${TURN_CERT_SRC_KEY}"
|
||||
REMOTE="${TURN_CERT_REMOTE}"
|
||||
REMOTE_CRT="${TURN_CERT_REMOTE_CRT}"
|
||||
REMOTE_KEY="${TURN_CERT_REMOTE_KEY}"
|
||||
SSH_KEY="${TURN_CERT_SSH_KEY}"
|
||||
SSH_PORT="${TURN_CERT_SSH_PORT}"
|
||||
DST_DIR="${TURN_CERT_DIR}"
|
||||
TMP_CRT="\$(mktemp)"; TMP_KEY="\$(mktemp)"
|
||||
trap 'rm -f "\$TMP_CRT" "\$TMP_KEY"' EXIT
|
||||
|
||||
if [ -n "\$REMOTE" ]; then
|
||||
ssh_opts="-o BatchMode=yes -o StrictHostKeyChecking=accept-new -p \$SSH_PORT"
|
||||
[ -n "\$SSH_KEY" ] && ssh_opts="\$ssh_opts -i \$SSH_KEY"
|
||||
# shellcheck disable=SC2086
|
||||
ssh \$ssh_opts "\$REMOTE" "cat '\$REMOTE_CRT'" >"\$TMP_CRT" || exit 1
|
||||
# shellcheck disable=SC2086
|
||||
ssh \$ssh_opts "\$REMOTE" "cat '\$REMOTE_KEY'" >"\$TMP_KEY" || exit 1
|
||||
else
|
||||
if [ ! -r "\$SRC_CRT" ] || [ ! -r "\$SRC_KEY" ]; then
|
||||
echo "glchat-cert-refresh: исходный сертификат недоступен" >&2
|
||||
exit 1
|
||||
fi
|
||||
cp "\$SRC_CRT" "\$TMP_CRT"
|
||||
cp "\$SRC_KEY" "\$TMP_KEY"
|
||||
fi
|
||||
SRC_CRT="\$TMP_CRT"; SRC_KEY="\$TMP_KEY"
|
||||
before="\$(sha256sum "\$DST_DIR/turn.crt" 2>/dev/null | cut -d' ' -f1 || true)"
|
||||
install -m 640 "\$SRC_CRT" "\$DST_DIR/turn.crt"
|
||||
install -m 640 "\$SRC_KEY" "\$DST_DIR/turn.key"
|
||||
|
||||
Reference in New Issue
Block a user