fix: Update readme
55
README-CN.md
@@ -44,22 +44,24 @@
|
|||||||
</p>
|
</p>
|
||||||
|
|
||||||
Termix 是一个开源、永久免费、自托管的一体化服务器管理平台。它提供了一个基于网页的解决方案,通过一个直观的界面管理你的服务器和基础设施。Termix
|
Termix 是一个开源、永久免费、自托管的一体化服务器管理平台。它提供了一个基于网页的解决方案,通过一个直观的界面管理你的服务器和基础设施。Termix
|
||||||
提供 SSH 终端访问、SSH 隧道功能以及远程文件管理,还会陆续添加更多工具。
|
提供 SSH 终端访问、SSH 隧道功能以及远程文件管理,还会陆续添加更多工具。Termix 是适用于所有平台的完美免费自托管 Termius 替代品。
|
||||||
|
|
||||||
# 功能
|
# 功能
|
||||||
|
|
||||||
- **SSH 终端访问** - 功能完整的终端,支持分屏(最多 4 个面板)和标签系统
|
- **SSH 终端访问** - 功能齐全的终端,具有分屏支持(最多 4 个面板)和类似浏览器的选项卡系统。包括对自定义终端的支持,包括常见终端主题、字体和其他组件
|
||||||
- **SSH 隧道管理** - 创建和管理 SSH 隧道,支持自动重连和健康监控
|
- **SSH 隧道管理** - 创建和管理 SSH 隧道,具有自动重新连接和健康监控功能
|
||||||
- **远程文件管理器** - 直接在远程服务器上管理文件,支持查看和编辑代码、图片、音频和视频。无缝上传、下载、重命名、删除和移动文件。
|
- **远程文件管理器** - 直接在远程服务器上管理文件,支持查看和编辑代码、图像、音频和视频。无缝上传、下载、重命名、删除和移动文件
|
||||||
- **SSH 主机管理器** - 保存、组织和管理 SSH 连接,支持标签和文件夹,轻松保存可重用的登录信息,同时能够自动部署 SSH 密钥
|
- **SSH 主机管理器** - 保存、组织和管理您的 SSH 连接,支持标签和文件夹,并轻松保存可重用的登录信息,同时能够自动部署 SSH 密钥
|
||||||
- **服务器统计** - 查看任意 SSH 服务器的 CPU、内存和硬盘使用情况
|
- **服务器统计** - 在任何 SSH 服务器上查看 CPU、内存和磁盘使用情况以及网络、正常运行时间和系统信息
|
||||||
- **用户认证** - 安全的用户管理,支持管理员控制、OIDC 和双因素认证(TOTP)
|
- **仪表板** - 在仪表板上一目了然地查看服务器信息
|
||||||
- **数据库加密** - SQLite 数据库文件在静态时加密,支持自动加密/解密
|
- **用户认证** - 安全的用户管理,具有管理员控制以及 OIDC 和 2FA (TOTP) 支持。查看所有平台上的活动用户会话并撤销权限。
|
||||||
- **数据导出/导入** - 导出和导入 SSH 主机、凭据和文件管理器数据,支持增量同步
|
- **数据库加密** - 后端存储为加密的 SQLite 数据库文件
|
||||||
|
- **数据导出/导入** - 导出和导入 SSH 主机、凭据和文件管理器数据
|
||||||
- **自动 SSL 设置** - 内置 SSL 证书生成和管理,支持 HTTPS 重定向
|
- **自动 SSL 设置** - 内置 SSL 证书生成和管理,支持 HTTPS 重定向
|
||||||
- **现代化界面** - 使用 React、Tailwind CSS 和 Shadcn 构建的简洁桌面/移动友好界面
|
- **现代用户界面** - 使用 React、Tailwind CSS 和 Shadcn 构建的简洁的桌面/移动设备友好界面
|
||||||
- **语言支持** - 内置英语、中文和德语支持
|
- **语言** - 内置支持英语、中文、德语和葡萄牙语
|
||||||
- **平台支持** - 提供 Web 应用、桌面应用程序(Windows 和 Linux)以及 iOS 和 Android 专用移动应用。计划支持 macOS 和 iPadOS。
|
- **平台支持** - 可作为 Web 应用程序、桌面应用程序(Windows、Linux 和 macOS)以及适用于 iOS 和 Android 的专用移动/平板电脑应用程序。
|
||||||
|
- **SSH 工具** - 创建可重用的命令片段,单击即可执行。在多个打开的终端上同时运行一个命令。
|
||||||
|
|
||||||
# 计划功能
|
# 计划功能
|
||||||
|
|
||||||
@@ -69,14 +71,28 @@ Termix 是一个开源、永久免费、自托管的一体化服务器管理平
|
|||||||
|
|
||||||
支持的设备:
|
支持的设备:
|
||||||
|
|
||||||
- 网站(任何现代浏览器,如 Google、Safari 和 Firefox)
|
- 网站(任何平台上的任何现代浏览器,如 Chrome、Safari 和 Firefox)
|
||||||
- Windows(应用程序)
|
- Windows(x64/ia32)
|
||||||
- Linux(应用程序)
|
- 便携版
|
||||||
- iOS(应用程序)
|
- MSI 安装程序
|
||||||
- Android(应用程序)
|
- Chocolatey 软件包管理器
|
||||||
- iPadOS 和 macOS 正在开发中
|
- Linux(x64/ia32)
|
||||||
|
- 便携版
|
||||||
|
- AppImage
|
||||||
|
- Deb
|
||||||
|
- Flatpak
|
||||||
|
- macOS(x64/ia32 on v12.0+)
|
||||||
|
- Apple App Store
|
||||||
|
- DMG
|
||||||
|
- Homebrew
|
||||||
|
- iOS/iPadOS(v15.1+)
|
||||||
|
- Apple App Store
|
||||||
|
- ISO
|
||||||
|
- Android(v7.0+)
|
||||||
|
- Google Play 商店
|
||||||
|
- APK
|
||||||
|
|
||||||
访问 Termix [文档](https://docs.termix.site/install) 获取所有平台的安装信息。或者可以参考以下示例 docker-compose 文件:
|
访问 Termix [文档](https://docs.termix.site/install) 了解有关如何在所有平台上安装 Termix 的更多信息。或者,在此处查看示例 Docker Compose 文件:
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
services:
|
services:
|
||||||
@@ -128,6 +144,7 @@ volumes:
|
|||||||
你的浏览器不支持 video 标签。
|
你的浏览器不支持 video 标签。
|
||||||
</video>
|
</video>
|
||||||
</p>
|
</p>
|
||||||
|
视频和图像可能已过时。
|
||||||
|
|
||||||
# 许可证
|
# 许可证
|
||||||
|
|
||||||
|
|||||||
@@ -75,12 +75,12 @@ Supported Devices:
|
|||||||
|
|
||||||
- Website (any modern browser on any platform like Chrome, Safari, and Firefox)
|
- Website (any modern browser on any platform like Chrome, Safari, and Firefox)
|
||||||
- Windows (x64/ia32)
|
- Windows (x64/ia32)
|
||||||
- Portable EXE
|
- Portable
|
||||||
- MSI Installer
|
- MSI Installer
|
||||||
- Chocolatey Package Manager
|
- Chocolatey Package Manager
|
||||||
- Linux (x64/ia32)
|
- Linux (x64/ia32)
|
||||||
- Portable EXE
|
- Portable
|
||||||
- Appimage
|
- AppImage
|
||||||
- Deb
|
- Deb
|
||||||
- Flatpak
|
- Flatpak
|
||||||
- macOS (x64/ia32 on v12.0+)
|
- macOS (x64/ia32 on v12.0+)
|
||||||
@@ -147,6 +147,7 @@ channel, however, response times may be longer.
|
|||||||
Your browser does not support the video tag.
|
Your browser does not support the video tag.
|
||||||
</video>
|
</video>
|
||||||
</p>
|
</p>
|
||||||
|
Videos and images may be out of date.
|
||||||
|
|
||||||
# License
|
# License
|
||||||
|
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 776 KiB After Width: | Height: | Size: 685 KiB |
|
Before Width: | Height: | Size: 309 KiB After Width: | Height: | Size: 598 KiB |
|
Before Width: | Height: | Size: 418 KiB After Width: | Height: | Size: 402 KiB |
|
Before Width: | Height: | Size: 780 KiB After Width: | Height: | Size: 407 KiB |
|
Before Width: | Height: | Size: 305 KiB After Width: | Height: | Size: 432 KiB |
|
Before Width: | Height: | Size: 360 KiB After Width: | Height: | Size: 307 KiB |
@@ -413,6 +413,27 @@ app.post("/ssh/file_manager/ssh/connect", async (req, res) => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
client.on("error", (err) => {
|
client.on("error", (err) => {
|
||||||
|
if (
|
||||||
|
(err.message.includes("All configured authentication methods failed") ||
|
||||||
|
err.message.includes("No authentication methods remaining")) &&
|
||||||
|
resolvedCredentials.authType === "password" &&
|
||||||
|
!config.password &&
|
||||||
|
resolvedCredentials.password &&
|
||||||
|
!userProvidedPassword
|
||||||
|
) {
|
||||||
|
fileLogger.info(
|
||||||
|
"Retrying password auth with password method for file manager",
|
||||||
|
{
|
||||||
|
operation: "file_connect_retry",
|
||||||
|
sessionId,
|
||||||
|
hostId,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
config.password = resolvedCredentials.password;
|
||||||
|
client.connect(config);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (responseSent) return;
|
if (responseSent) return;
|
||||||
responseSent = true;
|
responseSent = true;
|
||||||
fileLogger.error("SSH connection failed for file manager", {
|
fileLogger.error("SSH connection failed for file manager", {
|
||||||
|
|||||||
@@ -362,7 +362,10 @@ wss.on("connection", async (ws: WebSocket, req) => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
async function handleConnectToHost(data: ConnectToHostData) {
|
async function handleConnectToHost(
|
||||||
|
data: ConnectToHostData,
|
||||||
|
retryWithPassword = false,
|
||||||
|
) {
|
||||||
const { hostConfig, initialPath, executeCommand } = data;
|
const { hostConfig, initialPath, executeCommand } = data;
|
||||||
const {
|
const {
|
||||||
id,
|
id,
|
||||||
@@ -658,6 +661,22 @@ wss.on("connection", async (ws: WebSocket, req) => {
|
|||||||
sshConn.on("error", (err: Error) => {
|
sshConn.on("error", (err: Error) => {
|
||||||
clearTimeout(connectionTimeout);
|
clearTimeout(connectionTimeout);
|
||||||
|
|
||||||
|
if (
|
||||||
|
(err.message.includes("All configured authentication methods failed") ||
|
||||||
|
err.message.includes("No authentication methods remaining")) &&
|
||||||
|
resolvedCredentials.authType === "password" &&
|
||||||
|
!retryWithPassword &&
|
||||||
|
!(hostConfig as any).userProvidedPassword
|
||||||
|
) {
|
||||||
|
sshLogger.info("Retrying password auth with password method", {
|
||||||
|
operation: "ssh_connect_retry",
|
||||||
|
hostId: id,
|
||||||
|
});
|
||||||
|
cleanupSSH();
|
||||||
|
handleConnectToHost(data, true);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (
|
if (
|
||||||
(authMethodNotAvailable && resolvedCredentials.authType === "none") ||
|
(authMethodNotAvailable && resolvedCredentials.authType === "none") ||
|
||||||
(resolvedCredentials.authType === "none" &&
|
(resolvedCredentials.authType === "none" &&
|
||||||
@@ -912,7 +931,7 @@ wss.on("connection", async (ws: WebSocket, req) => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((hostConfig as any).userProvidedPassword) {
|
if ((hostConfig as any).userProvidedPassword || retryWithPassword) {
|
||||||
connectConfig.password = resolvedCredentials.password;
|
connectConfig.password = resolvedCredentials.password;
|
||||||
}
|
}
|
||||||
} else if (
|
} else if (
|
||||||
|
|||||||