feat: route fnos collector through server services
This commit is contained in:
@@ -4,6 +4,13 @@
|
|||||||
|
|
||||||
## 2026-04-06
|
## 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 与火爆视频迁到服务器本机
|
||||||
|
|
||||||
- 公网 `n8n` 不再依赖旧的 SSH 反向隧道,已经迁到服务器本机 Docker,健康检查地址切到 `127.0.0.1:25670/healthz`。
|
- 公网 `n8n` 不再依赖旧的 SSH 反向隧道,已经迁到服务器本机 Docker,健康检查地址切到 `127.0.0.1:25670/healthz`。
|
||||||
|
|||||||
@@ -51,9 +51,9 @@ ORCHESTRATOR_SHARED_SECRET="${ORCHESTRATOR_SHARED_SECRET:-storyforge-local-secre
|
|||||||
LOCAL_OPENAI_BASE_URL="${LOCAL_OPENAI_BASE_URL:-}"
|
LOCAL_OPENAI_BASE_URL="${LOCAL_OPENAI_BASE_URL:-}"
|
||||||
LOCAL_OPENAI_MODEL="${LOCAL_OPENAI_MODEL:-GLM-5}"
|
LOCAL_OPENAI_MODEL="${LOCAL_OPENAI_MODEL:-GLM-5}"
|
||||||
LOCAL_OPENAI_API_KEY="${LOCAL_OPENAI_API_KEY:-}"
|
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}"
|
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}"
|
CUTVIDEO_BASE_URL="${CUTVIDEO_BASE_URL:-http://$FNOS_HOST:19186}"
|
||||||
LIVE_RECORDER_BASE_URL="${LIVE_RECORDER_BASE_URL:-http://192.168.31.188:19106}"
|
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}"
|
CLOUD_DB_PATH="${CLOUD_DB_PATH:-/home/ubuntu/storyforge/data/collector/storyforge.db}"
|
||||||
|
|||||||
171
scripts/deploy_fnos_storyforge_server_tunnel.sh
Executable file
171
scripts/deploy_fnos_storyforge_server_tunnel.sh
Executable file
@@ -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" <<EOF
|
||||||
|
#!/bin/sh
|
||||||
|
set -eu
|
||||||
|
|
||||||
|
TUNNEL_KEY="$FNOS_TUNNEL_KEY_PATH"
|
||||||
|
LOG_FILE="/home/$FNOS_USER/storyforge_server_tunnel.log"
|
||||||
|
|
||||||
|
pkill -f "${FNOS_N8N_FORWARD_PORT}:127.0.0.1:${SERVER_N8N_TARGET_PORT}" >/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" <<EOF
|
||||||
|
#!/bin/sh
|
||||||
|
set -eu
|
||||||
|
|
||||||
|
SCRIPT_PATH="$FNOS_TUNNEL_SCRIPT_PATH"
|
||||||
|
TMP_CRON="\$(mktemp)"
|
||||||
|
|
||||||
|
crontab -l 2>/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"
|
||||||
Reference in New Issue
Block a user