Files
ai-proj-helper/skills-ops/ops-tools-plugin/skills/SKILL.md
John Qiu 712063071c refactor: 通用技能按类别拆分为独立目录
skills/ → skills-dev(9), skills-req(10), skills-ops(4),
skills-integration(8), skills-biz(4), skills-workflow(7)

generate-marketplace.py 改为自动扫描所有 skills-* 目录。

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-14 11:31:58 +10:30

1561 lines
44 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
name: ops-tools
description: DevOps 运维工具。用于 SSH 连接服务器、部署应用、健康检查、日志查看、服务重启和系统监控。当用户提到服务器操作、部署、运维、Jenkins、Gitea、ai-proj 相关任务时自动激活。
---
# DevOps Skill
## 子文档索引
| 文档 | 说明 |
|------|------|
| [ai-proj-deploy.md](ai-proj-deploy.md) | AI-Proj 部署流程 |
| [coolbuy-deploy.md](coolbuy-deploy.md) | Coolbuy-PaaS 部署流程 |
| [db-backup.md](db-backup.md) | ⚠️ **数据库备份与恢复(迁移前必读)** |
| [mcp-config.md](mcp-config.md) | Claude Code MCP 配置 |
| [incidents.md](incidents.md) | 重大事件记录 |
> ⚠️ **重要提醒**:执行任何数据库 UPDATE/DELETE/ALTER 或数据迁移操作前,**必须先备份**
> 详见 [db-backup.md](db-backup.md) 的「迁移前快速备份」章节。
---
## 服务器清单
| 别名 | IP | 用户 | SSH 密钥 | 用途 |
|------|-----|------|----------|------|
| tools-jenkins | 101.200.136.200 | root | ~/.ssh/tools.pem | Jenkins CI/CD |
| tools-gitea | 123.56.89.187 | root | ~/.ssh/tools.pem | Gitea 代码托管 |
| tools_ai_proj | 152.136.104.251 | root | ~/.ssh/tools_ai_proj.pem | AI项目生产服务器 |
| singapore | 43.134.28.147 | ubuntu | ~/.ssh/singpore.pem | AI项目测试环境 & 跳板机 |
| siyuan | 47.93.23.182 | root | ~/Downloads/siyuan.pem | 思源笔记服务器 (阿里云, Ubuntu 24.04) |
| lvkai | 124.223.196.74 | root | ~/.ssh/lvkai | 通用服务器 (腾讯云, OpenCloudOS) |
| coolbuy-dev | 100.112.161.79 | coolbuy-dev | ~/.ssh/id_ed25519_coolbuy_dev | Coolbuy 开发服务器 (Tailscale) |
| melbourne | 100.85.65.39 | coolbuy-dev | ~/.ssh/id_ed25519_coolbuy_dev | Melbourne 开发电脑 (Tailscale) |
| cn-dev | 100.92.148.46 | johnqiu | ~/.ssh/id_ed25519_cn_dev | 北京 MacBook Pro (Tailscale) |
| chengdu-mac-mini | 100.105.50.115 | coolbuy | ~/.ssh/id_ed25519 | 成都 Mac Mini (Tailscale, SOCKS5 代理节点) |
| au-dev | 当前电脑 | coolbuy-dev | - | 澳洲开发电脑 (本机) |
| adelaide-dev-mini | 100.114.124.68 | donglinlai | ~/.ssh/id_ed25519 | Adelaide Mac Mini (Tailscale, 密钥存储) |
| cn-bj-lazycat | 100.115.52.119 / haiqing.heiyu.space | root | 密码认证 (zhiyun2026) | 北京算力仓服务器 (Debian 6.5.0, 懒猫微服) |
### SSH 快捷连接
```bash
ssh tools-jenkins # Jenkins 服务器
ssh tools-gitea # Gitea 服务器
ssh tools_ai_proj # AI项目生产服务器
ssh singapore # 新加坡测试环境
ssh siyuan # 思源笔记服务器
ssh lvkai # LvKai 通用服务器
ssh coolbuy-dev # Coolbuy 开发服务器 (Tailscale)
ssh melbourne # Melbourne 开发电脑 (Tailscale)
ssh cn-dev # 北京 MacBook Pro (Tailscale) - iOS 开发
ssh adelaide-dev-mini # Adelaide Mac Mini (密钥存储)
```
### 密钥存储机器
**adelaide-dev-mini** (100.114.124.68) 存储了所有服务器的 SSH 密钥:
```bash
# 查看可用密钥
ssh adelaide-dev-mini "ls ~/.ssh/*.pem"
# 可用密钥列表:
# - singpore.pem → Singapore staging 服务器
# - tools_ai_proj.pem → 生产服务器
# - tools.pem → Jenkins/Gitea 服务器
# - coolbuy3.pem → Coolbuy 相关服务器
```
**密钥同步到本机**:
```bash
# 下载缺失的密钥
ssh adelaide-dev-mini "cat ~/.ssh/singpore.pem" > ~/.ssh/singpore.pem
chmod 600 ~/.ssh/singpore.pem
```
---
## 凭据配置
凭据存储在 `~/.config/devops/credentials.env`(权限 600
```bash
source ~/.config/devops/credentials.env
# Jenkins API
curl -s "$JENKINS_URL/api/json" \
-u "$JENKINS_USER:$JENKINS_TOKEN"
```
| 服务 | 变量 |
|------|------|
| Jenkins | `$JENKINS_USER:$JENKINS_TOKEN` |
| OSS | `$OSS_ACCESS_KEY_ID`, `$OSS_ACCESS_KEY_SECRET` |
> Gitea 操作统一使用 `tea` CLI详见 `pull-request` 技能。
---
## 服务地址
| 服务 | URL | 备注 |
|------|-----|------|
| Gitea Web | https://gitea.pipexerp.com | 代码仓库 |
| Gitea SSH | git@gitea.pipexerp.com:10022 | Git SSH |
| Jenkins | https://jenkins.pipexerp.com | CI/CD |
| AI-Proj | https://ai.pipexerp.com | 生产环境 |
| AI-Proj Staging | http://staging.ai.pipexerp.com | 测试环境 |
| 思源笔记 | http://47.93.23.182 | 访问码: SiYuan@2026 |
---
## 常用命令
### 系统状态
```bash
# 服务器概况
ssh <server> "uptime && free -h && df -h && docker ps"
# Docker 资源
ssh <server> "docker stats --no-stream"
# CPU/内存 Top 进程
ssh <server> "ps aux --sort=-%cpu | head -10"
```
### AI-Proj 操作
```bash
# 健康检查
curl -s https://ai.pipexerp.com/api/v1/health | jq .
# 查看日志
ssh tools_ai_proj "docker logs -f ai_backend_prod --tail 100"
# 重启服务
ssh tools_ai_proj "docker restart ai_backend_prod"
# 生产部署用户手动在终端执行Claude 不要自动运行)
# 详见 ai-proj-deploy.md「部署到生产环境」章节
# docker buildx build --platform linux/amd64 -t saltthing123/ai-proj-frontend:latest -f frontend/Dockerfile.prod --push ./frontend
# docker buildx build --platform linux/amd64 -t saltthing123/ai-proj-backend:latest --push ./backend
# ssh tools_ai_proj "cd /opt/ai-project && docker compose -f docker-compose.dockerhub.yml pull && docker compose -f docker-compose.dockerhub.yml up -d"
# iOS TestFlight 部署 → 详见 dev-coding 技能「TestFlight 部署」章节
# 构建机器: cn-dev | Apple ID: 6205365@qq.com | Team: 5NHLK8SPHB
```
### 思源笔记操作
```bash
# 查看容器状态
ssh siyuan "docker ps | grep siyuan"
# 查看日志
ssh siyuan "docker logs -f siyuan --tail 100"
# 重启服务
ssh siyuan "docker restart siyuan"
# 停止服务
ssh siyuan "docker stop siyuan"
# 启动服务
ssh siyuan "docker start siyuan"
# 查看数据目录大小
ssh siyuan "du -sh /opt/siyuan/workspace"
# 备份数据
ssh siyuan "tar -czf /root/siyuan-backup-\$(date +%Y%m%d).tar.gz /opt/siyuan/workspace"
# 下载备份到本地
scp siyuan:/root/siyuan-backup-*.tar.gz ~/Downloads/
# 升级思源笔记(拉取最新镜像)
ssh siyuan "docker pull b3log/siyuan:latest && docker restart siyuan"
# 访问测试
curl -I http://47.93.23.182
```
### 数据库操作(迁移前必备份)
```bash
# ⚠️ 迁移前备份AI-Proj 生产)
ssh tools_ai_proj 'docker exec ai_postgres_prod pg_dump -U ai_prod_user -Fc ai_project_prod \
> /backup/ai-project/database/ai_project_$(date +%Y%m%d_%H%M%S)_pre_migration.dump'
# 查看备份列表
ssh tools_ai_proj 'ls -lht /backup/ai-project/database/*.dump | head -5'
# 快速恢复
ssh tools_ai_proj 'docker exec ai_postgres_prod pg_restore \
-U ai_prod_user -d ai_project_prod --clean --if-exists -Fc \
/backup/ai-project/database/BACKUP_FILE.dump'
# 执行 SQL 文件
scp /tmp/migration.sql tools_ai_proj:/tmp/
ssh tools_ai_proj 'docker cp /tmp/migration.sql ai_postgres_prod:/tmp/ && \
docker exec ai_postgres_prod psql -U ai_prod_user -d ai_project_prod -f /tmp/migration.sql'
```
> 详细文档见 [db-backup.md](db-backup.md)
### Gitea 操作
```bash
# PR / 代码评审 → 使用 tea CLIpull-request 技能)
tea pr list
tea pr create ...
# 查看容器(服务器运维)
ssh tools-gitea "docker ps | grep gitea"
ssh tools-gitea "docker logs -f gitea --tail 100"
```
### Jenkins 操作
```bash
source ~/.config/devops/credentials.env
# 构建状态
curl -s "$JENKINS_URL/job/coolbuy-paas/lastBuild/api/json" \
-u "$JENKINS_USER:$JENKINS_TOKEN" | jq '.result, .building'
# 触发部署
curl -X POST "$JENKINS_URL/job/coolbuy-paas/buildWithParameters" \
-u "$JENKINS_USER:$JENKINS_TOKEN" \
--data "ACTION=deploy-prod&IMAGE_TAG=latest"
```
---
## 双电脑同步 (au-dev / cn-dev)
### 项目目录
| 电脑 | new-ai-proj 路径 |
|------|------------------|
| au-dev | /Users/coolbuy-dev/coding/new-ai-proj |
| cn-dev | /Users/johnqiu/workspace/new-ai-proj |
### sync-leave离开前
```bash
git add -A
git commit -m "WIP: sync from $(hostname)" || echo "Nothing to commit"
git push origin $(git branch --show-current)
```
### sync-arrive到达后
```bash
git fetch origin
git pull origin $(git branch --show-current)
```
### sync-merge合并 WIP 提交)
```bash
git reset --soft HEAD~<WIP数量>
git add -A
git commit -m "feat: 实际功能描述"
git push origin $(git branch --show-current) --force-with-lease
```
---
## 故障排查
### 服务无响应
```bash
systemctl status <service>
journalctl -u <service> --since "5 minutes ago"
netstat -tlnp | grep <port>
```
### 磁盘空间不足
```bash
df -h
docker system prune -af
journalctl --vacuum-size=500M
```
### 内存不足
```bash
free -h
ps aux --sort=-%mem | head -10
```
---
## 安全注意事项
- SSH 密钥权限必须是 600
- 不要在命令中明文包含密码
- 生产环境操作需要二次确认
- **生产数据库操作必须先备份**
- **docker compose down 前检查 volumes 配置**
---
## AI-Proj 用户管理
### 创建系统用户
> **重要**: AI-Proj 后端使用 bcrypt **cost 12** 进行密码哈希。不要使用 cost 10 或其他值。
#### 完整流程
由于 bcrypt 哈希包含 `$` 字符,在 shell 中直接执行会导致变量替换问题。正确流程如下:
**步骤 1: 生成密码哈希cost 12**
```bash
# 在 backend 目录下执行,使用 Go 生成哈希
cd /path/to/new-ai-proj/backend
# 创建临时 Go 脚本
cat > /tmp/genhash.go << 'EOF'
package main
import (
"fmt"
"golang.org/x/crypto/bcrypt"
)
func main() {
hash, err := bcrypt.GenerateFromPassword([]byte("用户密码"), 12)
if err != nil {
panic(err)
}
fmt.Println(string(hash))
}
EOF
# 执行生成哈希
go run /tmp/genhash.go
# 输出示例: $2a$12$E5KVmMDiJPi61kThzgDEdeRiIHqTtZ2yB5F0ccIoE3wfRPIH7hHRG
```
**步骤 2: 创建 SQL 文件**
```bash
# 将哈希写入 SQL 文件(避免 shell 转义问题)
cat > /tmp/create_user.sql << 'EOF'
INSERT INTO users (
username,
email,
password_hash,
user_type,
role,
status,
created_at,
updated_at
) VALUES (
'newuser',
'newuser@example.com',
'$2a$12$E5KVmMDiJPi61kThzgDEdeRiIHqTtZ2yB5F0ccIoE3wfRPIH7hHRG',
'system',
'admin',
'active',
NOW(),
NOW()
);
EOF
```
**步骤 3: 传输并执行 SQL**
```bash
# 复制 SQL 文件到服务器
scp /tmp/create_user.sql tools_ai_proj:/tmp/
# 在服务器上执行
ssh tools_ai_proj "docker cp /tmp/create_user.sql ai_postgres_prod:/tmp/ && \
docker exec ai_postgres_prod psql -U ai_prod_user -d ai_project_prod -f /tmp/create_user.sql"
```
**步骤 4: 验证用户创建**
```bash
# 检查用户是否创建成功
ssh tools_ai_proj "docker exec ai_postgres_prod psql -U ai_prod_user -d ai_project_prod \
-c \"SELECT id, username, email, user_type, role, status, length(password_hash) as hash_len FROM users WHERE username = 'newuser';\""
# 测试登录
curl -s -X POST "https://ai.pipexerp.com/api/v1/auth/login" \
-H "Content-Type: application/json" \
-d '{"username":"newuser","password":"用户密码"}' | jq '.success'
```
### 用户角色说明
| user_type | role | 说明 |
|-----------|------|------|
| system | admin | 系统管理员(最高权限) |
| system | user | 系统用户 |
| tenant | admin | 租户管理员 |
| tenant | user | 租户用户 |
### 重置用户密码
```bash
# 1. 生成新密码哈希
cd /path/to/new-ai-proj/backend
cat > /tmp/genhash.go << 'EOF'
package main
import (
"fmt"
"golang.org/x/crypto/bcrypt"
)
func main() {
hash, _ := bcrypt.GenerateFromPassword([]byte("新密码"), 12)
fmt.Println(string(hash))
}
EOF
NEW_HASH=$(go run /tmp/genhash.go)
# 2. 创建更新 SQL
cat > /tmp/reset_pwd.sql << EOF
UPDATE users SET password_hash = '$NEW_HASH' WHERE username = 'targetuser';
EOF
# 3. 执行更新
scp /tmp/reset_pwd.sql tools_ai_proj:/tmp/
ssh tools_ai_proj "docker cp /tmp/reset_pwd.sql ai_postgres_prod:/tmp/ && \
docker exec ai_postgres_prod psql -U ai_prod_user -d ai_project_prod -f /tmp/reset_pwd.sql"
```
### 常见问题
| 问题 | 原因 | 解决方案 |
|------|------|----------|
| 登录失败,密码错误 | 哈希 cost 不匹配(使用了 cost 10 | 使用 Go 重新生成 cost 12 的哈希 |
| SQL 执行失败 | `$` 字符被 shell 解释 | 使用 heredoc 或文件传输方式 |
| 哈希被截断 | 直接在命令行执行 SQL | 使用文件方式避免转义问题 |
## 本地开发环境配置 (au-dev)
### 前置条件
```bash
# PostgreSQL 16 (Homebrew)
brew install postgresql@16
brew services start postgresql@16
# Redis
brew install redis
brew services start redis
# Tailscale (用于访问 cn-dev / au-dev-mini)
# 从 App Store 安装或 brew install tailscale
```
### 从 Staging 同步数据库
当本地需要测试数据时,从 Singapore staging 环境同步:
```bash
# 1. 确保有 singpore.pem 密钥
ls ~/.ssh/singpore.pem || ssh au-dev-mini "cat ~/.ssh/singpore.pem" > ~/.ssh/singpore.pem
chmod 600 ~/.ssh/singpore.pem
# 2. 导出 staging 数据库
ssh singapore "docker exec ai_postgres_staging pg_dump -U ai_staging_user ai_project_staging --no-owner --no-acl --clean --if-exists | gzip > /tmp/staging_backup.sql.gz"
# 3. 下载到本地
scp singapore:/tmp/staging_backup.sql.gz /tmp/
# 4. 重建本地数据库
psql postgres -c "DROP DATABASE IF EXISTS ai_project_local;"
psql postgres -c "DROP USER IF EXISTS ai_local;"
psql postgres -c "CREATE USER ai_local WITH PASSWORD 'ai_local_pass' SUPERUSER;"
psql postgres -c "CREATE DATABASE ai_project_local OWNER ai_local;"
# 5. 恢复数据
gunzip -c /tmp/staging_backup.sql.gz | psql -U ai_local ai_project_local
# 6. 验证
psql -U ai_local ai_project_local -c "SELECT COUNT(*) FROM tasks;"
```
### 后端 .env 配置
```bash
# 创建 backend/.env
cat > /Users/coolbuy-dev/coding/new-ai-proj/backend/.env << 'EOF'
ENV=development
APP_ENV=development
GIN_MODE=debug
DB_HOST=localhost
DB_PORT=5432
DB_USER=ai_local
DB_PASSWORD=ai_local_pass
DB_NAME=ai_project_local
DB_SSL_MODE=disable
REDIS_HOST=localhost
REDIS_PORT=6379
REDIS_PASSWORD=
REDIS_DB=0
BACKEND_PORT=8080
JWT_SECRET=local_dev_jwt_secret_key_32chars
JWT_EXPIRATION=168h
CORS_ORIGIN=http://localhost:3000
FEATURE_SUPERADMIN_ENABLE=true
SUPER_ADMIN_USERNAMES=admin
EOF
```
### 启动本地服务
```bash
# 终端 1: 后端
cd /Users/coolbuy-dev/coding/new-ai-proj/backend
go run main.go
# 终端 2: 前端
cd /Users/coolbuy-dev/coding/new-ai-proj/frontend
npm start
# 验证
curl -s http://localhost:8080/api/v1/health | jq .
# 访问 http://localhost:3000
```
### 本地服务状态检查
```bash
# PostgreSQL
pg_isready -h localhost
# Redis
redis-cli ping
# 后端健康检查
curl -s http://localhost:8080/api/v1/health
# 前端 (检查端口)
lsof -i :3000
```
---
## 跨境网络代理 (SSH SOCKS5 隧道)
当从澳洲访问国内网站(如 ai.pipexerp.com速度慢时可通过国内 Tailscale 节点建立 SSH 隧道。
### 问题诊断
```bash
# 1. 检查延迟和丢包
ping -c 3 ai.pipexerp.com
# 2. 确认出口 IP 位置
curl -s ipinfo.io
# 3. 测试访问速度
curl -I --connect-timeout 10 https://ai.pipexerp.com
```
### Tailscale 国内节点
| 节点 | IP | 用户 | 用途 |
|------|-----|------|------|
| chengdu-mac-mini | 100.105.50.115 | coolbuy | 成都 Mac Mini (推荐) |
| cn-bj-qiu-macbook-portable | 100.92.148.46 | - | 北京 MacBook |
| cn-tj-pve-fnos | 100.118.62.18 | - | 天津 Linux |
### 手动启动 SOCKS5 代理
```bash
# 通过成都节点建立隧道 (端口 1080)
ssh -D 1080 -C -N -f coolbuy@100.105.50.115
# 测试代理
curl -x socks5://localhost:1080 -I https://ai.pipexerp.com
```
### 开机自启动配置
plist 文件: `~/Library/LaunchAgents/com.socks.chengdu.plist`
```xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.socks.chengdu</string>
<key>ProgramArguments</key>
<array>
<string>/usr/bin/ssh</string>
<string>-D</string>
<string>1080</string>
<string>-C</string>
<string>-N</string>
<string>-o</string>
<string>ServerAliveInterval=60</string>
<string>-o</string>
<string>ServerAliveCountMax=3</string>
<string>-o</string>
<string>ExitOnForwardFailure=yes</string>
<string>coolbuy@100.105.50.115</string>
</array>
<key>RunAtLoad</key>
<true/>
<key>KeepAlive</key>
<true/>
<key>StandardErrorPath</key>
<string>/tmp/socks-chengdu.err</string>
<key>StandardOutPath</key>
<string>/tmp/socks-chengdu.log</string>
</dict>
</plist>
```
### 服务管理
```bash
# 查看状态
launchctl list | grep socks.chengdu
# 停止服务
launchctl unload ~/Library/LaunchAgents/com.socks.chengdu.plist
# 启动服务
launchctl load ~/Library/LaunchAgents/com.socks.chengdu.plist
# 查看日志
cat /tmp/socks-chengdu.err
# 验证隧道运行
lsof -i :1080
```
### 浏览器配置 (SwitchyOmega)
1. 安装 Chrome/Edge 扩展 SwitchyOmega
2. 新建情景模式 → 代理服务器 → SOCKS5 → `127.0.0.1:1080`
3. 自动切换规则:
- `*.pipexerp.com` → 国内代理
- `*.cn` → 国内代理
- 其他 → 直连
---
## SSH 跳板与反向隧道
当 Tailscale 直连不稳定或反向连接失败时,可通过公网服务器建立 SSH 跳板解决。
### 问题场景
**典型问题**
- 本机可以 ping 通远程机器(如 cn-bj-lazycat
- 本机可以 SSH 到远程机器
- 但远程机器无法 SSH 回本机(连接超时)
**原因分析**
1. Tailscale 使用 DERP 中继,连接不稳定
2. NAT 穿透失败,反向连接无法建立
3. 网络延迟高200-700ms+TCP 连接容易超时
### 解决方案架构
```
远程机器 (cn-bj-lazycat)
↓ SSH
公网跳板 (Singapore)
↓ 反向隧道 localhost:2222
本机 (au-melbourne-coolbuy-dev)
```
**优势**
- ✅ 利用稳定的公网服务器作为中继
- ✅ 绕过 Tailscale DERP 不稳定问题
- ✅ 自动重连,无需手动维护
- ✅ 安全:隧道只监听 localhost需通过跳板访问
### 配置步骤
#### 步骤 1: 本机建立反向隧道
**手动启动**(测试用):
```bash
ssh -fN -R 2222:localhost:22 singapore
```
**配置自动重连服务**(推荐):
创建 `~/Library/LaunchAgents/com.ssh.singapore-tunnel.plist`
```xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.ssh.singapore-tunnel</string>
<key>ProgramArguments</key>
<array>
<string>/usr/bin/ssh</string>
<string>-N</string>
<string>-R</string>
<string>2222:localhost:22</string>
<string>-o</string>
<string>ServerAliveInterval=60</string>
<string>-o</string>
<string>ServerAliveCountMax=3</string>
<string>-o</string>
<string>ExitOnForwardFailure=yes</string>
<string>singapore</string>
</array>
<key>RunAtLoad</key>
<true/>
<key>KeepAlive</key>
<true/>
<key>StandardErrorPath</key>
<string>/tmp/singapore-tunnel.err</string>
<key>StandardOutPath</key>
<string>/tmp/singapore-tunnel.log</string>
</dict>
</plist>
```
启动服务:
```bash
launchctl load ~/Library/LaunchAgents/com.ssh.singapore-tunnel.plist
launchctl list | grep singapore-tunnel
```
#### 步骤 2: 配置 SSH 密钥认证
**在跳板服务器上生成密钥**(如果还没有):
```bash
ssh singapore "ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519 -N '' -C 'singapore-jump'"
```
**将跳板公钥添加到本机**
```bash
ssh singapore "cat ~/.ssh/id_ed25519.pub" >> ~/.ssh/authorized_keys
```
**测试反向隧道**
```bash
ssh singapore "ssh -p 2222 -o StrictHostKeyChecking=no <本机用户>@localhost 'hostname'"
```
#### 步骤 3: 远程机器配置
**传输跳板 SSH 密钥到远程机器**
```bash
# 在远程机器上创建 SSH 目录
ssh <remote-server> "mkdir -p ~/.ssh && chmod 700 ~/.ssh"
# 传输密钥(通过管道避免 scp 密码问题)
cat ~/.ssh/singpore.pem | ssh <remote-server> "cat > ~/.ssh/singpore.pem && chmod 600 ~/.ssh/singpore.pem"
```
**配置 SSH config**(在远程机器上):
```bash
ssh <remote-server> "cat > ~/.ssh/config << 'EOFCONFIG'
# Singapore 跳板服务器
Host singapore
HostName 43.134.28.147
User ubuntu
IdentityFile ~/.ssh/singpore.pem
ServerAliveInterval 60
ServerAliveCountMax 3
# 通过 Singapore 访问目标机器
Host <target-host-alias>
HostName localhost
Port 2222
User <target-user>
ProxyJump singapore
ServerAliveInterval 60
ServerAliveCountMax 3
EOFCONFIG
chmod 600 ~/.ssh/config"
```
**配置远程机器的 SSH 密钥认证**
```bash
# 在远程机器上生成密钥
ssh <remote-server> "ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519 -N '' -C '<remote-name>'"
# 将远程机器公钥添加到本机
ssh <remote-server> "cat ~/.ssh/id_ed25519.pub" >> ~/.ssh/authorized_keys
```
#### 步骤 4: 测试连接
**从远程机器测试**
```bash
# 连接到跳板
ssh <remote-server> "ssh singapore 'hostname'"
# 通过跳板连接到本机
ssh <remote-server> "ssh <target-host-alias> 'hostname && whoami'"
```
### 实际案例cn-bj-lazycat 配置
**场景**:从 cn-bj-lazycat (懒猫算力仓) 稳定访问 Melbourne 开发机
**服务器信息**
- **cn-bj-lazycat**: 100.115.52.119 / haiqing.heiyu.space
- 系统: Debian GNU/Linux (Kernel 6.5.0)
- 用户: root密码: zhiyun2026
- 用途: 北京算力仓服务器(懒猫微服)
- **Melbourne**: au-melbourne-coolbuy-dev (100.112.161.78)
- 系统: macOS Darwin 25.2.0
- 用户: coolbuy-dev
- 用途: 澳洲开发电脑
**配置详情**
```bash
# 1. Melbourne 本机 - 反向隧道已自动运行
launchctl list | grep singapore-tunnel
# 输出: 10349 0 com.ssh.singapore-tunnel
# 2. cn-bj-lazycat 上的完整配置
ssh root@haiqing.heiyu.space # 密码: zhiyun2026
# SSH config 已配置:
Host singapore
HostName 43.134.28.147
User ubuntu
IdentityFile ~/.ssh/singpore.pem
ServerAliveInterval 60
ServerAliveCountMax 3
Host au-melbourne au-dev melbourne
HostName localhost
Port 2222
User coolbuy-dev
ProxyJump singapore
ServerAliveInterval 60
ServerAliveCountMax 3
# 3. 使用方式(支持 3 个别名)
ssh melbourne "hostname && whoami"
ssh au-melbourne "ls -la"
ssh au-dev "uname -a"
# 文件传输
scp file.txt melbourne:/tmp/
scp melbourne:/path/to/file ./
# 4. 验证连接
ssh melbourne 'echo "✅ 连接成功!当前在 $(hostname)"'
```
**连接测试结果**
```bash
# 所有别名测试通过
ssh au-melbourne # ✅ 成功
ssh melbourne # ✅ 成功
ssh au-dev # ✅ 成功
```
### 管理命令
**本机管理反向隧道**
```bash
# 查看状态
launchctl list | grep singapore-tunnel
ps aux | grep "ssh.*singapore"
# 重启服务
launchctl unload ~/Library/LaunchAgents/com.ssh.singapore-tunnel.plist
launchctl load ~/Library/LaunchAgents/com.ssh.singapore-tunnel.plist
# 查看日志
cat /tmp/singapore-tunnel.err
# 验证隧道端口
ssh singapore "netstat -tlnp | grep :2222"
```
**远程机器管理**
```bash
# 测试连接质量
ssh <target-host> "time echo 'test'"
# 查看 SSH 配置
ssh <remote-server> "cat ~/.ssh/config"
# 测试 ProxyJump
ssh <remote-server> "ssh -v <target-host> 'hostname' 2>&1 | grep -i 'proxy\|jump'"
```
### 故障排查
| 问题 | 可能原因 | 解决方案 |
|------|---------|----------|
| 反向隧道断开 | 网络波动、服务器重启 | 检查 LaunchAgent 服务是否运行 |
| 认证失败 | 密钥权限错误、公钥未添加 | 确保密钥权限 600公钥在 authorized_keys |
| 连接超时 | 跳板服务器网络问题 | 测试到跳板的连接:`ping singapore` |
| ProxyJump 失败 | SSH config 语法错误 | 检查 config 文件格式和缩进 |
### 安全注意事项
- ✅ 反向隧道只监听 localhost外部无法直接访问
- ✅ SSH 密钥权限必须是 600
- ✅ 定期检查 authorized_keys移除不需要的密钥
- ✅ 跳板服务器应启用 fail2ban 等安全措施
- ⚠️ 避免在公共网络下使用密码认证,优先使用密钥
---
## MCP 配置(快速参考)
**配置文件**: `~/.claude/.mcp.json`
```json
{
"mcpServers": {
"ai-proj": {
"type": "stdio",
"command": "node",
"args": ["/Users/coolbuy-dev/coding/new-ai-proj/mcp-task-bridge/dist/index.js"],
"env": {
"TASK_API_BASE": "https://ai.pipexerp.com/api/v1",
"TASK_API_TOKEN": "aiproj_pk_2ecf8f8728b70afd4420af3875f4f7505c9fe8231a4771972b0f385aa1c75099",
"NODE_ENV": "production"
}
}
}
}
```
**前置条件**: `cd mcp-task-bridge && npm run build`
**详细说明**: 见 [mcp-config.md](mcp-config.md)
---
## OpenClaw 配置(懒猫算力仓)
OpenClaw 运行在懒猫算力仓的容器环境中,需要特殊配置才能访问 skills。
### 问题与解决方案
**问题**OpenClaw 运行在容器内,无法访问宿主机的 `~/.claude/skills/` 目录
**原因**容器和宿主机文件系统隔离skills 目录未挂载到容器内
**解决方案**:将 skills 复制到容器内的标准路径
### 配置步骤
#### 1. 连接到懒猫算力仓
```bash
# 添加 SSH 配置(首次配置)
cat >> ~/.ssh/config << 'EOF'
Host cn-bj-lazycat lazycat
HostName haiqing.heiyu.space
User root
IdentityFile ~/.ssh/id_lazycat
ServerAliveInterval 60
ServerAliveCountMax 3
EOF
# 生成并配置 SSH 密钥
ssh-keygen -t ed25519 -f ~/.ssh/id_lazycat -N "" -C "au-dev-to-lazycat"
ssh-copy-id -i ~/.ssh/id_lazycat root@haiqing.heiyu.space
# 密码: zhiyun2026
# 测试连接
ssh lazycat "whoami && hostname"
```
#### 2. 查找 OpenClaw 容器
```bash
# 查看运行的容器
ssh lazycat "/lzcsys/bin/lzc-docker ps --format 'table {{.ID}}\t{{.Names}}'"
# 找到 OpenClaw 容器 ID通常是固定的
CONTAINER_ID="5f3bf33e090b" # 懒猫算力仓的 OpenClaw 容器
```
#### 3. 复制 skills 到容器内
```bash
# 在容器内创建目录
ssh lazycat "/lzcsys/bin/lzc-docker exec $CONTAINER_ID mkdir -p /root/.claude/skills"
# 复制 skills从宿主机到容器
ssh lazycat "/lzcsys/bin/lzc-docker cp /root/.claude/skills/. $CONTAINER_ID:/root/.claude/skills/"
# 验证复制结果
ssh lazycat "/lzcsys/bin/lzc-docker exec $CONTAINER_ID ls -la /root/.claude/skills/ | head -20"
ssh lazycat "/lzcsys/bin/lzc-docker exec $CONTAINER_ID ls /root/.claude/skills/ | wc -l"
```
#### 4. 重启 OpenClaw
```bash
# 重启容器使配置生效
ssh lazycat "/lzcsys/bin/lzc-docker restart $CONTAINER_ID"
# 检查容器状态
ssh lazycat "/lzcsys/bin/lzc-docker ps | grep $CONTAINER_ID"
```
### 更新 Skills
当本地更新了 skills 后,需要重新同步到懒猫算力仓:
```bash
# 步骤 1: 同步 skills 到宿主机
ssh lazycat "mkdir -p ~/.claude"
cd ~/.dotfiles
tar -czf - claude-skills/ | ssh lazycat "cd ~/.claude && rm -rf skills && tar -xzf - && mv claude-skills skills"
# 步骤 2: 复制到 OpenClaw 容器
ssh lazycat "/lzcsys/bin/lzc-docker exec 5f3bf33e090b rm -rf /root/.claude/skills"
ssh lazycat "/lzcsys/bin/lzc-docker cp /root/.claude/skills/. 5f3bf33e090b:/root/.claude/skills/"
# 步骤 3: 重启 OpenClaw
ssh lazycat "/lzcsys/bin/lzc-docker restart 5f3bf33e090b"
```
### 验证配置
```bash
# 检查容器内的 skills 数量
ssh lazycat "/lzcsys/bin/lzc-docker exec 5f3bf33e090b ls /root/.claude/skills/ | wc -l"
# 应该显示: 41
# 检查特定 skill 内容
ssh lazycat "/lzcsys/bin/lzc-docker exec 5f3bf33e090b cat /root/.claude/skills/ai-proj/SKILL.md | head -30"
# 检查 OpenClaw 配置
ssh lazycat "/lzcsys/bin/lzc-docker exec 5f3bf33e090b cat /home/node/.openclaw/openclaw.json | grep -A 3 workspace"
```
### 懒猫算力仓环境信息
| 项目 | 信息 |
|------|------|
| **宿主机** | Debian GNU/Linux (Kernel 6.5.0) |
| **容器 ID** | 5f3bf33e090b (固定) |
| **Docker 命令** | `/lzcsys/bin/lzc-docker` (懒猫专用) |
| **OpenClaw 配置** | `/home/node/.openclaw/openclaw.json` |
| **Skills 路径** | `/root/.claude/skills/` (容器内) |
| **宿主 Skills** | `/root/.claude/skills/` (宿主机) |
### 自动化脚本
创建 `~/.local/bin/sync-skills-to-lazycat.sh`
```bash
#!/bin/bash
# 同步 skills 到懒猫算力仓 OpenClaw
set -e
echo "=== 同步 skills 到懒猫算力仓 ==="
# 1. 同步到宿主机
echo "步骤 1: 同步到宿主机..."
cd ~/.dotfiles
tar -czf - claude-skills/ | ssh lazycat "cd ~/.claude && rm -rf skills && tar -xzf - && mv claude-skills skills"
# 2. 复制到容器
echo "步骤 2: 复制到 OpenClaw 容器..."
ssh lazycat "/lzcsys/bin/lzc-docker exec 5f3bf33e090b rm -rf /root/.claude/skills || true"
ssh lazycat "/lzcsys/bin/lzc-docker exec 5f3bf33e090b mkdir -p /root/.claude/skills"
ssh lazycat "/lzcsys/bin/lzc-docker cp /root/.claude/skills/. 5f3bf33e090b:/root/.claude/skills/"
# 3. 验证
echo "步骤 3: 验证..."
SKILL_COUNT=$(ssh lazycat "/lzcsys/bin/lzc-docker exec 5f3bf33e090b ls /root/.claude/skills/ | wc -l")
echo "✅ 同步完成!共 $SKILL_COUNT 个 skills"
# 4. 重启 OpenClaw
echo "步骤 4: 重启 OpenClaw..."
ssh lazycat "/lzcsys/bin/lzc-docker restart 5f3bf33e090b"
echo "✅ OpenClaw 已重启"
```
使用方法:
```bash
chmod +x ~/.local/bin/sync-skills-to-lazycat.sh
sync-skills-to-lazycat.sh
```
### Agent-Swarm 多智能体技能部署
**agent-swarm** 是基于 OpenAI Swarm 设计模式的多智能体协作系统,用于复杂开发任务的智能分解与协调。
#### 技能概述
| 项目 | 信息 |
|------|------|
| **技能名称** | agent-swarm |
| **版本** | 1.0.0 |
| **文档大小** | 9.1KB (450+ 行) |
| **预定义 Agent** | 5 个 (Architect, Coder, Tester, Reviewer, Deployer) |
| **部署日期** | 2026-02-16 |
| **部署位置** | 懒猫算力仓 OpenClaw 容器 |
#### 快速部署
**从本地部署到懒猫算力仓**:
```bash
# 1. 确保本地有 agent-swarm 技能
ls ~/.claude/skills/agent-swarm/
# skill.yaml SKILL.md README.md
# 2. 打包技能
cd /tmp
tar -czf agent-swarm-skill.tar.gz -C ~/.claude/skills agent-swarm
# 3. 上传到懒猫算力仓宿主机
sshpass -p 'zhiyun2026' scp -o StrictHostKeyChecking=no \
agent-swarm-skill.tar.gz root@haiqing.heiyu.space:/tmp/
# 4. 在宿主机解压并部署到容器
sshpass -p 'zhiyun2026' ssh -o StrictHostKeyChecking=no root@haiqing.heiyu.space "
cd /tmp && tar -xzf agent-swarm-skill.tar.gz && \
cp -r agent-swarm /root/.claude/skills/ && \
/lzcsys/bin/lzc-docker cp /root/.claude/skills/agent-swarm 5f3bf33e090b:/root/.claude/skills/
"
# 5. 重启 OpenClaw
sshpass -p 'zhiyun2026' ssh -o StrictHostKeyChecking=no root@haiqing.heiyu.space \
"/lzcsys/bin/lzc-docker restart 5f3bf33e090b"
# 6. 验证安装
sshpass -p 'zhiyun2026' ssh -o StrictHostKeyChecking=no root@haiqing.heiyu.space \
"/lzcsys/bin/lzc-docker exec 5f3bf33e090b ls /root/.claude/skills/ | wc -l"
# 应该显示: 43 (42 + agent-swarm)
```
#### 使用方法
在飞书中 @OpenClaw 使用以下命令:
```bash
# 查看所有 Agent
/swarm agents
# 启动完整开发工作流(从架构设计开始)
/swarm start "在 new-ai-proj 中实现任务批量删除功能"
# 从特定 Agent 开始
/swarm coder "修复 backend/handlers/task_handler.go 的空指针 bug"
# 并行执行多个任务
/swarm parallel "实现后端API" "实现前端UI" "编写测试"
# 查看执行轨迹
/swarm trace
# 显示配置
/swarm config
```
#### Agent 工作流
```
用户请求 → Architect (需求分析、架构设计)
↓ handoff
Coder (编写代码、实现功能)
↓ handoff
Tester (编写测试、运行测试)
↓ handoff
Reviewer (代码审查、安全检查)
↓ handoff
Deployer (部署服务、监控上线)
完成 ✅
```
#### 5 个预定义 Agent
| Agent | 职责 | Tools | Handoff to |
|-------|------|-------|------------|
| **Architect** | 需求分析、架构设计、技术选型 | Read, Grep, Glob | Coder, Reviewer |
| **Coder** | 编写代码、实现功能、Bug 修复 | Edit, Write, Bash | Tester, Architect |
| **Tester** | 编写测试、运行测试、验证功能 | Bash, Write | Deployer, Coder |
| **Reviewer** | 代码审查、安全检查、质量把关 | Read, Grep | Coder, Deployer |
| **Deployer** | 部署服务、监控上线、健康检查 | Bash, SSH | Monitor, Coder |
#### 配置自定义 Agent (可选)
在项目根目录创建 `swarm.yaml`:
```yaml
agents:
architect:
instructions: |
你是系统架构师,专注于 Go + Vue.js 技术栈。
遵循 RESTful API 设计原则。
max_turns: 5
coder:
instructions: |
你是全栈工程师。
编写清晰、简洁、高性能的代码。
max_turns: 10
context_variables:
project_root: /Users/coolbuy-dev/coding/new-ai-proj
backend_lang: Go 1.21
frontend_framework: Vue 3
database: PostgreSQL 15
```
#### 实际应用场景
**场景 1: 新功能开发**
```bash
/swarm start "为 AI-Proj 实现需求批量导出为 Excel 功能,支持自定义字段和筛选条件"
```
自动执行Architect 设计 → Coder 实现 → Tester 测试 → Reviewer 审查 → Deployer 部署
**场景 2: Bug 修复 + 性能优化**
```bash
/swarm coder "优化任务详情页加载性能,从 3s 降到 300ms 以内"
```
自动执行Coder 优化 → Tester 验证 → Deployer 灰度发布
**场景 3: 代码审查**
```bash
/swarm reviewer "审查 PR #123 的代码质量和安全性"
```
自动执行Reviewer 分析 → Coder 修改 → Deployer 部署
#### 参考资料
- **完整文档**: 容器内 `/root/.claude/skills/agent-swarm/SKILL.md`
- **OpenAI Swarm**: https://github.com/openai/swarm
- **部署日期**: 2026-02-16
- **当前技能总数**: 43 个
### MCP 服务器配置
OpenClaw 支持 MCP (Model Context Protocol),可以连接 ai-proj 等服务。
#### 配置位置
容器内配置文件:`/root/.claude/.mcp.json`
#### 配置步骤
**1. 部署 mcp-task-bridge**
```bash
# 从本地传输 mcp-task-bridge包含编译产物和依赖
cd /Users/coolbuy-dev/coding/new-ai-proj
tar -czf - mcp-task-bridge/dist mcp-task-bridge/package.json mcp-task-bridge/node_modules | \
ssh lazycat "cd /root && tar -xzf -"
# 复制到容器内
ssh lazycat "/lzcsys/bin/lzc-docker cp /root/mcp-task-bridge 5f3bf33e090b:/root/"
# 验证
ssh lazycat "/lzcsys/bin/lzc-docker exec 5f3bf33e090b ls -la /root/mcp-task-bridge/"
ssh lazycat "/lzcsys/bin/lzc-docker exec 5f3bf33e090b node --version"
```
**2. 创建 MCP 配置文件**
```bash
# 创建配置文件
cat > /tmp/mcp-config.json << 'EOF'
{
"mcpServers": {
"ai-proj-prod": {
"type": "stdio",
"command": "node",
"args": ["/root/mcp-task-bridge/dist/index.js"],
"env": {
"NODE_ENV": "production",
"TASK_API_BASE": "https://ai.pipexerp.com/api/v1",
"TASK_API_TOKEN": "aiproj_pk_2ecf8f8728b70afd4420af3875f4f7505c9fe8231a4771972b0f385aa1c75099",
"DEV_LOGIN_USERNAME": "qiudl",
"MCP_SERVER_NAME": "ai-proj-prod"
}
},
"ai-proj-staging": {
"type": "stdio",
"command": "node",
"args": ["/root/mcp-task-bridge/dist/index.js"],
"env": {
"NODE_ENV": "staging",
"TASK_API_BASE": "https://staging.ai.pipexerp.com/api/v1",
"TASK_API_TOKEN": "aiproj_pk_ff1ee5478268fd8fe3f9eeb7dd28c8a35f32026b3a3846715f0a40cad542bdd6",
"DEV_LOGIN_USERNAME": "qiudl",
"MCP_SERVER_NAME": "ai-proj-staging"
}
}
}
}
EOF
# 复制到容器内
scp /tmp/mcp-config.json lazycat:/tmp/
ssh lazycat "/lzcsys/bin/lzc-docker cp /tmp/mcp-config.json 5f3bf33e090b:/root/.claude/.mcp.json"
# 验证配置
ssh lazycat "/lzcsys/bin/lzc-docker exec 5f3bf33e090b cat /root/.claude/.mcp.json" | jq .
```
**3. 重启 OpenClaw**
```bash
ssh lazycat "/lzcsys/bin/lzc-docker restart 5f3bf33e090b"
```
#### 测试 MCP 连接
```bash
# 测试 mcp-task-bridge 可执行性
ssh lazycat "/lzcsys/bin/lzc-docker exec 5f3bf33e090b node /root/mcp-task-bridge/dist/index.js --version"
# 检查配置文件
ssh lazycat "/lzcsys/bin/lzc-docker exec 5f3bf33e090b cat /root/.claude/.mcp.json"
```
#### 更新 MCP 配置
当 mcp-task-bridge 或 API token 更新时:
```bash
# 1. 更新 mcp-task-bridge
cd /Users/coolbuy-dev/coding/new-ai-proj/mcp-task-bridge
npm run build
cd /Users/coolbuy-dev/coding/new-ai-proj
tar -czf - mcp-task-bridge/dist | ssh lazycat "cd /root && tar -xzf -"
ssh lazycat "/lzcsys/bin/lzc-docker cp /root/mcp-task-bridge/dist 5f3bf33e090b:/root/mcp-task-bridge/"
# 2. 更新配置文件(重复上面的步骤 2
# 3. 重启 OpenClaw
ssh lazycat "/lzcsys/bin/lzc-docker restart 5f3bf33e090b"
```
#### 可用的 MCP 服务器
| MCP 服务器 | 环境 | API 地址 | 用途 |
|-----------|------|----------|------|
| ai-proj-prod | 生产 | https://ai.pipexerp.com/api/v1 | 生产数据管理 |
| ai-proj-staging | 测试 | https://staging.ai.pipexerp.com/api/v1 | 测试环境验证 |
#### 故障排查
| 问题 | 可能原因 | 解决方案 |
|------|---------|----------|
| MCP 连接失败 | node 命令不存在 | 检查容器内 node: `docker exec ... which node` |
| Token 认证失败 | API token 过期或错误 | 更新 .mcp.json 中的 TASK_API_TOKEN |
| 找不到模块 | node_modules 缺失 | 重新传输完整的 mcp-task-bridge |
| 网络连接超时 | 容器网络问题 | 检查容器网络:`docker exec ... curl -I https://ai.pipexerp.com` |
---
## OpenClaw 特殊说明
### MCP 协议不兼容
**重要发现**OpenClaw **不支持**标准的 MCP (Model Context Protocol) 配置。
- ❌ 不识别 `~/.claude/.mcp.json`
- ❌ 不支持 `openclaw.json` 中的 `mcpServers` 字段
- ✅ 使用自己的 **Plugins****Skills** 系统
### OpenClaw 工具集成方式
| 集成方式 | 说明 | 适用场景 |
|---------|------|----------|
| **Plugins插件** | TypeScript 模块,在 Gateway 进程内运行 | 复杂工具、需要注册 RPC 方法 |
| **Skills技能** | Markdown + YAML frontmatter指导 AI 使用工具 | 调用外部 API、CLI 工具 |
| **Web Tools** | 网络工具集成 | 网页操作、浏览器自动化 |
### ai-proj 在 OpenClaw 上的配置
由于 OpenClaw 不支持 MCPai-proj 功能通过 **Skill + REST API 调用**实现:
**Skill 位置**`/root/.claude/skills/ai-proj/SKILL.md`(容器内)
**工作原理**
1. Skill 文件提供 API 调用示例curl 命令)
2. OpenClaw AI 根据 skill 指导执行 bash 命令
3. 直接调用 ai-proj REST API无需 MCP bridge
**示例操作**
```bash
# 在 OpenClaw 容器内执行
# 列出项目
curl -s -H "Authorization: Bearer aiproj_pk_2ecf8f8728b70afd4420af3875f4f7505c9fe8231a4771972b0f385aa1c75099" \
"https://ai.pipexerp.com/api/v1/projects?page=1&page_size=10" | jq ".data.data[] | {id, name}"
# 创建任务
curl -s -X POST \
-H "Authorization: Bearer aiproj_pk_2ecf8f8728b70afd4420af3875f4f7505c9fe8231a4771972b0f385aa1c75099" \
-H "Content-Type: application/json" \
-d '{"title":"测试任务","project_id":161}' \
"https://ai.pipexerp.com/api/v1/tasks" | jq .
```
### OpenClaw 容器 SSH 访问本机au-dev
OpenClaw 容器可以通过 Singapore 跳板的反向隧道 SSH 到澳洲开发机au-dev
**链路架构**
```
OpenClaw容器(node@5f3bf33e090b)
→ ssh au-dev
→ ProxyJump singapore(43.134.28.147)
→ 反向隧道 localhost:2222
→ 本机(coolbuy-dev@Coolbuy-dev.local)
```
**前置条件**
1. 本机反向隧道服务运行中:`launchctl list | grep singapore-tunnel`
2. Singapore 端口 2222 监听中:`ssh singapore "ss -tlnp | grep :2222"`
**容器内 SSH 配置**(已配置,路径 `/home/node/.ssh/`
| 文件 | 说明 | 所有者 |
|------|------|--------|
| `id_ed25519` | 容器 SSH 私钥 | node:node |
| `id_ed25519.pub` | 公钥 (`openclaw@iamxiaoe`) | node:node |
| `singpore.pem` | Singapore 跳板密钥 | node:node |
| `config` | SSH 配置(含 ProxyJump | node:node |
**容器内 SSH config 内容**
```
Host lazycat cn-bj-lazycat
HostName 172.28.3.1
User root
StrictHostKeyChecking no
ServerAliveInterval 60
ServerAliveCountMax 3
Host singapore
HostName 43.134.28.147
User ubuntu
IdentityFile /home/node/.ssh/singpore.pem
StrictHostKeyChecking no
ServerAliveInterval 60
ServerAliveCountMax 3
Host au-dev melbourne
HostName localhost
Port 2222
User coolbuy-dev
ProxyJump singapore
StrictHostKeyChecking no
ServerAliveInterval 60
ServerAliveCountMax 3
```
**authorized_keys 配置**
| 目标机器 | 需包含的公钥 |
|---------|-------------|
| au-dev 本机 `~/.ssh/authorized_keys` | `openclaw@iamxiaoe` + `root@cn-bj-lazycat` |
| 宿主机 `/root/.ssh/authorized_keys` | `openclaw@iamxiaoe` |
**使用方式(在容器内以 node 用户执行)**
```bash
# 连接宿主机(通过 Docker 网关 172.28.3.1
ssh lazycat 'hostname && whoami'
ssh cn-bj-lazycat '/lzcsys/bin/lzc-docker ps'
# 连接 au-dev通过 Singapore 反向隧道)
ssh au-dev 'hostname && whoami'
ssh melbourne 'cd /Users/coolbuy-dev/coding/new-ai-proj && git log --oneline -5'
# 传输文件
scp au-dev:/path/to/file /tmp/
scp /tmp/file lazycat:/tmp/
```
**重新配置(容器重建后)**
```bash
LAZYCAT="sshpass -p 'zhiyun2026' ssh -o StrictHostKeyChecking=no -o PubkeyAuthentication=no root@haiqing.heiyu.space"
# 1. 复制 Singapore 密钥到容器
$LAZYCAT "/lzcsys/bin/lzc-docker cp /root/.ssh/singpore.pem 5f3bf33e090b:/home/node/.ssh/singpore.pem"
# 2. 将容器公钥加入宿主机 authorized_keys
$LAZYCAT "grep -q 'openclaw@iamxiaoe' ~/.ssh/authorized_keys || echo 'ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJsGNfvdmA4wCs57O9+tgbSJovDSO5esDyefVJHIoBXg openclaw@iamxiaoe' >> ~/.ssh/authorized_keys"
# 3. 创建 SSH config含宿主机 + Singapore + au-dev
$LAZYCAT "/lzcsys/bin/lzc-docker exec 5f3bf33e090b sh -c 'cat > /home/node/.ssh/config << EOF
Host lazycat cn-bj-lazycat
HostName 172.28.3.1
User root
StrictHostKeyChecking no
ServerAliveInterval 60
ServerAliveCountMax 3
Host singapore
HostName 43.134.28.147
User ubuntu
IdentityFile /home/node/.ssh/singpore.pem
StrictHostKeyChecking no
ServerAliveInterval 60
ServerAliveCountMax 3
Host au-dev melbourne
HostName localhost
Port 2222
User coolbuy-dev
ProxyJump singapore
StrictHostKeyChecking no
ServerAliveInterval 60
ServerAliveCountMax 3
EOF'"
# 4. 修复权限
$LAZYCAT "/lzcsys/bin/lzc-docker exec 5f3bf33e090b sh -c 'chown -R node:node /home/node/.ssh && chmod 700 /home/node/.ssh && chmod 600 /home/node/.ssh/id_ed25519 /home/node/.ssh/config /home/node/.ssh/singpore.pem'"
# 5. 测试宿主机连接
$LAZYCAT "/lzcsys/bin/lzc-docker exec -u node 5f3bf33e090b ssh -o ConnectTimeout=10 lazycat 'hostname && whoami'"
# 6. 测试 au-dev 连接
$LAZYCAT "/lzcsys/bin/lzc-docker exec -u node 5f3bf33e090b ssh -o ConnectTimeout=15 au-dev 'hostname && whoami'"
```
**故障排查**
| 问题 | 可能原因 | 解决方案 |
|------|---------|----------|
| Permission denied (publickey) to au-dev | 公钥未加入本机 authorized_keys | 将 `openclaw@iamxiaoe` 公钥加入本机 `~/.ssh/authorized_keys` |
| Permission denied (publickey) to lazycat | 公钥未加入宿主机 authorized_keys | 将 `openclaw@iamxiaoe` 公钥加入宿主机 `/root/.ssh/authorized_keys` |
| Connection timed out (au-dev) | 反向隧道断开 | 检查本机 `launchctl list \| grep singapore-tunnel`,重启服务 |
| Could not resolve hostname | SSH config 权限错误或缺失 | 检查 `/home/node/.ssh/config` 权限为 600所有者为 node |
| ProxyJump 失败 | singpore.pem 缺失或权限错误 | 重新从宿主机复制密钥到容器 |
| 容器连宿主机失败 | Docker 网关 IP 变化 | 容器内 `ip route \| grep default` 查看网关,更新 SSH config |
### 文档参考
- **OpenClaw 插件系统**https://docs.openclaw.ai/tools/plugin.md
- **OpenClaw Skills**https://docs.openclaw.ai/tools/skills.md
- **OpenClaw 配置**https://docs.openclaw.ai/cli/config