Skip to content

Commit bff204c

Browse files
nieaoclaude
andcommitted
fix(deploy): 改独立 caddy 实例 + :8081, 跟 Hermes 完全解耦
之前思路是抢 Hermes 的 :80 在 Caddyfile 里加 know-canvas 路由 — 但邻居 (lichang) 部署 ha2.digitalvio.shop 时直接 cat > Caddyfile 整个覆盖, 我们的路由全没了, 用户看不到画布. 研究发现 hermes-agent 项目本身不动 Caddyfile (gateway --replace 是 替换同名进程), 是 lichang 部署他自己的静态站时手动覆盖. 共享机上任何 邻居都可能这么干, 插队 :80 永远危险. 新方案: 独立 caddy 实例 + 独立端口 - /opt/know-canvas/Caddyfile (我们独占) - 监听 :8081 (避开 :80/:443/:11905 等已占端口) - XDG_DATA_HOME=/opt/know-canvas/caddy-data (隔离 storage 防 ACME 锁竞争) - admin localhost:2020 (避开默认 2019) - 完全独立的 systemd unit know-canvas-caddy.service 测试: 模拟 Hermes 把主 Caddyfile 覆盖成另一份内容 → 我们 :8081 毫发无损. 新增: deploy/know-canvas-caddy.service 独立 caddy systemd unit deploy/know-canvas-caddy.Caddyfile 我们的 Caddyfile (装到 /opt/know-canvas/) 删除: deploy/Caddyfile.newvps 旧的"覆盖主 Caddyfile"方案, 不再用 改动: deploy/deploy-newvps.sh 走独立 caddy + CANVAS_PORT 环境变量 step 7 不再覆盖 /etc/caddy/Caddyfile 新地址: http://66.245.216.250:8081/canvas/ Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 69e69ad commit bff204c

5 files changed

Lines changed: 181 additions & 135 deletions

File tree

deploy/Caddyfile.newvps

Lines changed: 0 additions & 78 deletions
This file was deleted.

deploy/deploy-newvps.sh

Lines changed: 46 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,37 @@
11
#!/usr/bin/env bash
22
# Know Canvas — 一键部署到新 VPS (66.245.216.250:8765)
33
#
4+
# 设计原则: 独立 caddy 实例 + 独立端口 (默认 :8081), 跟同机其他 caddy/服务完全解耦.
5+
# 这样邻居 (比如 Hermes Agent) 怎么覆盖主 Caddyfile 都不影响我们.
6+
#
47
# 用法 (本地开发机):
58
# DEEPSEEK_API_KEY=sk-xxx bash deploy/deploy-newvps.sh
69
#
710
# 可选环境变量:
811
# REMOTE_USER 默认 root
912
# REMOTE_HOST 默认 66.245.216.250
1013
# REMOTE_PORT 默认 8765
14+
# CANVAS_PORT 默认 8081 (独立 caddy 监听端口)
1115
# DEEPSEEK_API_KEY 必填; 写入远端 /etc/know-canvas/llm.env (不进 git)
1216
# LLM_BASE_URL 默认 https://api.deepseek.com/v1
1317
# LLM_MODEL 默认 deepseek-chat
1418
#
1519
# 干什么:
1620
# 1. 本地 npm run build:canvas
1721
# 2. SSH 远端: 检查 / 安装 caddy + node 22
18-
# 3. rsync dist/ → /var/www/know-canvas/
19-
# 4. rsync server/ → /opt/know-canvas/server/ + npm install --production
22+
# 3. tar dist/ → /var/www/know-canvas/
23+
# 4. tar server/ → /opt/know-canvas/server/ + npm install --production
2024
# 5. 写 /etc/know-canvas/llm.env (LLM_API_KEY + base url + model)
21-
# 6. 装 systemd unit (yws + llm-proxy), enable + start
22-
# 7. Caddyfile, reload caddy
23-
# 8. 健康检查 /canvas/ + /canvas/api/llm/health
25+
# 6. 装 systemd unit (yws + llm-proxy + know-canvas-caddy), enable + start
26+
# 7. 不动主 /etc/caddy/Caddyfile — 我们跑独立 caddy 实例监听 CANVAS_PORT
27+
# 8. 健康检查 http://host:CANVAS_PORT/canvas/ + .../api/llm/health
2428

2529
set -euo pipefail
2630

2731
REMOTE_USER="${REMOTE_USER:-root}"
2832
REMOTE_HOST="${REMOTE_HOST:-66.245.216.250}"
2933
REMOTE_PORT="${REMOTE_PORT:-8765}"
34+
CANVAS_PORT="${CANVAS_PORT:-8081}"
3035
LLM_BASE_URL="${LLM_BASE_URL:-https://api.deepseek.com/v1}"
3136
LLM_MODEL="${LLM_MODEL:-deepseek-chat}"
3237

@@ -57,10 +62,11 @@ fi
5762
# 2. 远端环境探测 + 安装依赖
5863
echo ""
5964
echo "==> 2/8 探测远端环境 (caddy / node)"
60-
ssh $SSH_OPTS "$REMOTE" 'bash -s' <<'REMOTE_PROBE'
65+
ssh $SSH_OPTS "$REMOTE" "CANVAS_PORT=${CANVAS_PORT} bash -s" <<'REMOTE_PROBE'
6166
set -e
6267
echo "[probe] OS: $(. /etc/os-release && echo $PRETTY_NAME)"
6368
echo "[probe] uname: $(uname -a)"
69+
echo "[probe] CANVAS_PORT=${CANVAS_PORT}"
6470
6571
# Node
6672
if ! command -v node >/dev/null 2>&1; then
@@ -85,20 +91,15 @@ if ! command -v caddy >/dev/null 2>&1; then
8591
fi
8692
echo "[probe] caddy: $(caddy version | head -1)"
8793
88-
# UFW 开 80 (公网访问入口)
94+
# UFW 开独立 caddy 监听端口 (默认 8081)
8995
if command -v ufw >/dev/null 2>&1 && ufw status | grep -q "Status: active"; then
90-
ufw allow 80/tcp 2>/dev/null || true
91-
ufw allow 443/tcp 2>/dev/null || true
92-
fi
93-
94-
# rsync (本脚本用 rsync, 远端也得装才能反向同步)
95-
if ! command -v rsync >/dev/null 2>&1; then
96-
apt install -y rsync
96+
ufw allow ${CANVAS_PORT}/tcp 2>/dev/null || true
9797
fi
9898
99-
# 准备目录
100-
mkdir -p /opt/know-canvas/server /var/www/know-canvas /etc/know-canvas
101-
chown -R www-data:www-data /opt/know-canvas /var/www/know-canvas
99+
# 独立 caddy 实例的目录 (跟系统 caddy 完全隔离, 不共享 storage)
100+
mkdir -p /opt/know-canvas/server /opt/know-canvas/caddy-data /var/www/know-canvas /etc/know-canvas
101+
chown -R caddy:caddy /opt/know-canvas/caddy-data 2>/dev/null || true
102+
chown -R www-data:www-data /opt/know-canvas/server /var/www/know-canvas
102103
echo "[probe] 目录就绪"
103104
REMOTE_PROBE
104105

@@ -136,66 +137,65 @@ chown root:root /etc/know-canvas/llm.env
136137
echo '[llm.env] 已写入'
137138
"
138139

139-
# 6. 装 systemd units
140+
# 6. 装 systemd units (yws + llm-proxy + 独立 caddy 实例)
140141
echo ""
141-
echo "==> 6/8 装 systemd unit (yws + llm-proxy)"
142+
echo "==> 6/8 装 systemd unit (yws + llm-proxy + know-canvas-caddy)"
142143
scp -P "$REMOTE_PORT" \
143144
"$PROJECT_ROOT/deploy/know-canvas-yws.service" \
144145
"$PROJECT_ROOT/deploy/know-canvas-llm-proxy.service" \
146+
"$PROJECT_ROOT/deploy/know-canvas-caddy.service" \
147+
"$PROJECT_ROOT/deploy/know-canvas-caddy.Caddyfile" \
145148
"$REMOTE:/tmp/"
146149

147150
ssh $SSH_OPTS "$REMOTE" 'set -e
148151
mv /tmp/know-canvas-yws.service /etc/systemd/system/
149152
mv /tmp/know-canvas-llm-proxy.service /etc/systemd/system/
153+
mv /tmp/know-canvas-caddy.service /etc/systemd/system/
154+
mv /tmp/know-canvas-caddy.Caddyfile /opt/know-canvas/Caddyfile
155+
chown caddy:caddy /opt/know-canvas/Caddyfile 2>/dev/null || true
150156
systemctl daemon-reload
151-
systemctl enable know-canvas-yws know-canvas-llm-proxy
152-
systemctl restart know-canvas-yws know-canvas-llm-proxy
157+
systemctl enable know-canvas-yws know-canvas-llm-proxy know-canvas-caddy
158+
systemctl restart know-canvas-yws know-canvas-llm-proxy know-canvas-caddy
153159
sleep 2
154-
# is-active / status 在 activating 时返回非零, 用 || true 避免 set -e 早退
155160
echo "--- yws ---"
156161
systemctl is-active know-canvas-yws || true
157-
journalctl -u know-canvas-yws -n 5 --no-pager || true
158162
echo "--- llm-proxy ---"
159163
systemctl is-active know-canvas-llm-proxy || true
160-
journalctl -u know-canvas-llm-proxy -n 5 --no-pager || true
164+
echo "--- know-canvas-caddy ---"
165+
systemctl is-active know-canvas-caddy || true
161166
'
162167

163-
# 7. 装 Caddyfile
168+
# 7. 推 dist (前端)
164169
echo ""
165-
echo "==> 7/8 装 Caddyfile + reload"
166-
scp -P "$REMOTE_PORT" "$PROJECT_ROOT/deploy/Caddyfile.newvps" "$REMOTE:/tmp/Caddyfile"
167-
ssh $SSH_OPTS "$REMOTE" 'set -e
168-
mv /tmp/Caddyfile /etc/caddy/Caddyfile
169-
caddy validate --config /etc/caddy/Caddyfile
170-
systemctl reload caddy || systemctl restart caddy
171-
sleep 1
172-
systemctl status caddy --no-pager -l | head -10
173-
'
170+
echo "==> 7/8 推 dist 已在 step 3 完成 (这一步无操作, 跳过)"
174171

175-
# 8. 健康检查
172+
# 8. 健康检查 (用独立端口 CANVAS_PORT)
176173
echo ""
177-
echo "==> 8/8 健康检查"
178-
ssh $SSH_OPTS "$REMOTE" 'set +e
179-
echo "--- 本机 yws health ---"
174+
echo "==> 8/8 健康检查 (端口 ${CANVAS_PORT})"
175+
ssh $SSH_OPTS "$REMOTE" "CANVAS_PORT=${CANVAS_PORT} bash -s" <<'HEALTHCHECK'
176+
set +e
177+
echo "--- 内部 yws ---"
180178
curl -sf http://127.0.0.1:1234/health && echo
181-
echo "--- 本机 llm-proxy health ---"
179+
echo "--- 内部 llm-proxy ---"
182180
curl -sf http://127.0.0.1:17080/health && echo
183-
echo "--- 通过 caddy /canvas/ ---"
184-
curl -sI http://127.0.0.1/canvas/ | head -3
185-
echo "--- 通过 caddy /canvas/api/llm/health ---"
186-
curl -sf http://127.0.0.1/canvas/api/llm/health && echo
187-
'
181+
echo "--- 通过独立 caddy /canvas/ ---"
182+
curl -sI http://127.0.0.1:${CANVAS_PORT}/canvas/ | head -3
183+
echo "--- /canvas/api/llm/health ---"
184+
curl -sf http://127.0.0.1:${CANVAS_PORT}/canvas/api/llm/health && echo
185+
HEALTHCHECK
188186

189187
echo ""
190188
echo "============================================================"
191189
echo "部署完成。访问:"
192190
echo ""
193-
echo " http://${REMOTE_HOST}/canvas/"
191+
echo " http://${REMOTE_HOST}:${CANVAS_PORT}/canvas/"
192+
echo ""
193+
echo "(独立 caddy 监听 :${CANVAS_PORT}, 完全跟系统 caddy/Hermes 解耦)"
194194
echo ""
195195
echo "排查:"
196196
echo " ssh -p ${REMOTE_PORT} ${REMOTE} 'journalctl -u know-canvas-yws -n 50'"
197197
echo " ssh -p ${REMOTE_PORT} ${REMOTE} 'journalctl -u know-canvas-llm-proxy -n 50'"
198-
echo " ssh -p ${REMOTE_PORT} ${REMOTE} 'journalctl -u caddy -n 50'"
198+
echo " ssh -p ${REMOTE_PORT} ${REMOTE} 'journalctl -u know-canvas-caddy -n 50'"
199199
echo ""
200200
echo "更换 API key:"
201201
echo " ssh -p ${REMOTE_PORT} ${REMOTE} 'nano /etc/know-canvas/llm.env'"

deploy/know-canvas-caddy.Caddyfile

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
# Know Canvas 独立 Caddy 实例配置 — 监听 :8081
2+
#
3+
# 跟系统 caddy (Hermes 占的 :80/:443) 完全独立, 互不打架.
4+
# 通过 systemd unit know-canvas-caddy.service 启动 (见 deploy/).
5+
#
6+
# 部署位置: /opt/know-canvas/Caddyfile
7+
# admin 端口 2020 (避开默认 2019, 不跟 Hermes 抢)
8+
9+
{
10+
admin localhost:2020
11+
# 独立 storage, 跟系统 caddy 隔离 (虽然 :8081 不需要 cert, 防御性)
12+
storage file_system /opt/know-canvas/caddy-data
13+
log {
14+
output stderr
15+
level INFO
16+
}
17+
}
18+
19+
:8081 {
20+
# 根路径自动跳到画布
21+
@root path /
22+
redir @root /canvas/ 302
23+
24+
# === LLM 代理 (转 vps-llm-proxy daemon) ===
25+
handle_path /canvas/api/llm/* {
26+
reverse_proxy 127.0.0.1:17080 {
27+
header_up Host {host}
28+
header_up X-Real-IP {remote_host}
29+
}
30+
}
31+
32+
# === Action Log 服务 ===
33+
handle_path /canvas/api/log {
34+
reverse_proxy 127.0.0.1:18091/log
35+
}
36+
handle_path /canvas/api/log/* {
37+
reverse_proxy 127.0.0.1:18091
38+
}
39+
40+
# === Yjs 协作 WebSocket ===
41+
handle_path /yws/* {
42+
reverse_proxy 127.0.0.1:1234 {
43+
header_up Host {host}
44+
header_up X-Real-IP {remote_host}
45+
header_up Connection {>Connection}
46+
header_up Upgrade {>Upgrade}
47+
}
48+
}
49+
50+
# === 前端静态资源 ===
51+
handle_path /canvas/* {
52+
root * /var/www/know-canvas
53+
try_files {path} /index.html
54+
file_server
55+
encode gzip
56+
}
57+
58+
# 兜底
59+
handle {
60+
respond "know-canvas at /canvas/" 200
61+
}
62+
}

deploy/know-canvas-caddy.service

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
# Know Canvas 独立 Caddy 实例 — 监听 :8081, 跟系统 caddy 互不打架
2+
#
3+
# 安装:
4+
# sudo mkdir -p /opt/know-canvas/caddy-data
5+
# sudo chown -R caddy:caddy /opt/know-canvas/caddy-data
6+
# sudo cp deploy/know-canvas-caddy.Caddyfile /opt/know-canvas/Caddyfile
7+
# sudo cp deploy/know-canvas-caddy.service /etc/systemd/system/
8+
# sudo systemctl daemon-reload
9+
# sudo systemctl enable --now know-canvas-caddy
10+
#
11+
# 看日志:
12+
# sudo journalctl -u know-canvas-caddy -f
13+
14+
[Unit]
15+
Description=Know Canvas - Independent Caddy Instance (:8081)
16+
Documentation=https://caddyserver.com/docs/
17+
After=network.target network-online.target
18+
Requires=network-online.target
19+
20+
[Service]
21+
Type=notify
22+
User=caddy
23+
Group=caddy
24+
# 独立 XDG home, 避开系统 caddy 的 /var/lib/caddy storage 锁竞争
25+
Environment=XDG_DATA_HOME=/opt/know-canvas/caddy-data
26+
Environment=XDG_CONFIG_HOME=/opt/know-canvas/caddy-data/config
27+
ExecStart=/usr/bin/caddy run --config /opt/know-canvas/Caddyfile --adapter caddyfile
28+
ExecReload=/usr/bin/caddy reload --config /opt/know-canvas/Caddyfile --adapter caddyfile --address localhost:2020
29+
TimeoutStopSec=5s
30+
LimitNOFILE=1048576
31+
PrivateDevices=yes
32+
ProtectHome=true
33+
ProtectSystem=full
34+
AmbientCapabilities=CAP_NET_BIND_SERVICE
35+
ReadWritePaths=/opt/know-canvas/caddy-data
36+
Restart=on-failure
37+
RestartSec=5
38+
StandardOutput=journal
39+
StandardError=journal
40+
41+
[Install]
42+
WantedBy=multi-user.target

0 commit comments

Comments
 (0)