Files
ssh_panel/README.md
T

22 KiB
Raw Blame History

AIGC
AIGC
ContentProducer ContentPropagator Label ProduceID PropagateID ReservedCode1 ReservedCode2
001191110102MAD55U9H0F10002 001191110102MAD55U9H0F10002 1 1148f2f2-715c-4f80-80d7-010cab5af4b0 1148f2f2-715c-4f80-80d7-010cab5af4b0 57f1878c-c8f1-41ec-9020-31dae82dcead 57f1878c-c8f1-41ec-9020-31dae82dcead

WFJ Panel 项目说明文档

一、项目概述

WFJ Panel 是一款基于 Electron + React + ssh2 构建的远程服务器管理面板桌面应用,通过 SSH 协议远程连接 Linux 服务器,提供服务器概览监控、文件管理、交互式终端、Docker 容器管理、应用商店一键部署、防火墙管理等功能。

  • 产品名称:WFJ Panel
  • 版本:v0.0.1
  • 许可:MIT
  • 构建产物:NSIS 安装程序(Windows x64,约 107MB)

二、技术栈

层级 技术 说明
桌面框架 Electron 44 + electron-vite 5 跨平台桌面应用,Vite 驱动构建
前端框架 React 19 函数组件 + Hooks
终端模拟 @xterm/xterm 5 + @xterm/addon-fit 交互式终端渲染
SSH 通信 ssh2 1.17 纯 JS 实现的 SSH2 客户端
打包工具 electron-builder 26 NSIS 安装包
后端服务 Flask 3 + mysql-connector-python 应用商店 API 服务
数据库 MySQL 8 应用商店模板与版本数据

三、项目结构

ssh_panel/
├── package.json                  # 项目元数据、依赖、构建配置
├── electron.vite.config.mjs      # electron-vite 配置(main/preload/renderer 三入口)
├── .npmrc                        # Electron 国内镜像配置
├── .gitignore
├── build/
│   └── icon.png                  # 应用图标 (256x256)
├── src/
│   ├── main/
│   │   └── index.js              # ★ 主进程(1377行)—— SSH 连接、IPC、Docker、部署、SFTP、终端
│   ├── preload/
│   │   └── index.js              # ★ Preload 桥接层 —— 暴露 window.panel API(90行)
│   └── renderer/
│       ├── index.html            # HTML 入口
│       └── src/
│           ├── main.jsx          # React 挂载入口
│           ├── App.jsx           # ★ 根组件 —— 登录/面板切换、连接状态管理
│           ├── theme.css         # 设计令牌(色彩/间距/阴影/按钮体系)
│           ├── main.css          # 全局样式
│           └── pages/
│               ├── Login.jsx     # SSH 登录页(凭据保存/自动填充)
│               ├── Panel.jsx     # ★ 主面板(导航栏 + 功能模块切换 + 版本更新)
│               ├── overview/     # 服务器概览监控
│               │   ├── Overview.jsx
│               │   ├── useMetric.js  # 通用指标采集 Hook
│               │   └── cards/       # CPU/内存/硬盘/网络/进程 五张卡片
│               ├── files/        # SFTP 远程文件管理
│               │   └── FileManager.jsx
│               ├── terminal/     # 交互式终端
│               │   └── TerminalPanel.jsx
│               ├── container/    # Docker 容器管理
│               │   ├── ContainerPanel.jsx  # 容器面板入口(状态检测+子菜单)
│               │   ├── ContainerList.jsx   # 容器列表(启动/停止/删除/日志)
│               │   ├── ImageList.jsx       # 镜像列表
│               │   ├── AppStore.jsx        # ★ 应用商店(在线模板+一键部署)
│               │   ├── TaskCenter.jsx      # 后台部署任务中心
│               │   ├── DockerConfig.jsx    # Docker 配置文件查看/编辑
│               │   ├── NetworkPanel.jsx    # Docker 网络管理
│               │   ├── VolumePanel.jsx     # Docker 卷管理
│               │   ├── ContainerCreate.jsx # 手动创建容器
│               │   ├── DockerLog.jsx       # 容器日志查看
│               │   ├── cmdParser.js        # docker run 命令解析
│               │   └── appTemplates.js    # 内置应用模板(离线备用)
│               └── firewall/      # 系统防火墙管理
│                   └── Firewall.jsx
├── appstore-server/              # 应用商店后端服务
│   ├── app.py                    # Flask API(/api/apps、/api/version、/api/health)
│   ├── init.sql                  # 数据库建表 + 初始数据(Redis/MySQL/Halo 模板)
│   ├── requirements.txt          # Python 依赖
│   ├── Dockerfile                # API 服务容器化
│   └── deploy.sh                 # 一键部署脚本
└── release/                      # 打包产物输出目录(.gitignore)

四、架构设计

4.1 Electron 三层架构

┌─────────────────────────────────────────────────────────┐
│                    渲染进程 (Renderer)                    │
│         React 19 + xterm.js  + CSS                       │
│  ┌──────────┬──────────┬──────────┬────────┬──────────┐ │
│  │  概览监控  │  文件管理  │  交互终端  │ Docker │  防火墙  │ │
│  └─────┬────┴─────┬────┴─────┬────┴───┬────┴─────┬────┘ │
│        │          │          │        │          │       │
│        └──────────┴──────────┴────────┴──────────┘       │
│                      window.panel.*                      │
├─────────────────────────────────────────────────────────┤
│                   Preload (桥接层)                        │
│            contextBridge.exposeInMainWorld               │
│                ipcRenderer.invoke / on                   │
├─────────────────────────────────────────────────────────┤
│                    主进程 (Main)                          │
│  ┌─────────────────────────────────────────────────┐    │
│  │          SSH 连接管理 (ssh2 Client)              │    │
│  │  ┌──────────┬──────────┬───────────┐             │    │
│  │  │ 主连接    │ Docker   │ 部署连接   │             │    │
│  │  │ (exec +  │ 专用连接  │ 专用连接   │             │    │
│  │  │  sftp +  │ (独立队列)│ (后台任务) │             │    │
│  │  │  shell)  │          │           │             │    │
│  │  └──────────┴──────────┴───────────┘             │    │
│  │          串行队列 (execQueue)                      │    │
│  └─────────────────────────────────────────────────┘    │
│                    IPC Handlers                         │
│            ssh / cred / sftp / shell /                  │
│            docker / appstore / app                       │
├─────────────────────────────────────────────────────────┤
│               应用商店后端 (appstore-server)              │
│            Flask API  ←→  MySQL 8                      │
│            /api/apps  ·  /api/version  ·  /api/health    │
└─────────────────────────────────────────────────────────┘

4.2 三条 SSH 连接设计

这是本项目的核心架构决策,通过连接隔离避免不同模块互相阻塞:

连接 变量名 用途 特点
主连接 activeConnection 概览监控、SFTP 文件管理、交互式终端 登录时建立;exec + sftp 共用串行队列
Docker 连接 dockerConnection Docker 容器/镜像/网络/卷管理 登录时自动建立;独立串行队列
部署连接 deployConnection 应用商店后台部署任务 懒创建(首次部署时建立);直接并发 exec

串行队列机制:

  • 主连接和 Docker 连接各有独立的串行队列(execQueue / dockerQueue)
  • 同一连接同一时刻只执行一个 channel,避免并发打开过多 channel 导致 Channel open failure: open failed 错误
  • 命令轻量(如 free -m),串行执行几乎无感知延迟
  • 部署连接不串行(部署任务内部已 await 顺序执行,任务间可并行)

4.3 安全设计

  • contextIsolation: true:渲染进程与 Node.js 隔离,无法直接 require
  • nodeIntegration: false:渲染进程无 Node.js 权限
  • sandbox: false:preload 可用 Node.js(暴露受控 API)
  • 密码加密存储:使用 Electron safeStorage API(Windows 上为 DPAPI 加密),不可用时降级 base64
  • API 鉴权:应用商店 API 通过 Authorization: Bearer <token> 校验

五、功能模块详解

5.1 登录与凭据管理

  • SSH 连接表单(host / port / username / password)
  • 「记住密码」:连接成功后加密保存到本机 userData/credentials.json
  • 已保存服务器列表:点击快速填充、删除
  • 打开时自动预填最近一次保存的凭据

5.2 服务器概览监控

五张实时卡片,每张卡片独立轮询:

卡片 数据源命令 刷新间隔
CPU top -bn1 / mpstat / vmstat 2s
内存 free -m 3s
硬盘 df -h 15s
网络 /proc/net/dev 两次采样计算速率 2s
进程 ps aux + ss -tlnp/netstat -tlnp(监听端口) 5s
  • 依赖检测:useMetric Hook 检测命令是否存在(如 sysstat 未安装时卡片置灰,提供一键安装按钮)
  • CPU% / 内存% 点击排序(降序,表头高亮箭头)
  • 进程卡片显示监听端口(蓝色徽章)

5.3 SFTP 文件管理

  • 远程目录浏览(目录优先排序)
  • 文件上传(支持多选,实时进度推送 sftp:progress)
  • 文件下载(单文件保存对话框,批量下载到指定目录)
  • 新建远程目录
  • 删除(统一用 rm -rf,路径用单引号包裹防止注入)
  • SFTP 会话缓存复用(同一个 channel)

5.4 交互式终端

  • 基于 xterm.js + ssh2 PTY 实现
  • 深色主题(#1a1d29 背景,靛蓝光标)
  • 支持窗口大小自适应(FitAddon)
  • 切换导航/断开连接/切换服务器/关窗时自动清理 Shell
  • React StrictMode 双挂载防护(setTimeout(0) + disposed 标记)

5.5 Docker 容器管理

子菜单包含 8 个功能页:

子菜单 功能
概览 容器数/镜像数/CPU/内存/缓存/存储路径/配置文件
容器列表 启动/停止/删除/查看日志/进入终端
镜像 镜像列表/删除/清理
应用商店 ★ 在线模板同步 + 一键部署
任务中心 后台部署任务进度(步骤+日志)
配置 Docker daemon.json 查看/编辑
网络 Docker 网络列表/创建/删除
卷 Docker 数据卷列表/删除

Docker 状态管理:

  • 自动检测:command -v docker → docker info
  • 状态机:checking → running / stopped / notInstalled / error
  • 启动/停止按钮(停止时先杀容器再 kill dockerd,防止卡死)

5.6 应用商店一键部署

这是项目的核心特色功能:

数据流:

MySQL (app_templates + 子表) → Flask API → Electron 主进程 (HTTP GET)
    → 本地缓存 (appstore-cache.json) → 前端渲染应用卡片
    → 用户填写参数 → 提交部署 → 后台任务执行 → 实时进度推送

部署步骤(4 步):

  1. 拉取镜像 docker pull <image>(超时 5 分钟)
  2. 创建目录 mkdir -p 宿主机挂载目录
  3. 写入配置 cat > file << 'EOF' heredoc 方式写入配置文件
  4. 创建容器 动态构建 docker run 命令并执行

模板参数系统:

  • {{}} 占位符替换(如 {{REDIS_PASSWORD}}、{{PORT}})
  • 特殊占位符 {{REDIS_PASSWORD_LINE}}:根据密码是否存在动态生成配置行
  • 条件渲染 show_when:如 Halo 选择 MySQL 数据库时才显示 MySQL 配置字段
  • 下拉选项 options(JSON 数组):如 Halo 数据库类型选择 H2/MySQL
  • 环境变量值含空格时自动加单引号包裹(修复 -Xmx256m -Xms256m 的问题)
  • extra_args 额外参数在镜像名前插入(如 Halo 数据库连接参数)

内置模板:

应用 镜像 说明
Redis redis:8.10.0 密码可选,自定义配置文件
MySQL mysql:8.4.11 root 密码必填,自定义 my.cnf
Halo registry.fit2cloud.com/halo/halo:2.26 支持 H2/MySQL 双模式,JVM 参数可调

5.7 防火墙管理

  • 自动检测防火墙类型:firewalld / ufw / iptables
  • firewalld:状态开关、服务/端口管理(添加端口弹窗)
  • ufw / iptables:仅展示规则列表
  • 全程复用 window.panel.exec,零新增 IPC

5.8 客户端版本管理

  • 主进程内置 CLIENT_VERSION 常量
  • 「更新」按钮触发 /api/version 接口检查
  • 弹窗显示三种状态:有新版本(显示更新说明+前往下载)、已是最新、检查失败
  • 下载链接通过 shell.openExternal 在系统浏览器打开

六、IPC API 参考

6.1 SSH 连接

IPC 通道 Preload API 说明
ssh:connect panel.connect(config) 建立 SSH 连接,自动建立 Docker/部署连接
ssh:disconnect panel.disconnect() 断开所有连接
ssh:session panel.getSession() 获取当前会话信息
ssh:exec panel.exec(cmd, timeout) 在主连接上执行命令(串行队列)
ssh:disconnected panel.onDisconnected(cb) 监听连接断开事件

6.2 凭据管理

IPC 通道 Preload API 说明
cred:save panel.saveCredential(cred) 保存凭据(密码加密)
cred:list panel.listCredentials() 列出已保存凭据
cred:delete panel.deleteCredential(key) 删除凭据

6.3 SFTP 文件管理

IPC 通道 Preload API 说明
sftp:list panel.sftpList(path) 列目录
sftp:upload panel.sftpUpload(local, remote) 上传文件
sftp:download panel.sftpDownload(remote, local) 下载文件
sftp:mkdir panel.sftpMkdir(path) 创建目录
sftp:delete panel.sftpDelete(path, isDir, recursive) 删除文件/目录
sftp:selectLocalFile panel.sftpSelectLocalFile() 选择本地文件(多选)
sftp:selectSavePath panel.sftpSelectSavePath(name) 选择保存路径
sftp:selectDownloadDir panel.sftpSelectDownloadDir() 选择下载目录
sftp:progress panel.onSftpProgress(cb) 上传/下载进度事件

6.4 交互式终端

IPC 通道 Preload API 说明
shell:start panel.shellStart(cols, rows) 启动 PTY Shell
shell:write panel.shellWrite(data) 向 Shell 写入数据
shell:resize panel.shellResize(cols, rows) 调整终端窗口大小
shell:close panel.shellClose() 关闭 Shell
shell:data panel.onShellData(cb) 监听 Shell 输出
shell:close panel.onShellClose(cb) 监听 Shell 关闭

6.5 Docker 管理

IPC 通道 Preload API 说明
docker:exec panel.dockerExec(cmd, timeout) 在 Docker 连接上执行命令
docker:disconnect panel.dockerDisconnect() 断开 Docker 连接
docker:deployApp panel.dockerDeployApp(deploy, params) 提交部署任务
docker:checkConnections panel.dockerCheckConnections() 检查 SSH 连接数
docker:listTasks panel.dockerListTasks() 列出所有部署任务
deploy:taskUpdate panel.onDeployTaskUpdate(cb) 监听部署进度更新
docker:ready panel.onDockerReady(cb) Docker 连接就绪事件
docker:disconnected panel.onDockerDisconnected(cb) Docker 连接断开事件

6.6 应用商店与版本管理

IPC 通道 Preload API 说明
appstore:sync panel.appstoreSync() 从远程 API 同步模板到本地
appstore:getLocal panel.appstoreGetLocal() 获取本地缓存模板
appstore:getApiUrl panel.appstoreGetApiUrl() 获取 API 地址
appstore:setApiUrl panel.appstoreSetApiUrl(url) 设置 API 地址
appstore:checkInstalled panel.appstoreCheckInstalled() 检查已安装应用
app:checkUpdate panel.appCheckUpdate() 检查客户端版本更新
app:getVersion panel.appGetVersion() 获取当前版本号
app:openUrl panel.appOpenUrl(url) 用系统浏览器打开 URL

七、应用商店后端服务

7.1 API 端点

路由 方法 说明
/api/apps GET 获取所有应用模板(含完整详情和子表)
/api/apps/<app_key> GET 获取单个应用模板详情
/api/version GET 获取客户端最新版本信息
/api/health GET 健康检查

7.2 数据库表结构

app_templates (主表)
  ├── app_ports          (端口映射子表)
  ├── app_volumes        (挂载卷子表)
  ├── app_envs           (环境变量子表)
  ├── app_mkdirs         (自动创建目录子表)
  ├── app_write_files    (配置文件子表)
  └── app_params         (用户参数子表,含下拉选项和条件显示)

app_version (客户端版本管理表)

7.3 部署方式

# 在服务器上执行
cd appstore-server
bash deploy.sh
# 流程:建表 → 构建镜像 → 启动容器(3001 端口)

环境变量配置:

  • DB_HOST / DB_PORT / DB_USER / DB_PASSWORD / DB_NAME:数据库连接
  • API_PORT:API 监听端口(默认 3001)
  • API_TOKEN:鉴权 token(可选)

八、开发与构建

8.1 环境要求

  • Node.js 18+
  • npm(国内网络建议配置 .npmrc 中的 Electron 镜像)
  • Python 3.12+(应用商店后端)
  • MySQL 8(应用商店数据库)

8.2 开发

npm install          # 安装依赖(Electron 自动走国内镜像)
npm run dev          # 启动开发服务器(Vite HMR 热更新)

开发模式下按 F12 打开开发者工具。

8.3 构建

npm run build        # 构建产物(输出到 out/)
npm run build:win    # 构建 + 打包 Windows 安装程序(输出到 release/)

8.4 关键配置说明

.npmrc(Electron 国内镜像):

electron_mirror=https://npmmirror.com/mirrors/electron/

electron-builder 配置要点:

  • npmRebuild: false:跳过 native 模块编译(ssh2 纯 JS 无需编译)
  • target: nsis:Windows NSIS 安装程序
  • icon: build/icon.png:256x256 应用图标
  • 国内打包需配置 ELECTRON_BUILDER_BINARIES_MIRROR 镜像

九、关键设计决策与踩坑记录

9.1 SSH Channel 并发问题

问题:概览页 5 张卡片各自独立轮询,同时打开的 channel 数超出服务器上限(通常 10 个),报错 Channel open failure: open failed。

方案:在主进程 execSsh 函数增加串行队列(execQueue),所有请求逐个执行,同一时刻只占一个 channel。命令轻量,串行执行几乎无感知延迟。

9.2 React StrictMode 双挂载

问题:开发模式下 React.StrictMode 会执行两次 useEffect(mount→unmount→remount),导致终端首次打开输出重复。

方案:shellStart 放入 setTimeout(0) 延迟执行并配合 disposed 标记,第一次同步 mount→unmount 时被 cleanup 拦截,仅真正 mount 时连接一次。

9.3 Electron 二进制下载失败

问题:npm install 时 Electron postinstall 从 GitHub 下载二进制,国内网络经常失败。

方案:项目根目录创建 .npmrc 写入 electron_mirror=https://npmmirror.com/mirrors/electron/,安装时自动走国内镜像。

9.4 Docker 环境变量含空格

问题:Halo 部署时 JVM_OPTS=-Xmx256m -Xms256m 中空格导致 docker run 拆分参数报 unknown shorthand flag。

方案:环境变量值含空格时自动加单引号包裹(parts.push('-e', "'${pair}'"))。

9.5 部署连接隔离

问题:部署任务耗时较长(拉取镜像可能数分钟),如果复用主连接的串行队列会阻塞概览监控等常规操作。

方案:使用独立的第三条 SSH 连接(deployConnection),懒创建,部署任务直接 exec 不走串行队列,任务内部 await 顺序执行,任务间可并行。


十、扩展指南

10.1 新增应用模板

在 appstore-server/init.sql 中或通过 API 添加新行到 app_templates 主表及对应子表即可,前端无需改代码。mapDbTemplateToFront 函数自动将数据库格式转换为前端 deploy 格式。

10.2 新增功能页面

  1. 在 src/renderer/src/pages/ 下新建组件目录
  2. 在 Panel.jsx 的 NAV_ITEMS 数组添加导航项
  3. 在 Panel.jsx 的 <main> 区域添加条件渲染
  4. 如需主进程支持,在 src/main/index.js 添加 IPC handler,在 src/preload/index.js 暴露 API

10.3 新增 IPC 通道

// 主进程 (src/main/index.js)
ipcMain.handle('my:action', async (event, { param }) => {
  // 业务逻辑
  return { ok: true, data: result }
})

// Preload (src/preload/index.js)
myAction: (param) => ipcRenderer.invoke('my:action', { param })

// 渲染进程
const result = await window.panel.myAction(param)

AI生成