diff --git a/apps/next-terminal/3.1.1/ssh/id_rsa b/apps/next-terminal/3.1.1/ssh/id_rsa deleted file mode 100644 index fe7575508..000000000 --- a/apps/next-terminal/3.1.1/ssh/id_rsa +++ /dev/null @@ -1,49 +0,0 @@ ------BEGIN OPENSSH PRIVATE KEY----- -b3BlbnNzaC1rZXktdjEAAAAABG5vbmUAAAAEbm9uZQAAAAAAAAABAAACFwAAAAdzc2gtcn -NhAAAAAwEAAQAAAgEAqNqKouPlvUBbLv4BUSMxaZu4rFBMKLcl2MSetFAx/Ya/e5JFQ9rZ -RhMmZqx7gfj6/OQTXw9qN43k0XKy0Y9u3APtt9OZ9Y5StcmXljQhy8EQOF+MyZAEY3HpM7 -4xIV+v16z1mBrczZcFUbALVdijPAWhhMZxxhaN+EA8IfA0ByoE++w6XjvrYEOhW2qCMptL -TV6ZSUW7IOOoa/VzZBujUqgXrqiOshVy79mZi/mg5Sctp727JHr4PAw4yEqDHkLX4D97Rc -Qy8FMbmw40my6G+P22YywCdwVXlgZOq1dCuCRVAzl811nnTSLigyll3DBOilkp0RsDATUv -xCYc8UbwIrlUGDFKz8f54BN2kIgUX7OKVFOefhnpwpasZ8BjF+4A+3b5PkxQEg4SYiYWJc -RDIs9pCuSG2kX45PhbGMoWfbqU63pftM2fVtWiStMOZysvfkaLVUhJPQT3TZhiO84mkz6S -juQO2+b7Olb+rSe0naOzewvi72fFzbAOSEe4hj4Ewh38u1gYge5kOSg/SaHcYvVa2OU9Fz -iS5BCKKfcGtvkxl/HNDlNndCVw4DZHxmIkWDDa6uLI3qWn5A+AVP2D8zMTSmn/gkPxkYE5 -lkhWr4aM0/purV2JeupZzSDYa0zWL+6SuEWDL1qw9oglDm209go6jBbjEtaMDxt9YpkCcX -kAAAdQPAxkLDwMZCwAAAAHc3NoLXJzYQAAAgEAqNqKouPlvUBbLv4BUSMxaZu4rFBMKLcl -2MSetFAx/Ya/e5JFQ9rZRhMmZqx7gfj6/OQTXw9qN43k0XKy0Y9u3APtt9OZ9Y5StcmXlj -Qhy8EQOF+MyZAEY3HpM74xIV+v16z1mBrczZcFUbALVdijPAWhhMZxxhaN+EA8IfA0ByoE -++w6XjvrYEOhW2qCMptLTV6ZSUW7IOOoa/VzZBujUqgXrqiOshVy79mZi/mg5Sctp727JH -r4PAw4yEqDHkLX4D97RcQy8FMbmw40my6G+P22YywCdwVXlgZOq1dCuCRVAzl811nnTSLi -gyll3DBOilkp0RsDATUvxCYc8UbwIrlUGDFKz8f54BN2kIgUX7OKVFOefhnpwpasZ8BjF+ -4A+3b5PkxQEg4SYiYWJcRDIs9pCuSG2kX45PhbGMoWfbqU63pftM2fVtWiStMOZysvfkaL -VUhJPQT3TZhiO84mkz6SjuQO2+b7Olb+rSe0naOzewvi72fFzbAOSEe4hj4Ewh38u1gYge -5kOSg/SaHcYvVa2OU9FziS5BCKKfcGtvkxl/HNDlNndCVw4DZHxmIkWDDa6uLI3qWn5A+A -VP2D8zMTSmn/gkPxkYE5lkhWr4aM0/purV2JeupZzSDYa0zWL+6SuEWDL1qw9oglDm209g -o6jBbjEtaMDxt9YpkCcXkAAAADAQABAAACAE2riU34SrtNGSR6jpyF9brAeKg6n22zIWOe -venvYa9fBkGPPPFDf+It+OINwRo+LyWYvBhj/NXlHTYC7qJaugHWhMikOxOrDfy06FedT1 -ZsTkvAGAC3kG01/rFgcTUK0NYCp036PUsMhtPWiMBKUHvRk0SCC9+0jEV/Nqnd1fDdsUE4 -nniuU00KjvR//7fLm03Rj+0WeEdesSBH3XZVCEGDNLGQs2LTXvVZQLoUb6A471VTfvv+3K -SycoQfUkTfNnHegZPL9ip58B7Y3/Xp5wgtnHHt0oxxFqLZ7+H816HghIJhNT3SCwV+YHc4 -2bP5PIeDECsxo6YwkvJFHdcWbGqtUEDawJ+sUit0iBnByvbDRT5iMgcszekdv4FC7YhWxp -nSJCU2GOWIeFKjxcqYkIyYNjJ2+Agh7JQME7pYfeXeyqWlewLi61Xp3jzAU6exH8l/6m0w -luzKDaoyw4XR9apIGkRSbmgi7sMhCqpxgWUuOYZj4cqxOXJsaR9vgdwOpvrvMMTahIjQSc -Es2qzsqvoyqV0pAufOAgO77NgawhGpO6E8nOm2W5TFvfAQLXdjcb7drKTgeSLgfLPeVITH -0a6AYyGij6N1QkOEADH3AwapJwbV6WFb0n/n6CnAfcfZ9ZDRhHC8R14Mc+EhZ2KiwwvKdk -qrchmspx6dWEs/nLABAAABAB7tCOMMbB4KC4/e2GIQCbW1DiTQOWwpGFTjhRf8f41fU6Wg -yT5W7CN4olPUWOnCs+CtyKdCtQdhZzMxhE9Kj01S0hBCJeNQibIq8CKmzab7XvSnSRdzsT -qm7hyo7Yvo3EFeBxHTaOAQ99CcgevX+CYGibj6EXs35vqjRXZ9OEnBJ+bbMJGU5JCINeb8 -ZiC9T/TTXBgemPYcmKb+LzxgJWco8hI9W9t37OmrAagdeXo3P1KWym0rWknlxF9glOdgZe -WsxcaErNhOos6tD2Jq/WUjQdEDwoYscpm5QMwkNqWKdFa/WK60S4e/bZdK/JOV4Dbd0Ukz -pl77sLYP+TT+wMcAAAEBANIwTNTjtoRws0XMioRg1yPU9XA577ZFh0E0qVFyhOKlAaZQo/ -qElZkaqd3IAkxXtJ9T80r5mMZxJL/9PBQIWLCSkvUC91qMNyBw0W9lr5S10JAl5vG27WOt -cGFJzdWa3g9DwZuyr5bTh62zV9ET1v/vr33fGf60g8H9SMQcb2oPqqkoZHMEcgeqhrd843 -zBm7nuFkY74WaCH1n78vkazKSGKVbUxwdh9MgMRW6mYf/HkAM7nuMqcubyZ4oF3OmCEizd -NBoEjAJtQNI5dms0BPuZBoqu1av52F9IIX+PI4miI5E7i8DNImMJQozCLlG4QWBrjd6oAp -UXqBWs+gg7lQEAAAEBAM2n6Vz3tsP4Y2JP3rKHUcCA5JuuzHVuemGj18C6Xh6cdYUy7RSe -F042HBRl/3nuV4H4+lfr3Ur5yCERBdyOUeeuGfNlZhWXwwy+myYSUtT/dNGN5P8wFK/sxc -pmbqM9Sl/TlEudYwqMBZzlzquzys3UBtEmtsM8Bgdxwd+vn94a4nKkGr5X0SfE8evpZWuS -dQywRfA0aPxSwORoTmYzr6yEWQzywYUlC1Gd9hW6Fy8lYKGx9SZXnrvxsRQBQwAQbnvHGL -FbF138AwwkrKJPtedQZkAs4teFg8ggPuA3SpWFcjEJGKQYwkpMxjHmiP9AvS0t34PJOiYa -i9cQ/l2FBHkAAAAWeW91cl9lbWFpbEBleGFtcGxlLmNvbQECAwQF ------END OPENSSH PRIVATE KEY----- diff --git a/apps/next-terminal/3.5.2/.env.sample b/apps/next-terminal/3.5.2/.env.sample new file mode 100644 index 000000000..303e64069 --- /dev/null +++ b/apps/next-terminal/3.5.2/.env.sample @@ -0,0 +1,10 @@ +CONTAINER_NAME="next-terminal" +PANEL_APP_PORT_HTTP="40058" +PANEL_APP_PORT_SSH="40059" +DATA_PATH="./data" +PANEL_DB_TYPE="postgresql" +PANEL_DB_HOST="" +PANEL_DB_PORT="5432" +PANEL_DB_NAME="next_terminal" +PANEL_DB_USER="next_terminal" +PANEL_DB_USER_PASSWORD="next_terminal" diff --git a/apps/next-terminal/3.5.2/data.yml b/apps/next-terminal/3.5.2/data.yml new file mode 100644 index 000000000..be1d37677 --- /dev/null +++ b/apps/next-terminal/3.5.2/data.yml @@ -0,0 +1,157 @@ +additionalProperties: + formFields: + - default: 40058 + edit: true + envKey: PANEL_APP_PORT_HTTP + labelEn: Web UI Port + labelZh: Web UI 端口 + label: + en: 'Web UI Port' + zh: 'Web UI 端口' + zh-Hant: 'Web UI 埠' + ja: 'Web UI ポート' + ko: 'Web UI 포트' + ru: 'Порт Web UI' + ms: 'Port Web UI' + pt-br: 'Porta da Web UI' + required: true + rule: paramPort + type: number + - default: 40059 + edit: true + envKey: PANEL_APP_PORT_SSH + labelEn: SSH proxy port + labelZh: SSH 代理端口 + label: + en: 'SSH proxy port' + zh: 'SSH 代理端口' + zh-Hant: 'SSH 代理埠' + ja: 'SSH プロキシポート' + ko: 'SSH 프록시 포트' + ru: 'Порт SSH-прокси' + ms: 'Port proksi SSH' + pt-br: 'Porta do proxy SSH' + required: false + rule: paramPort + type: number + - default: ./data + edit: true + envKey: DATA_PATH + labelEn: Data folder path + labelZh: 数据文件夹路径 + label: + en: 'Data folder path' + zh: '数据文件夹路径' + zh-Hant: '資料夾路徑' + ja: 'データフォルダパス' + ko: '데이터 폴더 경로' + ru: 'Путь к папке данных' + ms: 'Laluan folder data' + pt-br: 'Caminho da pasta de dados' + required: true + type: text + - default: postgresql + envKey: PANEL_DB_TYPE + labelEn: Database runtime + labelZh: 数据库 Runtime + label: + en: 'Database runtime' + zh: '数据库 Runtime' + zh-Hant: '資料庫 Runtime' + ja: 'データベース Runtime' + ko: '데이터베이스 Runtime' + ru: 'Среда базы данных' + ms: 'Runtime pangkalan data' + pt-br: 'Runtime de banco de dados' + required: true + type: apps + values: + - label: PostgreSQL + value: postgresql + child: + default: '' + envKey: PANEL_DB_HOST + labelEn: PostgreSQL service + labelZh: PostgreSQL 服务 + label: + en: 'PostgreSQL service' + zh: 'PostgreSQL 服务' + zh-Hant: 'PostgreSQL 服務' + ja: 'PostgreSQL サービス' + ko: 'PostgreSQL 서비스' + ru: 'Сервис PostgreSQL' + ms: 'Perkhidmatan PostgreSQL' + pt-br: 'Serviço PostgreSQL' + required: true + type: service + - default: 5432 + edit: true + envKey: PANEL_DB_PORT + labelEn: Database port + labelZh: 数据库端口 + label: + en: 'Database port' + zh: '数据库端口' + zh-Hant: '資料庫連接埠' + ja: 'データベースポート' + ko: '데이터베이스 포트' + ru: 'Порт базы данных' + ms: 'Port pangkalan data' + pt-br: 'Porta do banco de dados' + required: true + rule: paramPort + type: number + - default: next_terminal + edit: true + envKey: PANEL_DB_NAME + labelEn: Database name + labelZh: 数据库名 + label: + en: 'Database name' + zh: '数据库名' + zh-Hant: '資料庫名' + ja: 'データベース名' + ko: '데이터베이스 이름' + ru: 'Имя базы данных' + ms: 'Nama pangkalan data' + pt-br: 'Nome do banco de dados' + random: true + required: true + rule: paramCommon + type: text + - default: next_terminal + edit: true + envKey: PANEL_DB_USER + labelEn: Database user + labelZh: 数据库用户 + label: + en: 'Database user' + zh: '数据库用户' + zh-Hant: '資料庫用戶' + ja: 'データベースユーザー' + ko: '데이터베이스 사용자' + ru: 'Пользователь базы данных' + ms: 'Pengguna pangkalan data' + pt-br: 'Usuário do banco de dados' + random: true + required: true + rule: paramCommon + type: text + - default: next_terminal + edit: true + envKey: PANEL_DB_USER_PASSWORD + labelEn: Database password + labelZh: 数据库用户密码 + label: + en: 'Database password' + zh: '数据库用户密码' + zh-Hant: '資料庫用戶密碼' + ja: 'データベースユーザーパスワード' + ko: '데이터베이스 사용자 비밀번호' + ru: 'Пароль пользователя базы данных' + ms: 'Kata laluan pengguna pangkalan data' + pt-br: 'Senha do usuário do banco de dados' + random: true + required: true + rule: paramComplexity + type: password diff --git a/apps/next-terminal/3.5.2/docker-compose.yml b/apps/next-terminal/3.5.2/docker-compose.yml new file mode 100644 index 000000000..d522a8298 --- /dev/null +++ b/apps/next-terminal/3.5.2/docker-compose.yml @@ -0,0 +1,41 @@ +services: + nt-guacd: + container_name: ${CONTAINER_NAME}-guacd + restart: always + networks: + - 1panel-network + volumes: + - "${DATA_PATH}:/usr/local/next-terminal/data" + image: dushixiang/guacd:1.6.0@sha256:40872b125c3d946314bd322a3a54325ee2d9a58ecd788f76720ca11874548e42 + labels: + createdBy: "Apps" + + next-terminal: + container_name: ${CONTAINER_NAME} + restart: always + networks: + - 1panel-network + ports: + - "${PANEL_APP_PORT_HTTP}:8088" + - "${PANEL_APP_PORT_SSH}:2022" + volumes: + - "${DATA_PATH}:/usr/local/next-terminal/data" + - "${DATA_PATH}/logs:/usr/local/next-terminal/logs" + - "${DATA_PATH}/config.yaml:/etc/next-terminal/config.yaml:ro" + - "/etc/localtime:/etc/localtime:ro" + depends_on: + nt-guacd: + condition: service_started + healthcheck: + test: ["CMD-SHELL", "wget --quiet --tries=1 --spider http://127.0.0.1:8088/login || exit 1"] + interval: 30s + timeout: 10s + retries: 5 + start_period: 30s + image: dushixiang/next-terminal:v3.5.2@sha256:4e095f8a0309878e2966d3157af5667b6911b6890d5e4c4abfa5116e0209ca3e + labels: + createdBy: "Apps" + +networks: + 1panel-network: + external: true diff --git a/apps/next-terminal/3.5.2/scripts/init.sh b/apps/next-terminal/3.5.2/scripts/init.sh new file mode 100755 index 000000000..ef4cd7c79 --- /dev/null +++ b/apps/next-terminal/3.5.2/scripts/init.sh @@ -0,0 +1,123 @@ +#!/usr/bin/env bash +set -euo pipefail + +ROOT_DIR="$(cd "$(dirname "$0")/.." && pwd)" +ENV_FILE="${ENV_FILE:-${ROOT_DIR}/.env}" + +fail() { + printf '%s\n' "$1" >&2 + exit 1 +} + +get_env_value() { + local key="$1" + local default="$2" + local value="" + + if [[ -f "$ENV_FILE" ]]; then + value="$(sed -n -E "s/^${key}=//p" "$ENV_FILE" | tail -n 1 || true)" + value="${value%\"}" + value="${value#\"}" + value="${value%\'}" + value="${value#\'}" + fi + + if [[ -n "$value" ]]; then + printf '%s\n' "$value" + else + printf '%s\n' "$default" + fi +} + +resolve_app_path() { + local raw="$1" + if [[ "$raw" = /* ]]; then + printf '%s\n' "$raw" + else + printf '%s\n' "${ROOT_DIR}/${raw#./}" + fi +} + +yaml_escape() { + local value="$1" + value="${value//\\/\\\\}" + value="${value//\"/\\\"}" + printf '%s\n' "$value" +} + +[[ -f "$ENV_FILE" ]] || fail "Environment file not found: ${ENV_FILE}" + +DATA_DIR="$(resolve_app_path "$(get_env_value DATA_PATH ./data)")" +CONFIG_FILE="${DATA_DIR}/config.yaml" +LOG_DIR="${DATA_DIR}/logs" +CONTAINER_NAME="$(get_env_value CONTAINER_NAME next-terminal)" +DB_HOST="$(get_env_value PANEL_DB_HOST '')" +DB_PORT="$(get_env_value PANEL_DB_PORT 5432)" +DB_NAME="$(get_env_value PANEL_DB_NAME next_terminal)" +DB_USER="$(get_env_value PANEL_DB_USER next_terminal)" +DB_PASSWORD="$(get_env_value PANEL_DB_USER_PASSWORD next_terminal)" + +[[ -n "$DB_HOST" ]] || fail "PANEL_DB_HOST is required. Select a running PostgreSQL application and service in 1Panel." + +mkdir -p "$DATA_DIR" "$LOG_DIR" + +if [[ -d "$CONFIG_FILE" ]]; then + backup="${CONFIG_FILE}.dir-backup-$(date +%Y%m%d%H%M%S)" + mv "$CONFIG_FILE" "$backup" + echo "Moved directory blocking config.yaml to $backup" +fi + +if [[ -f "$CONFIG_FILE" ]]; then + CURRENT_DB_HOST="$(sed -n -E 's/^[[:space:]]*Hostname:[[:space:]]*"?([^"[:space:]]+)"?[[:space:]]*$/\1/p' "$CONFIG_FILE" | head -n 1)" + [[ -n "$CURRENT_DB_HOST" ]] || fail "Existing config.yaml has an unrecognized database host; it was preserved and the operation was stopped." + [[ "$CURRENT_DB_HOST" == "$DB_HOST" ]] || fail "Existing config.yaml uses database host '${CURRENT_DB_HOST}', but 1Panel selected '${DB_HOST}'. The file was preserved; migrate the database and configuration manually before retrying." + echo "Next Terminal config already exists: $CONFIG_FILE" + exit 0 +fi + +cat > "$CONFIG_FILE" </dev/null 2>&1; then + docker-compose down --volumes --remove-orphans +else + docker compose down --volumes --remove-orphans +fi diff --git a/apps/next-terminal/3.5.2/scripts/upgrade.sh b/apps/next-terminal/3.5.2/scripts/upgrade.sh new file mode 100755 index 000000000..04cc16a2e --- /dev/null +++ b/apps/next-terminal/3.5.2/scripts/upgrade.sh @@ -0,0 +1,74 @@ +#!/usr/bin/env bash +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +ROOT_DIR="$(cd "${SCRIPT_DIR}/.." && pwd)" +ENV_FILE="${ENV_FILE:-${ROOT_DIR}/.env}" + +get_env_value() { + local key="$1" + local default="$2" + local value="" + + if [[ -f "$ENV_FILE" ]]; then + value="$(sed -n -E "s/^${key}=//p" "$ENV_FILE" | tail -n 1 || true)" + value="${value%\"}" + value="${value#\"}" + value="${value%\'}" + value="${value#\'}" + fi + + if [[ -n "$value" ]]; then + printf '%s\n' "$value" + else + printf '%s\n' "$default" + fi +} + +resolve_app_path() { + local raw="$1" + if [[ "$raw" = /* ]]; then + printf '%s\n' "$raw" + else + printf '%s\n' "${ROOT_DIR}/${raw#./}" + fi +} + +restore_previous_release() { + if command -v docker-compose >/dev/null 2>&1; then + (cd "$ROOT_DIR" && docker-compose up -d) + elif command -v docker >/dev/null 2>&1 && docker compose version >/dev/null 2>&1; then + (cd "$ROOT_DIR" && docker compose up -d) + else + printf '%s\n' "Unable to restore the previous release because Docker Compose is unavailable." >&2 + return 1 + fi +} + +refuse_direct_upgrade() { + local reason="$1" + printf '%s\n' "$reason" >&2 + if restore_previous_release; then + printf '%s\n' "The previous Next Terminal release was restored. Install 3.5.2 separately and migrate the database manually." >&2 + else + printf '%s\n' "Previous-release restoration failed; start the existing compose manually before retrying." >&2 + fi + return 1 +} + +DATA_DIR="$(resolve_app_path "$(get_env_value DATA_PATH ./data)")" +DB_HOST="$(get_env_value PANEL_DB_HOST '')" + +if [[ -d "${DATA_DIR}/postgresql" ]]; then + refuse_direct_upgrade "Direct upgrade from the bundled-PostgreSQL layout is not supported." +fi + +if [[ -z "$DB_HOST" ]]; then + refuse_direct_upgrade "PANEL_DB_HOST is missing; select a PostgreSQL service on a fresh 3.5.2 installation." +fi + +if ! bash "${SCRIPT_DIR}/init.sh"; then + refuse_direct_upgrade "Next Terminal upgrade preflight failed without changing the existing configuration." +fi + +echo "Next Terminal external PostgreSQL upgrade preflight completed." diff --git a/apps/next-terminal/README.md b/apps/next-terminal/README.md index 0275994b8..82db99403 100644 --- a/apps/next-terminal/README.md +++ b/apps/next-terminal/README.md @@ -1,16 +1,16 @@ # Next Terminal ## 产品介绍 -一个简单好用安全的交互审计系统,支持 RDP、SSH、VNC、Telnet、Kubernetes 等协议。 +Next Terminal 是一个交互式运维审计系统,支持 RDP、SSH、VNC、Telnet、Kubernetes 等协议。 -当前应用包按 Next Terminal 官方容器部署方式提供 Next Terminal、Guacd 和 PostgreSQL 服务。安装脚本会在数据目录中生成 `config.yaml`,并保留已经存在的配置文件。 +`3.5.2` 和 `latest` 版本部署 Next Terminal 与 Guacd,并连接用户在 1Panel 安装表单中选择的 PostgreSQL 应用服务。历史 `3.1.1` 版本保留原有的内置 PostgreSQL 拓扑,仅用于兼容已有安装。 ## 主要功能 -- 管理和审计 RDP、SSH、VNC、Telnet、Kubernetes 等远程连接。 +- 管理和审计远程连接与会话。 - 使用 Guacd 提供远程桌面协议支持。 -- 使用内置 PostgreSQL 保存应用数据。 -- 持久化配置、日志、录屏和数据库数据。 -- Web UI 与 SSH 代理端口可在 1Panel 表单中配置。 +- 持久化配置、日志和录屏文件。 +- 在 1Panel 中选择并关联 PostgreSQL 应用服务。 +- Web UI 与 SSH 代理端口可在安装表单中配置。 ## 访问说明 安装完成后,通过应用表单中的 Web UI 端口访问: @@ -19,54 +19,69 @@ http://<服务器 IP>: ``` -`SSH 代理端口` 仅在 Next Terminal 后台启用 SSH 代理服务后使用。升级或迁移前,请先在 1Panel 中备份应用数据目录。 +首次安装请访问 `/setup` 初始化管理员。`SSH 代理端口` 仅在 Next Terminal 后台启用 SSH 代理服务后使用。 -## Introduction -Next Terminal is a simple and secure interactive audit system supporting RDP, SSH, VNC, Telnet, Kubernetes, and related remote access protocols. +## 部署拓扑 +- `3.5.2`、`latest`:Next Terminal + Guacd + 1Panel PostgreSQL 应用服务。 +- `3.1.1`:Next Terminal + Guacd + 应用包内置 PostgreSQL,仅作为历史兼容版本保留。 +- `latest` 当前固定到已审计的 `3.5.2` 镜像,不跟随未审计的浮动标签。 +- 支持架构:amd64、arm64。 -This package follows the official container deployment model and includes Next Terminal, Guacd, and PostgreSQL. The install script generates `config.yaml` in the data directory and preserves an existing config file. +## PostgreSQL 联动 +安装 `3.5.2` 或 `latest` 前,请先在 1Panel 应用商店安装并启动 PostgreSQL 16.x。安装表单会先选择 PostgreSQL 应用,再选择实际运行的服务实例;不要手工填写容器主机名。 -## Features -- Manage and audit RDP, SSH, VNC, Telnet, Kubernetes, and related remote sessions. -- Use Guacd for remote desktop protocol support. -- Store application data in the bundled PostgreSQL service. -- Persist config, logs, recordings, and database files. -- Configure Web UI and SSH proxy ports from the 1Panel form. - -## 应用简介 -一个简单好用安全的交互审计系统,支持 RDP、SSH、VNC、Telnet、Kubernetes 等协议。 - -英文说明:A simple and secure interactive audit system supporting RDP, SSH, VNC, Telnet, Kubernetes, and related remote access protocols. - -## 部署说明 -- 本应用使用 Docker Compose 在 1Panel 中部署。 -- 当前容器版本需要 `config.yaml` 和 PostgreSQL;安装脚本会在数据目录中自动生成 `config.yaml`。 -- 应用分类:工具。 -- 支持架构:amd64。 -- 可选版本:`latest`、`3.1.1`。 +1Panel 会根据 `PANEL_DB_NAME`、`PANEL_DB_USER` 和 `PANEL_DB_USER_PASSWORD` 创建并关联应用数据库。PostgreSQL 的数据目录、备份和大版本升级由所选 PostgreSQL 应用负责,不属于 Next Terminal 的 `DATA_PATH`。 ## 端口 | 变量 | 说明 | 默认值 | 必填 | | --- | --- | --- | --- | -| PANEL_APP_PORT_HTTP | Web UI 端口 | 40058 | 是 | -| PANEL_APP_PORT_SSH | SSH 代理端口,需在 Next Terminal 后台启用 SSH 代理服务器 | 40059 | 否 | +| `PANEL_APP_PORT_HTTP` | Web UI 端口 | 40058 | 是 | +| `PANEL_APP_PORT_SSH` | SSH 代理端口 | 40059 | 否 | ## 数据持久化 | 路径 | 说明 | | --- | --- | -| `DATA_PATH` | Next Terminal 数据、日志、`config.yaml` 和内置 PostgreSQL 数据目录 | -| `DATA_PATH/postgresql` | PostgreSQL 数据目录 | -| `DATA_PATH/logs` | Next Terminal 日志目录 | +| `DATA_PATH` | Next Terminal 配置、日志、录屏及 Guacd 共享数据 | +| `DATA_PATH/config.yaml` | 自动生成的应用配置;存在时不会被覆盖 | +| `DATA_PATH/logs` | Next Terminal 日志 | +| PostgreSQL 应用数据目录 | 数据库持久化位置,由所选 PostgreSQL 应用管理 | -升级或迁移前,请在 1Panel 中备份应用数据目录。 +历史 `3.1.1` 安装的数据库仍位于 `DATA_PATH/postgresql`。新版本不会读取、移动或删除该目录。 -## 数据库 -当前应用包按官方容器部署方式内置 PostgreSQL 服务,并通过 `PANEL_DB_NAME`、`PANEL_DB_USER`、`PANEL_DB_USER_PASSWORD` 初始化数据库。 +## 3.5.2 镜像来源 +- 官方容器安装文档使用 `dushixiang/next-terminal` 和 `dushixiang/guacd`,官方 Compose 同时使用 PostgreSQL 16.4。 +- `dushixiang/next-terminal:v3.5.2` 的多架构 manifest 固定为 `sha256:4e095f8a0309878e2966d3157af5667b6911b6890d5e4c4abfa5116e0209ca3e`。 +- 上游仓库存在提交 `7704b32dde617c161540432b6f71867fb3cf9ed8`,提交信息为 `v3.5.2`;截至 2026-07-23,上游没有同名 Git tag 或 GitHub Release,因此本应用将其标记为官方发布镜像版本,不把它表述为 GitHub 正式 Release。 +- Docker Hub 的 `dushixiang/next-terminal` 仓库在 2026-07-23 显示约 100 万次拉取。本应用按高下载量可信镜像策略接受该来源,并固定 manifest digest 防止标签漂移。 +- Guacd 固定为上游兼容版本 `1.6.0`,manifest 为 `sha256:40872b125c3d946314bd322a3a54325ee2d9a58ecd788f76720ca11874548e42`。 + +这些容器不需要特权模式、Docker Socket、额外 capability 或 host network。上游镜像默认以 root 用户运行,部署前应按实际暴露范围配置防火墙和反向代理。 ## 升级注意 -Next Terminal 上游历史版本存在不兼容迁移,旧的 SQLite/单容器部署不能保证无缝升级到当前 PostgreSQL 部署。应用包已关闭跨版本升级;如需迁移旧数据,请先按官方文档导出/备份,再在新部署中恢复。 +应用继续设置 `crossVersionUpdate: false`。不支持从 `3.1.1` 直接升级到 `3.5.2`,因为数据库拓扑从包内 PostgreSQL 改为 1Panel PostgreSQL 应用服务。 + +新版本初始化脚本会在缺少 `PANEL_DB_HOST` 时停止;如果已有 `config.yaml` 中的数据库主机与所选 PostgreSQL 服务不同,也会停止并保留原文件。脚本不会重写配置、迁移数据库或删除 `DATA_PATH/postgresql`。 + +由于两个版本的主版本号同为 3,1Panel 仍可能显示升级入口。目标版本的 `upgrade.sh` 会检测旧的 `DATA_PATH/postgresql` 或缺失的 `PANEL_DB_HOST`,恢复仍在磁盘上的旧 Compose 后拒绝升级;面板会显示升级失败,但旧版本容器和数据会继续保留。不要重复点击升级,请按下述迁移流程新装。 + +迁移时请先备份 `DATA_PATH` 和旧 PostgreSQL 数据库,再安装 PostgreSQL 16.x,使用 PostgreSQL 原生备份/恢复或 Next Terminal 官方备份恢复流程迁移数据,最后新装 `3.5.2` 并验证业务数据。旧实例确认无误前不要卸载。 + +## Introduction +Next Terminal is an interactive operations-audit platform supporting RDP, SSH, VNC, Telnet, Kubernetes, and related protocols. + +Versions `3.5.2` and `latest` deploy Next Terminal with Guacd and require a PostgreSQL 16.x service selected from an installed 1Panel PostgreSQL application. The historical `3.1.1` package retains its bundled PostgreSQL topology for existing installations. + +The `v3.5.2` image is referenced by the upstream deployment channel and has a matching upstream source commit, but no matching Git tag or GitHub Release was available on 2026-07-23. The package therefore pins the published multi-architecture image digest and documents the Docker Hub repository's approximately one million pulls. Direct `3.1.1` to `3.5.2` upgrades remain disabled because database migration is manual. + +## Features +- Manage and audit remote connections and sessions. +- Use Guacd for remote desktop protocol support. +- Persist configuration, logs, and recordings. +- Select and link a PostgreSQL service from the 1Panel application form. ## 参考资料 -- 官网: -- 文档: -- 源码: +- 官网: +- 文档: +- 容器安装: +- 源码: +- 镜像: diff --git a/apps/next-terminal/data.yml b/apps/next-terminal/data.yml index 0f9c303c8..aec4c7a49 100644 --- a/apps/next-terminal/data.yml +++ b/apps/next-terminal/data.yml @@ -23,8 +23,9 @@ additionalProperties: crossVersionUpdate: false limit: 0 recommend: 0 - website: https://next-terminal.typesafe.cn/ - github: https://github.com/dushixiang/next-terminal - document: https://docs.next-terminal.typesafe.cn/ + website: https://www.next-terminal.com/ + github: https://github.com/next-terminal/next-terminal + document: https://docs.next-terminal.com/ architectures: - amd64 + - arm64 diff --git a/apps/next-terminal/latest/.env.sample b/apps/next-terminal/latest/.env.sample index 8e0acd50e..303e64069 100644 --- a/apps/next-terminal/latest/.env.sample +++ b/apps/next-terminal/latest/.env.sample @@ -2,6 +2,9 @@ CONTAINER_NAME="next-terminal" PANEL_APP_PORT_HTTP="40058" PANEL_APP_PORT_SSH="40059" DATA_PATH="./data" +PANEL_DB_TYPE="postgresql" +PANEL_DB_HOST="" +PANEL_DB_PORT="5432" PANEL_DB_NAME="next_terminal" PANEL_DB_USER="next_terminal" PANEL_DB_USER_PASSWORD="next_terminal" diff --git a/apps/next-terminal/latest/data.yml b/apps/next-terminal/latest/data.yml index 04fbf53a3..be1d37677 100644 --- a/apps/next-terminal/latest/data.yml +++ b/apps/next-terminal/latest/data.yml @@ -50,6 +50,57 @@ additionalProperties: pt-br: 'Caminho da pasta de dados' required: true type: text + - default: postgresql + envKey: PANEL_DB_TYPE + labelEn: Database runtime + labelZh: 数据库 Runtime + label: + en: 'Database runtime' + zh: '数据库 Runtime' + zh-Hant: '資料庫 Runtime' + ja: 'データベース Runtime' + ko: '데이터베이스 Runtime' + ru: 'Среда базы данных' + ms: 'Runtime pangkalan data' + pt-br: 'Runtime de banco de dados' + required: true + type: apps + values: + - label: PostgreSQL + value: postgresql + child: + default: '' + envKey: PANEL_DB_HOST + labelEn: PostgreSQL service + labelZh: PostgreSQL 服务 + label: + en: 'PostgreSQL service' + zh: 'PostgreSQL 服务' + zh-Hant: 'PostgreSQL 服務' + ja: 'PostgreSQL サービス' + ko: 'PostgreSQL 서비스' + ru: 'Сервис PostgreSQL' + ms: 'Perkhidmatan PostgreSQL' + pt-br: 'Serviço PostgreSQL' + required: true + type: service + - default: 5432 + edit: true + envKey: PANEL_DB_PORT + labelEn: Database port + labelZh: 数据库端口 + label: + en: 'Database port' + zh: '数据库端口' + zh-Hant: '資料庫連接埠' + ja: 'データベースポート' + ko: '데이터베이스 포트' + ru: 'Порт базы данных' + ms: 'Port pangkalan data' + pt-br: 'Porta do banco de dados' + required: true + rule: paramPort + type: number - default: next_terminal edit: true envKey: PANEL_DB_NAME diff --git a/apps/next-terminal/latest/docker-compose.yml b/apps/next-terminal/latest/docker-compose.yml index b96a3a170..d522a8298 100644 --- a/apps/next-terminal/latest/docker-compose.yml +++ b/apps/next-terminal/latest/docker-compose.yml @@ -6,27 +6,7 @@ services: - 1panel-network volumes: - "${DATA_PATH}:/usr/local/next-terminal/data" - image: dushixiang/guacd:latest - labels: - createdBy: "Apps" - - nt-postgresql: - container_name: ${CONTAINER_NAME}-postgresql - restart: always - networks: - - 1panel-network - environment: - - POSTGRES_DB=${PANEL_DB_NAME:-next_terminal} - - POSTGRES_USER=${PANEL_DB_USER:-next_terminal} - - POSTGRES_PASSWORD=${PANEL_DB_USER_PASSWORD:-next_terminal} - volumes: - - "${DATA_PATH}/postgresql:/var/lib/postgresql/data" - healthcheck: - test: ["CMD-SHELL", "pg_isready -U ${PANEL_DB_USER:-next_terminal} -d ${PANEL_DB_NAME:-next_terminal}"] - interval: 10s - timeout: 5s - retries: 5 - image: postgres:16.4 + image: dushixiang/guacd:1.6.0@sha256:40872b125c3d946314bd322a3a54325ee2d9a58ecd788f76720ca11874548e42 labels: createdBy: "Apps" @@ -44,11 +24,15 @@ services: - "${DATA_PATH}/config.yaml:/etc/next-terminal/config.yaml:ro" - "/etc/localtime:/etc/localtime:ro" depends_on: - nt-postgresql: - condition: service_healthy nt-guacd: condition: service_started - image: dushixiang/next-terminal:latest + healthcheck: + test: ["CMD-SHELL", "wget --quiet --tries=1 --spider http://127.0.0.1:8088/login || exit 1"] + interval: 30s + timeout: 10s + retries: 5 + start_period: 30s + image: dushixiang/next-terminal:v3.5.2@sha256:4e095f8a0309878e2966d3157af5667b6911b6890d5e4c4abfa5116e0209ca3e labels: createdBy: "Apps" diff --git a/apps/next-terminal/latest/scripts/init.sh b/apps/next-terminal/latest/scripts/init.sh index 76f2d381f..ef4cd7c79 100755 --- a/apps/next-terminal/latest/scripts/init.sh +++ b/apps/next-terminal/latest/scripts/init.sh @@ -4,6 +4,11 @@ set -euo pipefail ROOT_DIR="$(cd "$(dirname "$0")/.." && pwd)" ENV_FILE="${ENV_FILE:-${ROOT_DIR}/.env}" +fail() { + printf '%s\n' "$1" >&2 + exit 1 +} + get_env_value() { local key="$1" local default="$2" @@ -40,39 +45,21 @@ yaml_escape() { printf '%s\n' "$value" } -random_password() { - if command -v openssl >/dev/null 2>&1; then - openssl rand -hex 16 - else - LC_ALL=C tr -dc 'A-Za-z0-9' > "$ENV_FILE" - fi -} - -if [[ -f "$ENV_FILE" ]]; then - ensure_env_value PANEL_DB_NAME next_terminal - ensure_env_value PANEL_DB_USER next_terminal - ensure_env_value PANEL_DB_USER_PASSWORD "$(random_password)" -fi +[[ -f "$ENV_FILE" ]] || fail "Environment file not found: ${ENV_FILE}" DATA_DIR="$(resolve_app_path "$(get_env_value DATA_PATH ./data)")" CONFIG_FILE="${DATA_DIR}/config.yaml" LOG_DIR="${DATA_DIR}/logs" -DB_DIR="${DATA_DIR}/postgresql" CONTAINER_NAME="$(get_env_value CONTAINER_NAME next-terminal)" +DB_HOST="$(get_env_value PANEL_DB_HOST '')" +DB_PORT="$(get_env_value PANEL_DB_PORT 5432)" DB_NAME="$(get_env_value PANEL_DB_NAME next_terminal)" DB_USER="$(get_env_value PANEL_DB_USER next_terminal)" DB_PASSWORD="$(get_env_value PANEL_DB_USER_PASSWORD next_terminal)" -mkdir -p "$DATA_DIR" "$LOG_DIR" "$DB_DIR" +[[ -n "$DB_HOST" ]] || fail "PANEL_DB_HOST is required. Select a running PostgreSQL application and service in 1Panel." + +mkdir -p "$DATA_DIR" "$LOG_DIR" if [[ -d "$CONFIG_FILE" ]]; then backup="${CONFIG_FILE}.dir-backup-$(date +%Y%m%d%H%M%S)" @@ -81,6 +68,9 @@ if [[ -d "$CONFIG_FILE" ]]; then fi if [[ -f "$CONFIG_FILE" ]]; then + CURRENT_DB_HOST="$(sed -n -E 's/^[[:space:]]*Hostname:[[:space:]]*"?([^"[:space:]]+)"?[[:space:]]*$/\1/p' "$CONFIG_FILE" | head -n 1)" + [[ -n "$CURRENT_DB_HOST" ]] || fail "Existing config.yaml has an unrecognized database host; it was preserved and the operation was stopped." + [[ "$CURRENT_DB_HOST" == "$DB_HOST" ]] || fail "Existing config.yaml uses database host '${CURRENT_DB_HOST}', but 1Panel selected '${DB_HOST}'. The file was preserved; migrate the database and configuration manually before retrying." echo "Next Terminal config already exists: $CONFIG_FILE" exit 0 fi @@ -90,8 +80,8 @@ Database: Enabled: true Type: postgres Postgres: - Hostname: "$(yaml_escape "${CONTAINER_NAME}-postgresql")" - Port: 5432 + Hostname: "$(yaml_escape "$DB_HOST")" + Port: $(yaml_escape "$DB_PORT") Username: "$(yaml_escape "$DB_USER")" Password: "$(yaml_escape "$DB_PASSWORD")" Database: "$(yaml_escape "$DB_NAME")" diff --git a/apps/next-terminal/latest/scripts/uninstall.sh b/apps/next-terminal/latest/scripts/uninstall.sh index 9543431b0..5a3f6bd6b 100755 --- a/apps/next-terminal/latest/scripts/uninstall.sh +++ b/apps/next-terminal/latest/scripts/uninstall.sh @@ -2,7 +2,7 @@ set -euo pipefail if command -v docker-compose >/dev/null 2>&1; then - docker-compose down --volumes + docker-compose down --volumes --remove-orphans else - docker compose down --volumes + docker compose down --volumes --remove-orphans fi diff --git a/apps/next-terminal/latest/scripts/upgrade.sh b/apps/next-terminal/latest/scripts/upgrade.sh index 271e0bbf9..04cc16a2e 100755 --- a/apps/next-terminal/latest/scripts/upgrade.sh +++ b/apps/next-terminal/latest/scripts/upgrade.sh @@ -2,6 +2,73 @@ set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" -bash "${SCRIPT_DIR}/init.sh" +ROOT_DIR="$(cd "${SCRIPT_DIR}/.." && pwd)" +ENV_FILE="${ENV_FILE:-${ROOT_DIR}/.env}" -echo "Next Terminal upgrade preflight completed." +get_env_value() { + local key="$1" + local default="$2" + local value="" + + if [[ -f "$ENV_FILE" ]]; then + value="$(sed -n -E "s/^${key}=//p" "$ENV_FILE" | tail -n 1 || true)" + value="${value%\"}" + value="${value#\"}" + value="${value%\'}" + value="${value#\'}" + fi + + if [[ -n "$value" ]]; then + printf '%s\n' "$value" + else + printf '%s\n' "$default" + fi +} + +resolve_app_path() { + local raw="$1" + if [[ "$raw" = /* ]]; then + printf '%s\n' "$raw" + else + printf '%s\n' "${ROOT_DIR}/${raw#./}" + fi +} + +restore_previous_release() { + if command -v docker-compose >/dev/null 2>&1; then + (cd "$ROOT_DIR" && docker-compose up -d) + elif command -v docker >/dev/null 2>&1 && docker compose version >/dev/null 2>&1; then + (cd "$ROOT_DIR" && docker compose up -d) + else + printf '%s\n' "Unable to restore the previous release because Docker Compose is unavailable." >&2 + return 1 + fi +} + +refuse_direct_upgrade() { + local reason="$1" + printf '%s\n' "$reason" >&2 + if restore_previous_release; then + printf '%s\n' "The previous Next Terminal release was restored. Install 3.5.2 separately and migrate the database manually." >&2 + else + printf '%s\n' "Previous-release restoration failed; start the existing compose manually before retrying." >&2 + fi + return 1 +} + +DATA_DIR="$(resolve_app_path "$(get_env_value DATA_PATH ./data)")" +DB_HOST="$(get_env_value PANEL_DB_HOST '')" + +if [[ -d "${DATA_DIR}/postgresql" ]]; then + refuse_direct_upgrade "Direct upgrade from the bundled-PostgreSQL layout is not supported." +fi + +if [[ -z "$DB_HOST" ]]; then + refuse_direct_upgrade "PANEL_DB_HOST is missing; select a PostgreSQL service on a fresh 3.5.2 installation." +fi + +if ! bash "${SCRIPT_DIR}/init.sh"; then + refuse_direct_upgrade "Next Terminal upgrade preflight failed without changing the existing configuration." +fi + +echo "Next Terminal external PostgreSQL upgrade preflight completed." diff --git a/apps/next-terminal/latest/ssh/id_rsa b/apps/next-terminal/latest/ssh/id_rsa deleted file mode 100644 index fe7575508..000000000 --- a/apps/next-terminal/latest/ssh/id_rsa +++ /dev/null @@ -1,49 +0,0 @@ ------BEGIN OPENSSH PRIVATE KEY----- -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 ------END OPENSSH PRIVATE KEY-----