From 7698b5e1e4d093d96112fda507e0389a0e640e6f Mon Sep 17 00:00:00 2001 From: kris Date: Mon, 6 Apr 2026 10:57:25 +0800 Subject: [PATCH] feat: route fnos collector through server services --- CHANGELOG.md | 7 + scripts/deploy_fnos_storyforge_collector.sh | 4 +- .../deploy_fnos_storyforge_server_tunnel.sh | 171 ++++++++++++++++++ 3 files changed, 180 insertions(+), 2 deletions(-) create mode 100755 scripts/deploy_fnos_storyforge_server_tunnel.sh diff --git a/CHANGELOG.md b/CHANGELOG.md index 3097f5d..fbf2233 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,13 @@ ## 2026-04-06 +### NAS collector 改走服务器本机的 n8n 与火爆视频 + +- 新增 `fnOS -> 公网服务器` 的本地转发隧道,把服务器本机 `127.0.0.1:25670/25678` 分别映射到 NAS 的 `19570/19578`。 +- `deploy_fnos_storyforge_collector.sh` 默认值已经改成走这条隧道,不再继续依赖旧的 `192.168.31.139:5670/5678`。 +- 这样局域网和外网的 `collector` 现在统一使用同一套服务器侧 `n8n + huobao`,只有 `cutvideo / live_recorder / Windows ASR` 继续保留在局域网设备。 +- NAS `integrations/health` 里 `n8n / huobao / asr / cutvideo / live_recorder` 已全部恢复在线,`local_model` 维持为刻意禁用状态。 + ### 公网 n8n 与火爆视频迁到服务器本机 - 公网 `n8n` 不再依赖旧的 SSH 反向隧道,已经迁到服务器本机 Docker,健康检查地址切到 `127.0.0.1:25670/healthz`。 diff --git a/scripts/deploy_fnos_storyforge_collector.sh b/scripts/deploy_fnos_storyforge_collector.sh index e7bb533..2a8cad3 100755 --- a/scripts/deploy_fnos_storyforge_collector.sh +++ b/scripts/deploy_fnos_storyforge_collector.sh @@ -51,9 +51,9 @@ ORCHESTRATOR_SHARED_SECRET="${ORCHESTRATOR_SHARED_SECRET:-storyforge-local-secre LOCAL_OPENAI_BASE_URL="${LOCAL_OPENAI_BASE_URL:-}" LOCAL_OPENAI_MODEL="${LOCAL_OPENAI_MODEL:-GLM-5}" LOCAL_OPENAI_API_KEY="${LOCAL_OPENAI_API_KEY:-}" -N8N_BASE_URL="${N8N_BASE_URL:-http://$FNOS_HOST:5670}" +N8N_BASE_URL="${N8N_BASE_URL:-http://$FNOS_HOST:19570}" ASR_HTTP_BASE_URL="${ASR_HTTP_BASE_URL:-http://192.168.31.18:8088}" -HUOBAO_BASE_URL="${HUOBAO_BASE_URL:-http://$FNOS_HOST:5678}" +HUOBAO_BASE_URL="${HUOBAO_BASE_URL:-http://$FNOS_HOST:19578}" CUTVIDEO_BASE_URL="${CUTVIDEO_BASE_URL:-http://$FNOS_HOST:19186}" LIVE_RECORDER_BASE_URL="${LIVE_RECORDER_BASE_URL:-http://192.168.31.188:19106}" CLOUD_DB_PATH="${CLOUD_DB_PATH:-/home/ubuntu/storyforge/data/collector/storyforge.db}" diff --git a/scripts/deploy_fnos_storyforge_server_tunnel.sh b/scripts/deploy_fnos_storyforge_server_tunnel.sh new file mode 100755 index 0000000..4ade3f8 --- /dev/null +++ b/scripts/deploy_fnos_storyforge_server_tunnel.sh @@ -0,0 +1,171 @@ +#!/usr/bin/env bash +set -euo pipefail + +ROOT="$(CDPATH= cd -- "$(dirname "$0")/.." && pwd)" + +export CODEX_HOME="${CODEX_HOME:-$HOME/.codex}" +export FNOS_SKILL="${FNOS_SKILL:-$CODEX_HOME/skills/fnos-hyzq-deploy}" +export FNOS_SCP="${FNOS_SCP:-$FNOS_SKILL/scripts/fnos_scp.sh}" + +FNOS_HOST="${FNOS_HOST:-192.168.31.188}" +FNOS_USER="${FNOS_USER:-krisolo}" +AG_HOST="${AG_HOST:-111.231.132.51}" +AG_USER="${AG_USER:-ubuntu}" +FNOS_TUNNEL_KEY_PATH="${FNOS_TUNNEL_KEY_PATH:-/home/$FNOS_USER/.ssh/storyforge_server_tunnel}" +FNOS_TUNNEL_SCRIPT_PATH="${FNOS_TUNNEL_SCRIPT_PATH:-/home/$FNOS_USER/codex_start_storyforge_server_tunnel_on_fnos.sh}" +FNOS_TUNNEL_CRON_SCRIPT_PATH="${FNOS_TUNNEL_CRON_SCRIPT_PATH:-/home/$FNOS_USER/codex_enable_storyforge_server_tunnel_cron_on_fnos.sh}" +FNOS_N8N_FORWARD_PORT="${FNOS_N8N_FORWARD_PORT:-19570}" +FNOS_HUOBAO_FORWARD_PORT="${FNOS_HUOBAO_FORWARD_PORT:-19578}" +SERVER_N8N_TARGET_PORT="${SERVER_N8N_TARGET_PORT:-25670}" +SERVER_HUOBAO_TARGET_PORT="${SERVER_HUOBAO_TARGET_PORT:-25678}" + +need_cmd() { + if ! command -v "$1" >/dev/null 2>&1; then + echo "missing required command: $1" >&2 + exit 1 + fi +} + +shell_quote() { + python3 - "$1" <<'PY' +import shlex +import sys +print(shlex.quote(sys.argv[1])) +PY +} + +need_cmd python3 +need_cmd ssh +need_cmd scp +need_cmd expect +need_cmd ssh-keygen + +if [ -z "${FNOS_PASSWORD:-}" ]; then + need_cmd security +fi + +resolve_fnos_password() { + if [ -n "${FNOS_PASSWORD:-}" ]; then + printf '%s' "$FNOS_PASSWORD" + return 0 + fi + security find-internet-password -s "$FNOS_HOST" -a "$FNOS_USER" -w +} + +resolve_ag_password() { + if [ -n "${AG_SERVER_PASSWORD:-}" ]; then + printf '%s' "$AG_SERVER_PASSWORD" + return 0 + fi + security find-generic-password -a "$AG_USER" -s ai-glasses-debug-ssh -w +} + +run_fnos_cmd() { + local remote_cmd="$1" + local remote_cmd_quoted + remote_cmd_quoted="$(shell_quote "$remote_cmd")" + export FNOS_REMOTE_CMD_QUOTED="$remote_cmd_quoted" + export FNOS_REMOTE_HOST="$FNOS_HOST" + export FNOS_REMOTE_USER="$FNOS_USER" + export FNOS_REMOTE_PASSWORD="$FNOS_PASSWORD_VALUE" + /usr/bin/expect <<'EOF' +set timeout -1 +set pw $env(FNOS_REMOTE_PASSWORD) +set host $env(FNOS_REMOTE_HOST) +set user $env(FNOS_REMOTE_USER) +set remote_cmd_quoted $env(FNOS_REMOTE_CMD_QUOTED) +set argv [list ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null $user@$host "sh -lc $remote_cmd_quoted"] +spawn {*}$argv +expect { + -re {Are you sure you want to continue connecting \(yes/no(/\[fingerprint\])?\)\?} { + send "yes\r" + exp_continue + } + -re {[Pp]assword:} { + send "$pw\r" + exp_continue + } + eof +} +catch wait result +set exit_code [lindex $result 3] +exit $exit_code +EOF +} + +TMPDIR_DEPLOY="$(mktemp -d)" +trap 'rm -rf "$TMPDIR_DEPLOY"' EXIT + +FNOS_PASSWORD_VALUE="$(resolve_fnos_password)" +AG_PASSWORD_VALUE="$(resolve_ag_password)" +START_SCRIPT_LOCAL="$TMPDIR_DEPLOY/codex_start_storyforge_server_tunnel_on_fnos.sh" +CRON_SCRIPT_LOCAL="$TMPDIR_DEPLOY/codex_enable_storyforge_server_tunnel_cron_on_fnos.sh" + +echo "[1/6] ensure fnOS tunnel key" +FNOS_PUBKEY="$( + run_fnos_cmd "mkdir -p ~/.ssh && chmod 700 ~/.ssh && if [ ! -f ~/.ssh/storyforge_server_tunnel ]; then ssh-keygen -t ed25519 -N '' -f ~/.ssh/storyforge_server_tunnel >/dev/null; fi && cat ~/.ssh/storyforge_server_tunnel.pub" +)" +FNOS_PUBKEY="$(printf '%s\n' "$FNOS_PUBKEY" | tail -n 1)" + +echo "[2/6] authorize fnOS key on cloud server" +sshpass -p "$AG_PASSWORD_VALUE" ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null "$AG_USER@$AG_HOST" \ + "mkdir -p ~/.ssh && chmod 700 ~/.ssh && touch ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys && grep -qxF $(shell_quote "$FNOS_PUBKEY") ~/.ssh/authorized_keys || printf '%s\n' $(shell_quote "$FNOS_PUBKEY") >> ~/.ssh/authorized_keys" + +echo "[3/6] verify fnOS -> cloud key login" +run_fnos_cmd "ssh -i $FNOS_TUNNEL_KEY_PATH -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null $AG_USER@$AG_HOST sh -lc $(shell_quote "printf STORYFORGE_SERVER_TUNNEL_OK")" + +cat >"$START_SCRIPT_LOCAL" </dev/null 2>&1 || true + +nohup ssh \\ + -i "\$TUNNEL_KEY" \\ + -o StrictHostKeyChecking=no \\ + -o UserKnownHostsFile=/dev/null \\ + -o ExitOnForwardFailure=yes \\ + -o ServerAliveInterval=30 \\ + -o ServerAliveCountMax=3 \\ + -g \\ + -N \\ + -L 0.0.0.0:${FNOS_N8N_FORWARD_PORT}:127.0.0.1:${SERVER_N8N_TARGET_PORT} \\ + -L 0.0.0.0:${FNOS_HUOBAO_FORWARD_PORT}:127.0.0.1:${SERVER_HUOBAO_TARGET_PORT} \\ + $AG_USER@$AG_HOST \\ + >"\$LOG_FILE" 2>&1 & + +sleep 2 +pgrep -af "${FNOS_N8N_FORWARD_PORT}:127.0.0.1:${SERVER_N8N_TARGET_PORT}" +EOF + +cat >"$CRON_SCRIPT_LOCAL" </dev/null | grep -v "codex_start_storyforge_server_tunnel_on_fnos.sh" >"\$TMP_CRON" || true +echo "@reboot \$SCRIPT_PATH" >>"\$TMP_CRON" +crontab "\$TMP_CRON" +rm -f "\$TMP_CRON" + +crontab -l +EOF + +echo "[4/6] upload fnOS tunnel scripts" +"$FNOS_SCP" "/home/$FNOS_USER" "$START_SCRIPT_LOCAL" "$CRON_SCRIPT_LOCAL" + +echo "[5/6] start tunnel and enable reboot recovery" +run_fnos_cmd "chmod +x $FNOS_TUNNEL_SCRIPT_PATH $FNOS_TUNNEL_CRON_SCRIPT_PATH && $FNOS_TUNNEL_SCRIPT_PATH && $FNOS_TUNNEL_CRON_SCRIPT_PATH" + +echo "[6/6] verify forwarded ports" +curl -fsS "http://$FNOS_HOST:$FNOS_N8N_FORWARD_PORT/healthz" >/dev/null +curl -fsS "http://$FNOS_HOST:$FNOS_HUOBAO_FORWARD_PORT/health" >/dev/null + +echo "fnOS server tunnel ready:" +echo " n8n: http://$FNOS_HOST:$FNOS_N8N_FORWARD_PORT/healthz" +echo " huobao: http://$FNOS_HOST:$FNOS_HUOBAO_FORWARD_PORT/health"