From b973db78e2d0375bcd3ca624a49eb09a50dd2bfa Mon Sep 17 00:00:00 2001 From: Meng Sen Date: Sun, 27 Apr 2025 11:14:31 +0800 Subject: [PATCH] =?UTF-8?q?=E5=8F=91=E5=B8=83=20RustDesk-API?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Meng Sen --- apps/rustdesk-api/2.6.16/conf/hbbr/run | 5 + apps/rustdesk-api/2.6.16/conf/hbbs/run | 6 + apps/rustdesk-api/2.6.16/data.yml | 154 ++++++++++++++++++ apps/rustdesk-api/2.6.16/docker-compose.yml | 51 ++++++ apps/rustdesk-api/2.6.16/envs/default.env | 2 + apps/rustdesk-api/2.6.16/envs/global.env | 2 + apps/rustdesk-api/2.6.16/scripts/init.sh | 17 ++ apps/rustdesk-api/2.6.16/scripts/uninstall.sh | 10 ++ apps/rustdesk-api/2.6.16/scripts/upgrade.sh | 17 ++ apps/rustdesk-api/README.md | 34 ++++ apps/rustdesk-api/data.yml | 14 ++ apps/rustdesk-api/logo.png | Bin 0 -> 7689 bytes 12 files changed, 312 insertions(+) create mode 100644 apps/rustdesk-api/2.6.16/conf/hbbr/run create mode 100644 apps/rustdesk-api/2.6.16/conf/hbbs/run create mode 100644 apps/rustdesk-api/2.6.16/data.yml create mode 100644 apps/rustdesk-api/2.6.16/docker-compose.yml create mode 100644 apps/rustdesk-api/2.6.16/envs/default.env create mode 100644 apps/rustdesk-api/2.6.16/envs/global.env create mode 100644 apps/rustdesk-api/2.6.16/scripts/init.sh create mode 100644 apps/rustdesk-api/2.6.16/scripts/uninstall.sh create mode 100644 apps/rustdesk-api/2.6.16/scripts/upgrade.sh create mode 100644 apps/rustdesk-api/README.md create mode 100644 apps/rustdesk-api/data.yml create mode 100644 apps/rustdesk-api/logo.png diff --git a/apps/rustdesk-api/2.6.16/conf/hbbr/run b/apps/rustdesk-api/2.6.16/conf/hbbr/run new file mode 100644 index 000000000..7d6025653 --- /dev/null +++ b/apps/rustdesk-api/2.6.16/conf/hbbr/run @@ -0,0 +1,5 @@ +#!/command/with-contenv sh +cd /data || exit +PARAMS= +[ "${ENCRYPTED_ONLY}" = "1" ] && PARAMS="-k ${KEY}" +/usr/bin/hbbr $PARAMS diff --git a/apps/rustdesk-api/2.6.16/conf/hbbs/run b/apps/rustdesk-api/2.6.16/conf/hbbs/run new file mode 100644 index 000000000..44cdd5261 --- /dev/null +++ b/apps/rustdesk-api/2.6.16/conf/hbbs/run @@ -0,0 +1,6 @@ +#!/command/with-contenv sh +sleep 2 +cd /data +PARAMS= +[ "${ENCRYPTED_ONLY}" = "1" ] && PARAMS="-k ${KEY}" +/usr/bin/hbbs -r $RELAY $PARAMS diff --git a/apps/rustdesk-api/2.6.16/data.yml b/apps/rustdesk-api/2.6.16/data.yml new file mode 100644 index 000000000..b0815cfb5 --- /dev/null +++ b/apps/rustdesk-api/2.6.16/data.yml @@ -0,0 +1,154 @@ +additionalProperties: + formFields: + - default: "/home/rustdesk-api" + edit: true + envKey: RUSTDESK_API_ROOT_PATH + labelZh: 数据持久化路径 + labelEn: Data persistence path + required: true + type: text + - default: 21114 + edit: true + envKey: PANEL_APP_PORT_HTTP + labelZh: WebUI 端口 + labelEn: WebUI port + required: true + rule: paramPort + type: number + - default: "http://127.0.0.1" + edit: true + envKey: RUSTDESK_SERVER_URL + labelZh: RustDesk 服务地址 + labelEn: RustDesk server address + required: true + type: text + - default: "RustDesk API Admin" + edit: true + envKey: RUSTDESK_API_ADMIN_TITLE + labelZh: 后台页面标题 + labelEn: Admin page title + required: true + type: text + - default: "" + edit: true + envKey: RUSTDESK_API_RUSTDESK_KEY + labelZh: RustDesk API 密钥 + labelEn: RustDesk API key + required: true + type: text + - default: "168h" + edit: true + envKey: RUSTDESK_API_APP_TOKEN_EXPIRE + labelZh: 登录有效期 + labelEn: Login validity period + required: true + type: text + - default: "1" + edit: true + envKey: RUSTDESK_API_APP_WEB_CLIENT + labelZh: 启用 Web Client + labelEn: Enable Web Client + required: true + type: select + values: + - label: 启用 + value: "1" + - label: 禁用 + value: "0" + - default: "1" + edit: true + envKey: RUSTDESK_API_APP_REGISTER + labelZh: 开启 Swagger 文档 + labelEn: Enable Swagger docs + required: true + type: select + values: + - label: 启用 + value: "1" + - label: 禁用 + value: "0" + - default: "false" + edit: true + envKey: RUSTDESK_API_APP_REGISTER + labelZh: 启用注册 + labelEn: Enable register + required: true + type: select + values: + - label: 启用 + value: "true" + - label: 禁用 + value: "false" + - default: "false" + edit: true + envKey: RUSTDESK_API_APP_DISABLE_PWD_LOGIN + labelZh: 登录策略 + labelEn: Login strategy + required: true + type: select + values: + - label: 禁用密码登录 + value: "true" + - label: 允许密码登录 + value: "false" + - default: "false" + edit: true + envKey: RUSTDESK_API_PROXY_ENABLE + labelZh: 启用代理 + labelEn: Enable proxy + required: true + type: select + values: + - label: 启用 + value: "true" + - label: 禁用 + value: "false" + - default: "" + edit: true + envKey: RUSTDESK_API_PROXY_HOST + labelZh: 代理地址 + labelEn: Proxy address + required: false + type: text + - default: "sqlite" + edit: true + envKey: RUSTDESK_API_GORM_TYPE + labelZh: 数据库类型 + labelEn: Database type + required: true + type: select + values: + - label: sqlite + value: "sqlite" + - label: MySQL + value: "false" + - default: "127.0.0.1:3306" + edit: true + envKey: RUSTDESK_API_MYSQL_ADDR + labelZh: 数据库地址 + labelEn: Database Host + required: false + type: text + - default: "rustdesk" + edit: true + envKey: RUSTDESK_API_MYSQL_DBNAME + labelZh: 数据库 名称 + labelEn: Database Name + required: false + rule: paramCommon + type: text + - default: "rustdesk" + edit: true + envKey: RUSTDESK_API_MYSQL_USERNAME + labelZh: 数据库 用户名 + labelEn: Database Username + required: false + type: text + - default: "" + edit: true + envKey: RUSTDESK_API_MYSQL_PASSWORD + labelZh: 数据库 密码 + labelEn: Database Password + required: false + rule: paramComplexity + type: password diff --git a/apps/rustdesk-api/2.6.16/docker-compose.yml b/apps/rustdesk-api/2.6.16/docker-compose.yml new file mode 100644 index 000000000..74d93f586 --- /dev/null +++ b/apps/rustdesk-api/2.6.16/docker-compose.yml @@ -0,0 +1,51 @@ +networks: + 1panel-network: + external: true + +services: + rustdesk-api: + image: lejianwen/rustdesk-api:v2.6.16 + container_name: ${CONTAINER_NAME} + labels: + createdBy: "Apps" + restart: always + networks: + - 1panel-network + ports: + - ${PANEL_APP_PORT_HTTP}:21114 + env_file: + - ${GLOBAL_ENV_FILE:-/etc/1panel/envs/global.env} + - ${ENV_FILE:-/etc/1panel/envs/default.env} + volumes: + - ${RUSTDESK_API_ROOT_PATH}/data:/data + environment: + - TZ=Asia/Shanghai + - RUSTDESK_API_LANG=zh-CN + - RUSTDESK_API_RUSTDESK_ID_SERVER=${RUSTDESK_SERVER_URL}:21116 + - RUSTDESK_API_RUSTDESK_RELAY_SERVER=${RUSTDESK_SERVER_URL}:21117 + - RUSTDESK_API_RUSTDESK_API_SERVER=${RUSTDESK_SERVER_URL}:${PANEL_APP_PORT_HTTP:-21114} + rustdesk-server-s6: + image: rustdesk/rustdesk-server-s6:latest + container_name: server-${CONTAINER_NAME} + labels: + createdBy: "Apps" + restart: always + networks: + - 1panel-network + ports: + - 21115:21115 + - 21116:21116 + - 21116:21116/udp + - 21117:21117 + - 21118:21118 + - 21119:21119 + env_file: + - ${GLOBAL_ENV_FILE:-/etc/1panel/envs/global.env} + - ${ENV_FILE:-/etc/1panel/envs/default.env} + volumes: + - ${RUSTDESK_API_ROOT_PATH}/data:/data + environment: + - TZ=Asia/Shanghai + - RUSTDESK_API_LANG=zh-CN + - RELAY=${RUSTDESK_SERVER_URL}:21117 + - ENCRYPTED_ONLY=1 diff --git a/apps/rustdesk-api/2.6.16/envs/default.env b/apps/rustdesk-api/2.6.16/envs/default.env new file mode 100644 index 000000000..cd05f46e6 --- /dev/null +++ b/apps/rustdesk-api/2.6.16/envs/default.env @@ -0,0 +1,2 @@ +# copyright© 2024 XinJiang Ms Studio +ENV_FILE=.env diff --git a/apps/rustdesk-api/2.6.16/envs/global.env b/apps/rustdesk-api/2.6.16/envs/global.env new file mode 100644 index 000000000..e10989fe4 --- /dev/null +++ b/apps/rustdesk-api/2.6.16/envs/global.env @@ -0,0 +1,2 @@ +# copyright© 2024 XinJiang Ms Studio +TZ=Asia/Shanghai diff --git a/apps/rustdesk-api/2.6.16/scripts/init.sh b/apps/rustdesk-api/2.6.16/scripts/init.sh new file mode 100644 index 000000000..07fb8c3fe --- /dev/null +++ b/apps/rustdesk-api/2.6.16/scripts/init.sh @@ -0,0 +1,17 @@ +#!/bin/bash + +if [ -f .env ]; then + source .env + + # setup-1 add default values + CURRENT_DIR=$(pwd) + sed -i '/^ENV_FILE=/d' .env + sed -i '/^GLOBAL_ENV_FILE=/d' .env + echo "ENV_FILE=${CURRENT_DIR}/.env" >> .env + echo "GLOBAL_ENV_FILE=${CURRENT_DIR}/envs/global.env" >> .env + + echo "Check Finish." + +else + echo "Error: .env file not found." +fi diff --git a/apps/rustdesk-api/2.6.16/scripts/uninstall.sh b/apps/rustdesk-api/2.6.16/scripts/uninstall.sh new file mode 100644 index 000000000..c86c4fbca --- /dev/null +++ b/apps/rustdesk-api/2.6.16/scripts/uninstall.sh @@ -0,0 +1,10 @@ +#!/bin/bash + +if [ -f .env ]; then + source .env + + echo "Check Finish." + +else + echo "Error: .env file not found." +fi diff --git a/apps/rustdesk-api/2.6.16/scripts/upgrade.sh b/apps/rustdesk-api/2.6.16/scripts/upgrade.sh new file mode 100644 index 000000000..07fb8c3fe --- /dev/null +++ b/apps/rustdesk-api/2.6.16/scripts/upgrade.sh @@ -0,0 +1,17 @@ +#!/bin/bash + +if [ -f .env ]; then + source .env + + # setup-1 add default values + CURRENT_DIR=$(pwd) + sed -i '/^ENV_FILE=/d' .env + sed -i '/^GLOBAL_ENV_FILE=/d' .env + echo "ENV_FILE=${CURRENT_DIR}/.env" >> .env + echo "GLOBAL_ENV_FILE=${CURRENT_DIR}/envs/global.env" >> .env + + echo "Check Finish." + +else + echo "Error: .env file not found." +fi diff --git a/apps/rustdesk-api/README.md b/apps/rustdesk-api/README.md new file mode 100644 index 000000000..6fc90b387 --- /dev/null +++ b/apps/rustdesk-api/README.md @@ -0,0 +1,34 @@ +# RustDesk API + +RustDesk 是一款远程访问和远程控制软件 + +![RustDesk API](https://file.lifebus.top/imgs/rustdesk-api_cover.png) + +![](https://img.shields.io/badge/%E6%96%B0%E7%96%86%E8%90%8C%E6%A3%AE%E8%BD%AF%E4%BB%B6%E5%BC%80%E5%8F%91%E5%B7%A5%E4%BD%9C%E5%AE%A4-%E6%8F%90%E4%BE%9B%E6%8A%80%E6%9C%AF%E6%94%AF%E6%8C%81-blue) + +## 简介 + +本项目使用 Go 实现了 RustDesk 的 API,并包含了 Web Admin 和 Web 客户端。RustDesk 是一个远程桌面软件,提供了自托管的解决方案。 + +## 安装说明 + +### 端口 + +RustDesk 服务器自托管所需的端口很大程度上取决于您的环境以及您希望使用 RustDesk 做什么。 + +核心端口: + +| 类型 | 范围 | +|-----|-------------| +| TCP | 21114-21119 | +| UDP | 21116 | + +其中 21115-21117 是 RustDesk 工作所需的最低端口,它们处理信号和中继端口以及 NAT 遍历。 + +TCP 端口 21118 和 21119 是 RustDesk Web 客户端的 WebSocket 端口,您需要一个反向代理才能使其支持 HTTPS。 + +对于没有 SSL 代理的专业用户,您需要打开 TCP 端口 21114 才能使 API 工作,或者使用 SSL 代理打开 TCP 端口 443 。 + +--- + +![Ms Studio](https://file.lifebus.top/imgs/ms_blank_001.png) diff --git a/apps/rustdesk-api/data.yml b/apps/rustdesk-api/data.yml new file mode 100644 index 000000000..627dd7442 --- /dev/null +++ b/apps/rustdesk-api/data.yml @@ -0,0 +1,14 @@ +additionalProperties: + key: rustdesk-api + name: RustDesk API + tags: + - WebSite + - Local + shortDescZh: RustDesk 的 API 管理平台 + shortDescEn: RustDesk API management platform + type: website + crossVersionUpdate: true + limit: 0 + website: https://rustdesk.com/ + github: https://github.com/lejianwen/rustdesk-api/ + document: https://github.com/lejianwen/rustdesk-api/ diff --git a/apps/rustdesk-api/logo.png b/apps/rustdesk-api/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..89abf23a68ae85d0f28cdb90d1b08ad36db9d2c8 GIT binary patch literal 7689 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 literal 0 HcmV?d00001