# Linux 服务器部署运维设计 ## 1. 背景 `system-ops/deploy` 当前只提供系统部署菜单的基础入口: - `GET /deploy/overview` - `DeployController` - `DeployService` - `DeployOverviewVO` 本次需求是在 `deploy` 模块中补充 Linux 服务器远程运维能力。用户可以维护 Linux 服务器连接配置,基于 SSH/SFTP 连接服务器,完成远程文件上传、下载和基础命令终端操作。命令终端目标体验接近 Xshell 的基础能力。 当前仓库没有前端代码,本设计只定义页面布局、接口契约、后端模块拆分、数据存储和验证方式,不实现真实前端页面。 ## 2. 范围确认 本期只支持 Linux 服务器。 本期包含: - Linux SSH 连接配置的新增、编辑、删除、查询。 - SSH 连接测试。 - SFTP 文件列表、上传、下载、删除、新建目录。 - SSH Shell 基础命令交互。 - 前端单页运维工作台布局设计。 - 连接配置使用文件方式存储,不新建数据库表。 本期不包含: - Windows 服务器。 - FTP 协议。 - 数据库存储连接配置。 - 部署任务编排。 - 命令审批、命令黑名单、命令历史。 - 批量文件压缩下载。 - 数据库专用客户端封装。 - Maven 编译、打包、测试。 说明:需求中提到的 “FPT” 本期按 Linux 服务器常用能力理解为 SFTP。SFTP 复用 SSH 账号、密码和端口,比单独 FTP 更适合本期场景。 ## 3. 总体方案 推荐采用 “SSH/SFTP + WebSocket 终端” 方案: - 服务器连接配置保存到本地 JSON 文件。 - 后端通过 SSH 建立 Linux 连接。 - 文件操作通过 SFTP 通道完成。 - 终端操作通过 SSH Shell 通道完成。 - 前端通过 WebSocket 与后端交换终端输入输出。 该方案可以复用同一份服务器连接配置,不需要引入 Windows 远程协议,也能满足类 Xshell 的基础交互需求。 ## 4. 前端页面布局 页面路径建议沿用当前菜单路径: ```text /systemOps/deploy ``` 页面采用三块工作区: - 左侧:服务器列表。 - 中间:远程文件管理。 - 右侧:连接详情和快捷操作。 - 底部:SSH 终端区。 推荐布局: ```text ┌──────────────────────────────────────────────────────────────┐ │ 顶部工具栏:新增连接 测试连接 刷新 当前连接状态 │ ├──────────────┬──────────────────────────────┬────────────────┤ │ 服务器列表 │ 远程文件管理 │ 连接详情/操作 │ │ │ │ │ │ Linux-测试 │ 路径栏:/opt/app │ 主机/IP │ │ Linux-生产 │ 上传 下载 新建目录 删除 刷新 │ 用户名 │ │ │ │ 端口 │ │ │ 文件表格 │ 测试连接 │ │ │ │ 打开终端 │ ├──────────────┴──────────────────────────────┴────────────────┤ │ 终端 Tabs:Linux-测试 │ │ $ pwd │ │ /opt/app │ └──────────────────────────────────────────────────────────────┘ ``` ### 4.1 服务器列表 左侧服务器列表用于选择当前操作目标。 展示字段: | 字段 | 说明 | |---|---| | 名称 | 服务器显示名称 | | 主机地址 | IP 或域名 | | SSH 端口 | 默认 22 | | 连接状态 | 未测试、连接成功、连接失败 | 交互: - 支持按名称、主机地址搜索。 - 点击服务器后加载连接详情,并将文件管理区切换到该服务器。 - 列表项提供编辑、删除、测试连接入口。 - 删除连接前必须二次确认。 ### 4.2 连接配置弹窗 新增和编辑使用同一个弹窗。 字段: | 字段 | 是否必填 | 说明 | |---|---|---| | 名称 | 是 | 页面展示名称 | | 主机地址 | 是 | Linux 服务器 IP 或域名 | | SSH 端口 | 是 | 默认 22,范围 1-65535 | | 用户名 | 是 | SSH 登录用户 | | 密码 | 新增必填 | 编辑时留空表示不修改 | | 备注 | 否 | 环境说明 | 按钮: - 测试连接。 - 保存。 - 取消。 密码规则: - 新增连接时密码必填。 - 编辑连接时密码不回显。 - 编辑时密码为空表示沿用原密码。 - 查询列表和详情接口均不返回密码。 ### 4.3 远程文件管理 中间文件管理区基于当前选中的服务器工作。 顶部路径栏: - 展示当前远程目录,例如 `/opt/app`。 - 支持返回上级目录。 - 支持点击面包屑跳转到上级路径。 工具栏: - 上传。 - 下载。 - 新建目录。 - 删除。 - 刷新。 文件表格字段: | 字段 | 说明 | |---|---| | 名称 | 文件或目录名称 | | 类型 | 文件、目录、软链接 | | 大小 | 文件大小,目录可为空 | | 权限 | Linux 权限字符串 | | 修改时间 | 远程文件修改时间 | 交互规则: - 双击目录进入下级目录。 - 下载只支持普通文件。 - 删除文件或目录前必须二次确认。 - 本期支持单文件上传和单文件下载。 - 上传目标目录为当前路径。 - 下载目录、批量压缩下载不在本期范围。 ### 4.4 SSH 终端区 底部终端区用于执行 Linux 命令。 交互规则: - 点击“打开终端”后创建 SSH Shell 会话。 - 前端输入通过 WebSocket 实时发送给后端。 - 后端将 Shell 输出通过 WebSocket 实时推送给前端。 - 本期建议限制为每台服务器最多一个终端会话。 - 关闭终端 Tab 时通知后端释放 SSH 会话。 - 终端断开后显示状态,不自动重连。 用户可以在终端中自行执行数据库命令,例如: ```bash mysql -uroot -p psql -h 127.0.0.1 -U postgres redis-cli ``` 后端不解析数据库命令,也不保存命令历史。 ## 5. 后端结构设计 在 `system-ops/deploy` 模块内按职责新增类,保留现有 `DeployController` 的 `/deploy/overview`。 建议结构: ```text system-ops/deploy/src/main/java/com/njcn/gather/systemops/deploy/ ├── config/ ├── controller/ ├── pojo/param/ ├── pojo/vo/ ├── pojo/dto/ ├── repository/ ├── service/ ├── service/impl/ └── websocket/ ``` 职责拆分: | 类 | 职责 | |---|---| | `DeployServerController` | 连接配置查询、新增、编辑、删除、测试连接 | | `DeployFileController` | SFTP 文件列表、上传、下载、删除、新建目录 | | `DeployTerminalWebSocketHandler` | SSH 终端 WebSocket 输入输出转发 | | `DeployServerConfigService` | 连接配置业务校验和编排 | | `DeployServerConfigRepository` | JSON 文件读写 | | `DeploySftpService` | SFTP 文件操作 | | `DeploySshTerminalService` | SSH Shell 会话创建、输入、输出、关闭 | | `DeployCryptoService` | 密码加密和解密 | | `DeployProperties` | deploy 配置项绑定 | ## 6. 连接配置存储 连接配置不入库,使用 JSON 文件落盘。存储目录通过配置指定。 建议配置: ```yaml deploy: storage-dir: ${log.homeDir}/deploy terminal-idle-timeout-minutes: 30 ``` `deploy.crypto-key` 不建议在默认 `application.yml` 中配置明文值。后续实现时可通过环境覆盖或外部配置提供,业务代码只读取配置,不写死密钥。 落盘文件: ```text D:\logs\deploy\deploy-server-connections.json ``` JSON 结构: ```json { "servers": [ { "id": "uuid", "name": "测试服务器", "host": "192.168.1.10", "sshPort": 22, "username": "root", "password": "加密密文", "description": "测试环境", "createdTime": "2026-05-21 14:00:00", "updatedTime": "2026-05-21 14:00:00" } ] } ``` 写文件规则: - 启动时如果文件不存在,自动创建空配置文件。 - 读写方法集中在 `DeployServerConfigRepository`。 - 写入时先写临时文件,再替换正式文件,避免进程中断导致 JSON 损坏。 - 保存和删除操作需要加进程内锁,避免并发写入互相覆盖。 密码规则: - 密码必须加密后落盘。 - 接口返回不包含密码。 - 日志不打印密码。 - 优先复用项目已有加密能力;如没有合适工具,则在 `deploy` 内封装 AES 加解密组件。 - 加密密钥通过配置提供,不在业务代码中硬编码。 ## 7. 接口设计 接口风格沿用当前仓库常见写法:查询和变更优先使用 `POST`,返回 `HttpResult`。 ### 7.1 连接配置接口 | 方法 | 路径 | 说明 | |---|---|---| | `POST` | `/deploy/server/list` | 查询服务器连接配置列表 | | `POST` | `/deploy/server/add` | 新增服务器连接配置 | | `POST` | `/deploy/server/update` | 修改服务器连接配置 | | `POST` | `/deploy/server/delete` | 删除服务器连接配置 | | `POST` | `/deploy/server/test` | 测试 SSH 连接 | 列表返回字段: | 字段 | 说明 | |---|---| | `id` | 连接 ID | | `name` | 服务器名称 | | `host` | 主机地址 | | `sshPort` | SSH 端口 | | `username` | 用户名 | | `description` | 备注 | | `createdTime` | 创建时间 | | `updatedTime` | 更新时间 | 新增参数: | 字段 | 是否必填 | |---|---| | `name` | 是 | | `host` | 是 | | `sshPort` | 是 | | `username` | 是 | | `password` | 是 | | `description` | 否 | 编辑参数: | 字段 | 是否必填 | 说明 | |---|---|---| | `id` | 是 | 连接 ID | | `name` | 是 | 服务器名称 | | `host` | 是 | 主机地址 | | `sshPort` | 是 | SSH 端口 | | `username` | 是 | 用户名 | | `password` | 否 | 为空表示不修改 | | `description` | 否 | 备注 | ### 7.2 文件接口 | 方法 | 路径 | 说明 | |---|---|---| | `POST` | `/deploy/file/list` | 查询远程目录文件列表 | | `POST` | `/deploy/file/mkdir` | 新建远程目录 | | `POST` | `/deploy/file/delete` | 删除远程文件或目录 | | `POST` | `/deploy/file/upload` | 上传本地文件到远程目录 | | `POST` | `/deploy/file/download` | 下载远程普通文件 | 文件列表参数: | 字段 | 是否必填 | 说明 | |---|---|---| | `serverId` | 是 | 服务器连接 ID | | `path` | 是 | 远程目录路径 | 文件列表返回字段: | 字段 | 说明 | |---|---| | `name` | 文件名 | | `path` | 完整路径 | | `type` | `FILE`、`DIRECTORY`、`LINK` | | `size` | 文件大小 | | `permissions` | 权限字符串 | | `modifiedTime` | 修改时间 | 下载接口直接写入 `HttpServletResponse`。下载文件名沿用远程文件名,不追加日期;仓库“导出或生成文件追加日期”的规则适用于后端生成或导出文件,本功能是下载远程已有文件,不改变原文件名。 ### 7.3 终端 WebSocket 终端连接: ```text WebSocket /deploy/terminal?serverId={serverId} ``` 前端发送输入: ```json { "type": "input", "data": "ls -la\n" } ``` 前端发送窗口大小: ```json { "type": "resize", "cols": 120, "rows": 30 } ``` 后端输出: ```json { "type": "output", "data": "total 20\r\n..." } ``` 后端状态: ```json { "type": "status", "status": "CONNECTED" } ``` 异常消息: ```json { "type": "error", "message": "SSH连接失败" } ``` ## 8. 参数校验 后端至少补充以下校验: - 服务器名称不能为空。 - 主机地址不能为空。 - SSH 端口范围为 `1-65535`。 - 用户名不能为空。 - 新增连接时密码不能为空。 - 编辑连接时 `id` 必须存在。 - 删除连接时 `id` 必须存在。 - 同一主机、端口、用户名组合不建议重复保存。 - 文件路径不能为空。 - 文件上传目标必须是远程目录。 - 下载目标必须是远程普通文件。 - 删除路径不能为空,不能删除空路径或根目录 `/`。 - 新建目录名称不能为空,不能包含路径分隔符。 ## 9. 安全与资源控制 安全规则: - 密码不明文落盘。 - 接口返回不包含密码。 - 日志不打印密码、终端输入内容、文件内容。 - 终端不保存命令历史。 - 文件路径需要做基础规范化,避免空路径、非法路径和目录穿越。 - 下载只允许下载普通文件。 资源规则: - SSH 连接测试设置连接超时,例如 5 秒。 - SFTP 操作每次请求创建短连接,操作完成后释放。 - 终端会话保持长连接,关闭 WebSocket 后释放 SSH Session 和 Channel。 - 终端会话设置空闲超时,默认 30 分钟。 - 本期每台服务器最多保留一个终端会话。 ## 10. 依赖建议 后续实现 SSH/SFTP 时建议优先选择 Java 8 可用、项目易接入的 SSH 客户端库,例如 JSch 或 sshj。 选择标准: - 支持 SSH 密码登录。 - 支持 SFTP 文件操作。 - 支持 Shell Channel。 - 能在 Spring Boot 2.3 和 Java 8 下稳定使用。 最终依赖需要写入 `system-ops/deploy/pom.xml`,不影响其他模块。 ## 11. 错误处理 连接测试需要区分常见错误: | 场景 | 返回说明 | |---|---| | 主机不可达 | 连接服务器失败 | | 端口不通 | SSH端口连接失败 | | 账号或密码错误 | SSH认证失败 | | SFTP 打开失败 | 文件通道打开失败 | | 终端打开失败 | Shell通道打开失败 | 接口层仍使用项目现有 `HttpResult` 和 `CommonResponseEnum` 风格。具体错误文案由 Service 返回给 Controller,不新增全局异常体系。 ## 12. 验证方式 默认不执行 Maven 编译、打包、测试命令。后续实现完成后按以下方式验证: - 检查 `deploy` 新增代码只位于 `system-ops/deploy`。 - 新增连接后,接口返回和 JSON 文件内容一致。 - 编辑连接时密码留空不会覆盖原密码。 - 删除连接后,JSON 文件同步移除对应记录。 - 查询接口不返回密码。 - JSON 文件中密码不是明文。 - 测试连接能识别成功、主机不可达、端口不通、账号密码错误。 - 文件列表能展示远程目录内容。 - 上传文件后远程目录可见。 - 下载普通文件内容与远程文件一致。 - 删除文件或目录后远程路径不存在。 - 新建目录后远程路径存在。 - 终端能打开 Linux Shell,执行 `pwd`、`ls -la`、`mysql --version` 等基础命令。 - 关闭终端后,后端 SSH 会话被释放。 ## 13. 后续扩展 后续如需求增加,可以在当前方案基础上扩展: - SSH 私钥登录。 - 多终端 Tab。 - 命令审计和历史记录。 - 命令黑名单或审批。 - 部署脚本编排。 - 文件批量上传和批量下载。 - Windows WinRM 或 PowerShell Remoting。 这些能力不进入本期实现,避免当前 `deploy` 模块从基础入口一次扩张为完整运维平台。