From d793bcf5693f28bb90d3c01147d504f49b347419 Mon Sep 17 00:00:00 2001
From: lejianwen <84855512@qq.com>
Date: Sun, 12 Jan 2025 19:17:53 +0800
Subject: [PATCH] docs: up readme
---
README-EN.md | 354 +++++++++++++++++++++++++++++++++++++++++++++++++
README-ZH.md | 348 ------------------------------------------------
README.md | 287 ++++++++++++++++++++++-----------------
img.png | Bin 0 -> 49462 bytes
readme/api.png | Bin 0 -> 49462 bytes
5 files changed, 520 insertions(+), 469 deletions(-)
create mode 100644 README-EN.md
delete mode 100644 README-ZH.md
create mode 100644 img.png
create mode 100644 readme/api.png
diff --git a/README-EN.md b/README-EN.md
new file mode 100644
index 0000000..fdfa7b8
--- /dev/null
+++ b/README-EN.md
@@ -0,0 +1,354 @@
+
+docker run --name hbbr --net=host -v "$PWD/data:/root" -d rustdesk/rustdesk-server:latest hbbr
+```
+
+or without `--net=host`, but P2P direct connection can not work.
+
+For systems using SELinux, replacing `/root` by `/root:z` is required for the containers to run correctly. Alternatively, SELinux container separation can be disabled completely adding the option `--security-opt label=disable`.
+
+```bash
+docker run --name hbbs -p 21115:21115 -p 21116:21116 -p 21116:21116/udp -p 21118:21118 -v "$PWD/data:/root" -d rustdesk/rustdesk-server:latest hbbs -r
+docker run --name hbbr -p 21117:21117 -p 21119:21119 -v "$PWD/data:/root" -d rustdesk/rustdesk-server:latest hbbr
+```
+
+The `relay-server-ip` parameter is the IP address (or dns name) of the server running these containers. The **optional** `port` parameter has to be used if you use a port different than **21117** for `hbbr`.
+
+You can also use docker-compose, using this configuration as a template:
+
+```yaml
+version: '3'
+
+networks:
+ rustdesk-net:
+ external: false
+
+services:
+ hbbs:
+ container_name: hbbs
+ ports:
+ - 21115:21115
+ - 21116:21116
+ - 21116:21116/udp
+ - 21118:21118
+ image: rustdesk/rustdesk-server:latest
+ command: hbbs -r rustdesk.example.com:21117
+ volumes:
+ - ./data:/root
+ networks:
+ - rustdesk-net
+ depends_on:
+ - hbbr
+ restart: unless-stopped
+
+ hbbr:
+ container_name: hbbr
+ ports:
+ - 21117:21117
+ - 21119:21119
+ image: rustdesk/rustdesk-server:latest
+ command: hbbr
+ volumes:
+ - ./data:/root
+ networks:
+ - rustdesk-net
+ restart: unless-stopped
+```
+
+Edit line 16 to point to your relay server (the one listening on port 21117). You can also edit the volume lines (line 18 and line 33) if you need.
+
+(docker-compose credit goes to @lukebarone and @QuiGonLeong)
+
+> [!NOTE]
+> The rustdesk/rustdesk-server:latest in China may be replaced with the latest version number on Docker Hub, such as `rustdesk-server:1.1.10-3`. Otherwise, the old version may be pulled due to image acceleration.
+
+> [!NOTE]
+> If you are experiencing issues pulling from Docker Hub, try pulling from the [GitHub Container Registry](https://github.com/rustdesk/rustdesk-server/pkgs/container/rustdesk-server) instead.
+
+## S6-overlay based images
+
+These images are build against `busybox:stable` with the addition of the binaries (both `hbbs` and `hbbr`) and [S6-overlay](https://github.com/just-containers/s6-overlay). They're available on [Docker hub](https://hub.docker.com/r/rustdesk/rustdesk-server-s6/) and [GitHub Container Registry](https://github.com/rustdesk/rustdesk-server/pkgs/container/rustdesk-server) with these architectures:
+
+* amd64
+* i386
+* arm64v8
+* armv7
+
+You could use `latest` tag or major version tag `1` with supported architectures:
+
+| Version | image:tag |
+| ------------- | ------------------------------------ |
+| latest | `rustdesk/rustdesk-server-s6:latest` |
+| Major version | `rustdesk/rustdesk-server-s6:1` |
+
+The S6-overlay acts as a supervisor and keeps both process running, so with this image, there's no need to have two separate running containers.
+
+You can start these images directly with `docker run` with this command:
+
+```bash
+docker run --name rustdesk-server \
+ --net=host \
+ -e "RELAY=rustdeskrelay.example.com" \
+ -e "ENCRYPTED_ONLY=1" \
+ -v "$PWD/data:/data" -d rustdesk/rustdesk-server-s6:latest
+```
+
+or without `--net=host`, but P2P direct connection cannot work.
+
+```bash
+docker run --name rustdesk-server \
+ -p 21115:21115 -p 21116:21116 -p 21116:21116/udp \
+ -p 21117:21117 -p 21118:21118 -p 21119:21119 \
+ -e "RELAY=rustdeskrelay.example.com" \
+ -e "ENCRYPTED_ONLY=1" \
+ -v "$PWD/data:/data" -d rustdesk/rustdesk-server-s6:latest
+```
+
+Or you can use a docker-compose file:
+
+```yaml
+version: '3'
+
+services:
+ rustdesk-server:
+ container_name: rustdesk-server
+ ports:
+ - 21115:21115
+ - 21116:21116
+ - 21116:21116/udp
+ - 21117:21117
+ - 21118:21118
+ - 21119:21119
+ image: rustdesk/rustdesk-server-s6:latest
+ environment:
+ - "RELAY=rustdesk.example.com:21117"
+ - "ENCRYPTED_ONLY=1"
+ volumes:
+ - ./data:/data
+ restart: unless-stopped
+```
+
+For this container image, you can use these environment variables, **in addition** to the ones specified in the following **ENV variables** section:
+
+| variable | optional | description |
+| --- | --- | --- |
+| RELAY | no | the IP address/DNS name of the machine running this container |
+| ENCRYPTED_ONLY | yes | if set to **"1"** unencrypted connection will not be accepted |
+| KEY_PUB | yes | public part of the key pair |
+| KEY_PRIV | yes | private part of the key pair |
+
+### Secret management in S6-overlay based images
+
+You can obviously keep the key pair in a docker volume, but the best practices tells you to not write the keys on the filesystem; so we provide a couple of options.
+
+On container startup, the presence of the keypair is checked (`/data/id_ed25519.pub` and `/data/id_ed25519`) and if one of these keys doesn't exist, it's recreated from ENV variables or docker secrets.
+Then the validity of the keypair is checked: if public and private keys doesn't match, the container will stop.
+If you provide no keys, `hbbs` will generate one for you, and it'll place it in the default location.
+
+#### Use ENV to store the key pair
+
+You can use docker environment variables to store the keys. Just follow this examples:
+
+```bash
+docker run --name rustdesk-server \
+ --net=host \
+ -e "RELAY=rustdeskrelay.example.com" \
+ -e "ENCRYPTED_ONLY=1" \
+ -e "DB_URL=/db/db_v2.sqlite3" \
+ -e "KEY_PRIV=FR2j78IxfwJNR+HjLluQ2Nh7eEryEeIZCwiQDPVe+PaITKyShphHAsPLn7So0OqRs92nGvSRdFJnE2MSyrKTIQ==" \
+ -e "KEY_PUB=iEyskoaYRwLDy5+0qNDqkbPdpxr0kXRSZxNjEsqykyE=" \
+ -v "$PWD/db:/db" -d rustdesk/rustdesk-server-s6:latest
+```
+
+```yaml
+version: '3'
+
+services:
+ rustdesk-server:
+ container_name: rustdesk-server
+ ports:
+ - 21115:21115
+ - 21116:21116
+ - 21116:21116/udp
+ - 21117:21117
+ - 21118:21118
+ - 21119:21119
+ image: rustdesk/rustdesk-server-s6:latest
+ environment:
+ - "RELAY=rustdesk.example.com:21117"
+ - "ENCRYPTED_ONLY=1"
+ - "DB_URL=/db/db_v2.sqlite3"
+ - "KEY_PRIV=FR2j78IxfwJNR+HjLluQ2Nh7eEryEeIZCwiQDPVe+PaITKyShphHAsPLn7So0OqRs92nGvSRdFJnE2MSyrKTIQ=="
+ - "KEY_PUB=iEyskoaYRwLDy5+0qNDqkbPdpxr0kXRSZxNjEsqykyE="
+ volumes:
+ - ./db:/db
+ restart: unless-stopped
+```
+
+#### Use Docker secrets to store the key pair
+
+You can alternatively use docker secrets to store the keys.
+This is useful if you're using **docker-compose** or **Docker Swarm**.
+Just follow this examples:
+
+```bash
+cat secrets/id_ed25519.pub | docker secret create key_pub -
+cat secrets/id_ed25519 | docker secret create key_priv -
+docker service create --name rustdesk-server \
+ --secret key_priv --secret key_pub \
+ --net=host \
+ -e "RELAY=rustdeskrelay.example.com" \
+ -e "ENCRYPTED_ONLY=1" \
+ -e "DB_URL=/db/db_v2.sqlite3" \
+ --mount "type=bind,source=$PWD/db,destination=/db" \
+ rustdesk/rustdesk-server-s6:latest
+```
+
+```yaml
+version: '3'
+
+services:
+ rustdesk-server:
+ container_name: rustdesk-server
+ ports:
+ - 21115:21115
+ - 21116:21116
+ - 21116:21116/udp
+ - 21117:21117
+ - 21118:21118
+ - 21119:21119
+ image: rustdesk/rustdesk-server-s6:latest
+ environment:
+ - "RELAY=rustdesk.example.com:21117"
+ - "ENCRYPTED_ONLY=1"
+ - "DB_URL=/db/db_v2.sqlite3"
+ volumes:
+ - ./db:/db
+ restart: unless-stopped
+ secrets:
+ - key_pub
+ - key_priv
+
+secrets:
+ key_pub:
+ file: secrets/id_ed25519.pub
+ key_priv:
+ file: secrets/id_ed25519
+```
+
+## How to create a keypair
+
+A keypair is needed for encryption; you can provide it, as explained before, but you need a way to create one.
+
+You can use this command to generate a keypair:
+
+```bash
+/usr/bin/rustdesk-utils genkeypair
+```
+
+If you don't have (or don't want) the `rustdesk-utils` package installed on your system, you can invoke the same command with docker:
+
+```bash
+docker run --rm --entrypoint /usr/bin/rustdesk-utils rustdesk/rustdesk-server-s6:latest genkeypair
+```
+
+The output will be something like this:
+
+```text
+Public Key: 8BLLhtzUBU/XKAH4mep3p+IX4DSApe7qbAwNH9nv4yA=
+Secret Key: egAVd44u33ZEUIDTtksGcHeVeAwywarEdHmf99KM5ajwEsuG3NQFT9coAfiZ6nen4hfgNICl7upsDA0f2e/jIA==
+```
+
+## .deb packages
+
+Separate .deb packages are available for each binary, you can find them in the [Releases](https://github.com/rustdesk/rustdesk-server/releases).
+These packages are meant for the following distributions:
+
+- Ubuntu 24.04 LTS
+- Ubuntu 22.04 LTS
+- Ubuntu 20.04 LTS
+- Ubuntu 18.04 LTS
+- Debian 12 bookworm
+- Debian 11 bullseye
+- Debian 10 buster
+
+## ENV variables
+
+`hbbs` and `hbbr` can be configured using these ENV variables.
+You can specify the variables as usual or use an `.env` file.
+
+| variable | binary | description |
+| --- | --- | --- |
+| ALWAYS_USE_RELAY | hbbs | if set to **"Y"** disallows direct peer connection |
+| DB_URL | hbbs | path for database file |
+| DOWNGRADE_START_CHECK | hbbr | delay (in seconds) before downgrade check |
+| DOWNGRADE_THRESHOLD | hbbr | threshold of downgrade check (bit/ms) |
+| KEY | hbbs/hbbr | if set force the use of a specific key, if set to **"_"** force the use of any key |
+| LIMIT_SPEED | hbbr | speed limit (in Mb/s) |
+| PORT | hbbs/hbbr | listening port (21116 for hbbs - 21117 for hbbr) |
+| RELAY | hbbs | IP address/DNS name of the machines running hbbr (separated by comma) |
+| RUST_LOG | all | set debug level (error\|warn\|info\|debug\|trace) |
+| SINGLE_BANDWIDTH | hbbr | max bandwidth for a single connection (in Mb/s) |
+| TOTAL_BANDWIDTH | hbbr | max total bandwidth (in Mb/s) |
diff --git a/README-ZH.md b/README-ZH.md
deleted file mode 100644
index 4f8c07b..0000000
--- a/README-ZH.md
+++ /dev/null
@@ -1,348 +0,0 @@
-
- 自行构建 •
- Docker •
- S6-overlay •
- 密钥 •
- Debian •
- 环境参数
- [English] | [Deutsch] | [Nederlands] | [繁体中文]
-
-
-# RustDesk Server Program
-
-[](https://github.com/rustdesk/rustdesk-server/actions/workflows/build.yaml)
-
-[**下载**](https://github.com/rustdesk/rustdesk-server/releases)
-
-[**说明文件**](https://rustdesk.com/docs/zh-cn/self-host/)
-
-[**FAQ**](https://github.com/rustdesk/rustdesk/wiki/FAQ)
-
-自行搭建属于你的RustDesk服务器,所有的一切都是免费且开源的
-
-## 如何自行构建
-
-```bash
-cargo build --release
-```
-
-执行后会在target/release目录下生成三个对应平台的可执行程序
-
-- hbbs - RustDesk ID/会和服务器
-- hbbr - RustDesk 中继服务器
-- rustdesk-utils - RustDesk 命令行工具
-
-您可以在 [releases](https://github.com/rustdesk/rustdesk-server/releases) 页面中找到最新的服务端软件。
-
-如果您需要额外的功能支持,[RustDesk 专业版服务器](https://rustdesk.com/pricing.html) 获取更适合您。
-
-如果您想开发自己的服务器,[rustdesk-server-demo](https://github.com/rustdesk/rustdesk-server-demo) 应该会比直接使用这个仓库更简单快捷。
-
-## Docker 镜像
-
-Docker镜像会在每次 GitHub 发布新的release版本时自动构建。我们提供两种类型的镜像。
-
-### Classic 传统镜像
-
-这个类型的镜像是基于 `ubuntu-20.04` 进行构建,镜像仅包含两个主要的可执行程序(`hbbr` 和 `hbbs`)。它们可以通过以下tag在 [Docker Hub](https://hub.docker.com/r/rustdesk/rustdesk-server/) 上获得:
-
-| 架构 | image:tag |
-|---------| ----------------------------------------- |
-| amd64 | `rustdesk/rustdesk-server:latest` |
-| arm64v8 | `rustdesk/rustdesk-server:latest-arm64v8` |
-
-您可以使用以下命令,直接通过 ``docker run`` 來启动这些镜像:
-
-```bash
-docker run --name hbbs --net=host -v "$PWD/data:/root" -d rustdesk/rustdesk-server:latest hbbs -r
-docker run --name hbbr --net=host -v "$PWD/data:/root" -d rustdesk/rustdesk-server:latest hbbr
-```
-
-或不使用 `--net=host` 参数启动, 但这样 P2P 直连功能将无法工作。
-
-对于使用了 SELinux 的系统,您需要将 ``/root`` 替换为 ``/root:z``,以保证容器的正常运行。或者,也可以通过添加参数 ``--security-opt label=disable`` 来完全禁用 SELinux 容器隔离。
-
-```bash
-docker run --name hbbs -p 21115:21115 -p 21116:21116 -p 21116:21116/udp -p 21118:21118 -v "$PWD/data:/root" -d rustdesk/rustdesk-server:latest hbbs -r
-docker run --name hbbr -p 21117:21117 -p 21119:21119 -v "$PWD/data:/root" -d rustdesk/rustdesk-server:latest hbbr
-```
-
-`relay-server-ip` 参数是运行这些容器的服务器的 IP 地址(或 DNS 名称)。如果你不想使用 **21117** 作为 `hbbr` 的服务端口,可使用可选参数 `port` 进行指定。
-
-您也可以使用 docker-compose 进行构建,以下为配置示例:
-
-```yaml
-version: '3'
-
-networks:
- rustdesk-net:
- external: false
-
-services:
- hbbs:
- container_name: hbbs
- ports:
- - 21115:21115
- - 21116:21116
- - 21116:21116/udp
- - 21118:21118
- image: rustdesk/rustdesk-server:latest
- command: hbbs -r rustdesk.example.com:21117
- volumes:
- - ./data:/root
- networks:
- - rustdesk-net
- depends_on:
- - hbbr
- restart: unless-stopped
-
- hbbr:
- container_name: hbbr
- ports:
- - 21117:21117
- - 21119:21119
- image: rustdesk/rustdesk-server:latest
- command: hbbr
- volumes:
- - ./data:/root
- networks:
- - rustdesk-net
- restart: unless-stopped
-```
-
-编辑第16行来指定你的中继服务器 (默认端口监听在 21117 的那一个)。 如果需要的话,您也可以编辑 volume 信息 (第 18 和 33 行)。
-
-(感谢 @lukebarone 和 @QuiGonLeong 协助提供的 docker-compose 配置示例)
-
-## 基于 S6-overlay 的镜像
-
-> 这些镜像是针对 `busybox:stable` 构建的,并添加了可执行程序(hbbr 和 hbbs)以及 [S6-overlay](https://github.com/just-containers/s6-overlay)。 它们可以使用以下tag在 [Docker hub](https://hub.docker.com/r/rustdesk/rustdesk-server-s6/) 上获取:
-
-
-| 架構 | version | image:tag |
-| --------- | ------- | -------------------------------------------- |
-| multiarch | latest | `rustdesk/rustdesk-server-s6:latest` |
-| amd64 | latest | `rustdesk/rustdesk-server-s6:latest-amd64` |
-| i386 | latest | `rustdesk/rustdesk-server-s6:latest-i386` |
-| arm64v8 | latest | `rustdesk/rustdesk-server-s6:latest-arm64v8` |
-| armv7 | latest | `rustdesk/rustdesk-server-s6:latest-armv7` |
-| multiarch | 2 | `rustdesk/rustdesk-server-s6:2` |
-| amd64 | 2 | `rustdesk/rustdesk-server-s6:2-amd64` |
-| i386 | 2 | `rustdesk/rustdesk-server-s6:2-i386` |
-| arm64v8 | 2 | `rustdesk/rustdesk-server-s6:2-arm64v8` |
-| armv7 | 2 | `rustdesk/rustdesk-server-s6:2-armv7` |
-| multiarch | 2.0.0 | `rustdesk/rustdesk-server-s6:2.0.0` |
-| amd64 | 2.0.0 | `rustdesk/rustdesk-server-s6:2.0.0-amd64` |
-| i386 | 2.0.0 | `rustdesk/rustdesk-server-s6:2.0.0-i386` |
-| arm64v8 | 2.0.0 | `rustdesk/rustdesk-server-s6:2.0.0-arm64v8` |
-| armv7 | 2.0.0 | `rustdesk/rustdesk-server-s6:2.0.0-armv7` |
-
-强烈建议您使用`major version` 或 `latest` tag 的 `multiarch` 架构的镜像。
-
-S6-overlay 在此处作为监控程序,用以保证两个进程的运行,因此使用此镜像,您无需运行两个容器。
-
-您可以使用 `docker run` 命令直接启动镜像,如下:
-
-```bash
-docker run --name rustdesk-server \
- --net=host \
- -e "RELAY=rustdeskrelay.example.com" \
- -e "ENCRYPTED_ONLY=1" \
- -v "$PWD/data:/data" -d rustdesk/rustdesk-server-s6:latest
-```
-
-或刪去 `--net=host` 参数, 但 P2P 直连功能将无法工作。
-
-```bash
-docker run --name rustdesk-server \
- -p 21115:21115 -p 21116:21116 -p 21116:21116/udp \
- -p 21117:21117 -p 21118:21118 -p 21119:21119 \
- -e "RELAY=rustdeskrelay.example.com" \
- -e "ENCRYPTED_ONLY=1" \
- -v "$PWD/data:/data" -d rustdesk/rustdesk-server-s6:latest
-```
-
-或着您也可以使用 docker-compose 文件:
-
-```yaml
-version: '3'
-
-services:
- rustdesk-server:
- container_name: rustdesk-server
- ports:
- - 21115:21115
- - 21116:21116
- - 21116:21116/udp
- - 21117:21117
- - 21118:21118
- - 21119:21119
- image: rustdesk/rustdesk-server-s6:latest
- environment:
- - "RELAY=rustdesk.example.com:21117"
- - "ENCRYPTED_ONLY=1"
- volumes:
- - ./data:/data
- restart: unless-stopped
-```
-
-对于此容器镜像,除了在下面的环境变量部分指定的变量之外,您还可以使用以下`环境变量`
-
-| 环境变量 | 是否可选 | 描述 |
-|----------------|------|--------------------------|
-| RELAY | 否 | 运行此容器的宿主机的 IP 地址/ DNS 名称 |
-| ENCRYPTED_ONLY | 是 | 如果设置为 **"1"**,将不接受未加密的连接。 |
-| KEY_PUB | 是 | 密钥对中的公钥(Public Key) |
-| KEY_PRIV | 是 | 密钥对中的私钥(Private Key) |
-
-### 基于 S6-overlay 镜像的密钥管理
-
-您可以将密钥对保存在 Docker volume 中,但我们建议不要将密钥写入文件系統中;因此,我们提供了一些方案。
-
-在容器启动时,会检查密钥对是否存在(`/data/id_ed25519.pub` 和 `/data/id_ed25519`),如果其中一個密钥不存在,则会从环境变量或 Docker Secret 中重新生成它。
-然后检查密钥对的可用性:如果公钥和私钥不匹配,容器将停止运行。
-如果您未提供密钥,`hbbs` 将会在默认位置生成一个。
-
-#### 使用 ENV 存储密钥对
-
-您可以使用 Docker 环境变量來存储密钥。如下:
-
-```bash
-docker run --name rustdesk-server \
- --net=host \
- -e "RELAY=rustdeskrelay.example.com" \
- -e "ENCRYPTED_ONLY=1" \
- -e "DB_URL=/db/db_v2.sqlite3" \
- -e "KEY_PRIV=FR2j78IxfwJNR+HjLluQ2Nh7eEryEeIZCwiQDPVe+PaITKyShphHAsPLn7So0OqRs92nGvSRdFJnE2MSyrKTIQ==" \
- -e "KEY_PUB=iEyskoaYRwLDy5+0qNDqkbPdpxr0kXRSZxNjEsqykyE=" \
- -v "$PWD/db:/db" -d rustdesk/rustdesk-server-s6:latest
-```
-
-```yaml
-version: '3'
-
-services:
- rustdesk-server:
- container_name: rustdesk-server
- ports:
- - 21115:21115
- - 21116:21116
- - 21116:21116/udp
- - 21117:21117
- - 21118:21118
- - 21119:21119
- image: rustdesk/rustdesk-server-s6:latest
- environment:
- - "RELAY=rustdesk.example.com:21117"
- - "ENCRYPTED_ONLY=1"
- - "DB_URL=/db/db_v2.sqlite3"
- - "KEY_PRIV=FR2j78IxfwJNR+HjLluQ2Nh7eEryEeIZCwiQDPVe+PaITKyShphHAsPLn7So0OqRs92nGvSRdFJnE2MSyrKTIQ=="
- - "KEY_PUB=iEyskoaYRwLDy5+0qNDqkbPdpxr0kXRSZxNjEsqykyE="
- volumes:
- - ./db:/db
- restart: unless-stopped
-```
-
-#### 使用 Docker Secret 來保存密钥对
-
-您还可以使用 Docker Secret 來保存密钥。
-如果您使用 **docker-compose** 或 **docker swarm**,推荐您使用。
-只需按照以下示例操作:
-
-```bash
-cat secrets/id_ed25519.pub | docker secret create key_pub -
-cat secrets/id_ed25519 | docker secret create key_priv -
-docker service create --name rustdesk-server \
- --secret key_priv --secret key_pub \
- --net=host \
- -e "RELAY=rustdeskrelay.example.com" \
- -e "ENCRYPTED_ONLY=1" \
- -e "DB_URL=/db/db_v2.sqlite3" \
- --mount "type=bind,source=$PWD/db,destination=/db" \
- rustdesk/rustdesk-server-s6:latest
-```
-
-```yaml
-version: '3'
-
-services:
- rustdesk-server:
- container_name: rustdesk-server
- ports:
- - 21115:21115
- - 21116:21116
- - 21116:21116/udp
- - 21117:21117
- - 21118:21118
- - 21119:21119
- image: rustdesk/rustdesk-server-s6:latest
- environment:
- - "RELAY=rustdesk.example.com:21117"
- - "ENCRYPTED_ONLY=1"
- - "DB_URL=/db/db_v2.sqlite3"
- volumes:
- - ./db:/db
- restart: unless-stopped
- secrets:
- - key_pub
- - key_priv
-
-secrets:
- key_pub:
- file: secrets/id_ed25519.pub
- key_priv:
- file: secrets/id_ed25519
-```
-
-## 如何生成密钥对
-
-加密需要一对密钥;您可以按照前面所述提供它,但需要一个工具去生成密钥对。
-
-您可以使用以下命令生成一对密钥:
-
-```bash
-/usr/bin/rustdesk-utils genkeypair
-```
-
-如果您沒有(或不想)在系统上安装 `rustdesk-utils` 套件,您可以使用 Docker 执行相同的命令:
-
-```bash
-docker run --rm --entrypoint /usr/bin/rustdesk-utils rustdesk/rustdesk-server-s6:latest genkeypair
-```
-
-运行后的输出内容如下:
-
-```text
-Public Key: 8BLLhtzUBU/XKAH4mep3p+IX4DSApe7qbAwNH9nv4yA=
-Secret Key: egAVd44u33ZEUIDTtksGcHeVeAwywarEdHmf99KM5ajwEsuG3NQFT9coAfiZ6nen4hfgNICl7upsDA0f2e/jIA==
-```
-
-## .deb 套件
-
-每个可执行文件都有单独的 .deb 套件可供使用,您可以在 [releases](https://github.com/rustdesk/rustdesk-server/releases) 页面中找到它們。
-這些套件适用于以下发行版:
-
-- Ubuntu 22.04 LTS
-- Ubuntu 20.04 LTS
-- Ubuntu 18.04 LTS
-- Debian 11 bullseye
-- Debian 10 buster
-
-## ENV 环境变量
-
-可以使用这些`环境变量`参数來配置 hbbs 和 hbbr。
-您可以像往常一样指定参数,或者使用 .env 文件。
-
-| 参数 | 可执行文件 | 描述 |
-|-----------------------|---------------|--------------------------------------------------|
-| ALWAYS_USE_RELAY | hbbs | 如果设定为 **"Y"**,将关闭直接点对点连接功能 |
-| DB_URL | hbbs | 数据库配置 |
-| DOWNGRADE_START_CHECK | hbbr | 降级检查之前的延迟是啊尽(以秒为单位) |
-| DOWNGRADE_THRESHOLD | hbbr | 降级检查的阈值(bit/ms) |
-| KEY | hbbs/hbbr | 如果设置了此参数,将强制使用指定密钥对,如果设为 **"_"**,则强制使用任意密钥 |
-| LIMIT_SPEED | hbbr | 速度限制(以Mb/s为单位) |
-| PORT | hbbs/hbbr | 监听端口(hbbs为21116,hbbr为21117) |
-| RELAY_SERVERS | hbbs | 运行hbbr的机器的IP地址/DNS名称(用逗号分隔) |
-| RUST_LOG | all | 设置 debug level (error\|warn\|info\|debug\|trace) |
-| SINGLE_BANDWIDTH | hbbr | 单个连接的最大带宽(以Mb/s为单位) |
-| TOTAL_BANDWIDTH | hbbr | 最大总带宽(以Mb/s为单位) |
\ No newline at end of file
diff --git a/README.md b/README.md
index fdfa7b8..eb553ac 100644
--- a/README.md
+++ b/README.md
@@ -1,82 +1,123 @@
+
+# 关于此分支
+
+
+
+[](https://github.com/lejianwen/rustdesk-server/actions/workflows/build.yaml)
+
+- 解决当客户端登录了`Api`账号时链接超时的问题
+- s6镜像添加了`Api`支持,`Api`开源地址 https://github.com/lejianwen/rustdesk-api
+
+## docker镜像地址
+
+- s6 镜像 [lejianwen/rustdesk-server-s6](https://hub.docker.com/r/lejianwen/rustdesk-server-s6)
+
+```yaml
+ networks:
+ rustdesk-net:
+ external: false
+ services:
+ rustdesk:
+ ports:
+ - 21114:21114
+ - 21115:21115
+ - 21116:21116
+ - 21116:21116/udp
+ - 21117:21117
+ - 21118:21118
+ - 21119:21119
+ image: lejianwen/rustdesk-server-s6:latest
+ environment:
+ - RELAY=
+ - ENCRYPTED_ONLY=1
+ - TZ=Asia/Shanghai
+ - RUSTDESK_API_RUSTDESK_ID_SERVER=
+ - RUSTDESK_API_RUSTDESK_RELAY_SERVER=
+ - RUSTDESK_API_RUSTDESK_API_SERVER=http://
+ volumes:
+ - /data/rustdesk/server:/data
+ - /data/rustdesk/api:/app/data #将数据库挂载
+ - /data/rustdesk/server:/app/conf/data #挂载key文件到api容器,可以不用使用 RUSTDESK_API_RUSTDESK_KEY
+ networks:
+ - rustdesk-net
+ restart: unless-stopped
+
+```
+
+- 普通镜像 [lejianwen/rustdesk-server](https://hub.docker.com/r/lejianwen/rustdesk-server)
+
+
+
- Manually •
- Docker •
- S6-overlay •
- Keypair •
- Debian •
- Variables
- [Deutsch] | [Nederlands] | [繁體中文] | [简体中文]
+ 自行构建 •
+ Docker •
+ S6-overlay •
+ 密钥 •
+ Debian •
+ 环境参数
+ [English] | [Deutsch] | [Nederlands] | [繁体中文]
# RustDesk Server Program
-[](https://github.com/rustdesk/rustdesk-server/actions/workflows/build.yaml)
-[**Download**](https://github.com/rustdesk/rustdesk-server/releases)
-[**Manual**](https://rustdesk.com/docs/en/self-host/)
+[**下载**](https://github.com/lejianwen/rustdesk-server/releases)
-[**FAQ**](https://github.com/rustdesk/rustdesk/wiki/FAQ)
+[**说明文件**](https://rustdesk.com/docs/zh-cn/self-host/)
-Self-host your own RustDesk server, it is free and open source.
+自行搭建属于你的RustDesk服务器,所有的一切都是免费且开源的
-## How to build manually
+## 如何自行构建
```bash
cargo build --release
```
-Three executables will be generated in target/release.
+执行后会在target/release目录下生成三个对应平台的可执行程序
-- hbbs - RustDesk ID/Rendezvous server
-- hbbr - RustDesk relay server
-- rustdesk-utils - RustDesk CLI utilities
+- hbbs - RustDesk ID/会和服务器
+- hbbr - RustDesk 中继服务器
+- rustdesk-utils - RustDesk 命令行工具
-You can find updated binaries on the [Releases](https://github.com/rustdesk/rustdesk-server/releases) page.
+您可以在 [releases](https://github.com/lejianwen/rustdesk-server/releases) 页面中找到最新的服务端软件。
-If you want extra features, [RustDesk Server Pro](https://rustdesk.com/pricing.html) might suit you better.
+如果您需要额外的功能支持,[RustDesk 专业版服务器](https://rustdesk.com/pricing.html) 获取更适合您。
-If you want to develop your own server, [rustdesk-server-demo](https://github.com/rustdesk/rustdesk-server-demo) might be a better and simpler start for you than this repo.
+如果您想开发自己的服务器,[rustdesk-server-demo](https://github.com/rustdesk/rustdesk-server-demo) 应该会比直接使用这个仓库更简单快捷。
-## Docker images
+## Docker 镜像
-Docker images are automatically generated and published to [Docker Hub](https://hub.docker.com/r/rustdesk) and [GitHub Container Registry](https://github.com/rustdesk?tab=packages&repo_name=rustdesk-server) on every GitHub release. We have 2 kind of images.
+Docker镜像会在每次 GitHub 发布新的release版本时自动构建。我们提供两种类型的镜像。
-### Classic image
+### Classic 传统镜像
-These images are built from scratch with two main binaries (`hbbs` and `hbbr`). They're available on [Docker Hub](https://hub.docker.com/r/rustdesk/rustdesk-server/) and [GitHub Container Registry](https://github.com/rustdesk/rustdesk-server/pkgs/container/rustdesk-server) with these architectures:
+这个类型的镜像是基于 `ubuntu-20.04` 进行构建,镜像仅包含两个主要的可执行程序(`hbbr` 和 `hbbs`)。它们可以通过以下tag在 [Docker Hub](https://hub.docker.com/r/lejianwen/rustdesk-server/) 上获得:
-* amd64
-* arm64v8
-* armv7
+| 架构 | image:tag |
+|---------| ----------------------------------------- |
+| amd64 | `lejianwen/rustdesk-server:latest` |
+| arm64v8 | `lejianwen/rustdesk-server:latest-arm64v8` |
-You could use `latest` tag or major version tag `1` with supported architectures:
-
-| Version | image:tag |
-| ------------- | --------------------------------- |
-| latest | `rustdesk/rustdesk-server:latest` |
-| Major version | `rustdesk/rustdesk-server:1` |
-
-
-You can start these images directly with `docker run` with these commands:
+您可以使用以下命令,直接通过 ``docker run`` 來启动这些镜像:
```bash
-docker run --name hbbs --net=host -v "$PWD/data:/root" -d rustdesk/rustdesk-server:latest hbbs -r
-docker run --name hbbr --net=host -v "$PWD/data:/root" -d rustdesk/rustdesk-server:latest hbbr
+docker run --name hbbs --net=host -v "$PWD/data:/root" -d lejianwen/rustdesk-server:latest hbbs -r
+docker run --name hbbr --net=host -v "$PWD/data:/root" -d lejianwen/rustdesk-server:latest hbbr
```
-or without `--net=host`, but P2P direct connection can not work.
+或不使用 `--net=host` 参数启动, 但这样 P2P 直连功能将无法工作。
-For systems using SELinux, replacing `/root` by `/root:z` is required for the containers to run correctly. Alternatively, SELinux container separation can be disabled completely adding the option `--security-opt label=disable`.
+对于使用了 SELinux 的系统,您需要将 ``/root`` 替换为 ``/root:z``,以保证容器的正常运行。或者,也可以通过添加参数 ``--security-opt label=disable`` 来完全禁用 SELinux 容器隔离。
```bash
-docker run --name hbbs -p 21115:21115 -p 21116:21116 -p 21116:21116/udp -p 21118:21118 -v "$PWD/data:/root" -d rustdesk/rustdesk-server:latest hbbs -r
-docker run --name hbbr -p 21117:21117 -p 21119:21119 -v "$PWD/data:/root" -d rustdesk/rustdesk-server:latest hbbr
+docker run --name hbbs -p 21115:21115 -p 21116:21116 -p 21116:21116/udp -p 21118:21118 -v "$PWD/data:/root" -d lejianwen/rustdesk-server:latest hbbs -r
+docker run --name hbbr -p 21117:21117 -p 21119:21119 -v "$PWD/data:/root" -d lejianwen/rustdesk-server:latest hbbr
```
-The `relay-server-ip` parameter is the IP address (or dns name) of the server running these containers. The **optional** `port` parameter has to be used if you use a port different than **21117** for `hbbr`.
+`relay-server-ip` 参数是运行这些容器的服务器的 IP 地址(或 DNS 名称)。如果你不想使用 **21117** 作为 `hbbr` 的服务端口,可使用可选参数 `port` 进行指定。
-You can also use docker-compose, using this configuration as a template:
+您也可以使用 docker-compose 进行构建,以下为配置示例:
```yaml
version: '3'
@@ -93,7 +134,7 @@ services:
- 21116:21116
- 21116:21116/udp
- 21118:21118
- image: rustdesk/rustdesk-server:latest
+ image: lejianwen/rustdesk-server:latest
command: hbbs -r rustdesk.example.com:21117
volumes:
- ./data:/root
@@ -108,7 +149,7 @@ services:
ports:
- 21117:21117
- 21119:21119
- image: rustdesk/rustdesk-server:latest
+ image: lejianwen/rustdesk-server:latest
command: hbbr
volumes:
- ./data:/root
@@ -117,45 +158,48 @@ services:
restart: unless-stopped
```
-Edit line 16 to point to your relay server (the one listening on port 21117). You can also edit the volume lines (line 18 and line 33) if you need.
+编辑第16行来指定你的中继服务器 (默认端口监听在 21117 的那一个)。 如果需要的话,您也可以编辑 volume 信息 (第 18 和 33 行)。
-(docker-compose credit goes to @lukebarone and @QuiGonLeong)
+(感谢 @lukebarone 和 @QuiGonLeong 协助提供的 docker-compose 配置示例)
-> [!NOTE]
-> The rustdesk/rustdesk-server:latest in China may be replaced with the latest version number on Docker Hub, such as `rustdesk-server:1.1.10-3`. Otherwise, the old version may be pulled due to image acceleration.
+## 基于 S6-overlay 的镜像
-> [!NOTE]
-> If you are experiencing issues pulling from Docker Hub, try pulling from the [GitHub Container Registry](https://github.com/rustdesk/rustdesk-server/pkgs/container/rustdesk-server) instead.
+> 这些镜像是针对 `busybox:stable` 构建的,并添加了可执行程序(hbbr 和 hbbs)以及 [S6-overlay](https://github.com/just-containers/s6-overlay)。 它们可以使用以下tag在 [Docker hub](https://hub.docker.com/r/lejianwen/rustdesk-server-s6/) 上获取:
-## S6-overlay based images
-These images are build against `busybox:stable` with the addition of the binaries (both `hbbs` and `hbbr`) and [S6-overlay](https://github.com/just-containers/s6-overlay). They're available on [Docker hub](https://hub.docker.com/r/rustdesk/rustdesk-server-s6/) and [GitHub Container Registry](https://github.com/rustdesk/rustdesk-server/pkgs/container/rustdesk-server) with these architectures:
+| 架構 | version | image:tag |
+| --------- | ------- | -------------------------------------------- |
+| multiarch | latest | `lejianwen/rustdesk-server-s6:latest` |
+| amd64 | latest | `lejianwen/rustdesk-server-s6:latest-amd64` |
+| i386 | latest | `lejianwen/rustdesk-server-s6:latest-i386` |
+| arm64v8 | latest | `lejianwen/rustdesk-server-s6:latest-arm64v8` |
+| armv7 | latest | `lejianwen/rustdesk-server-s6:latest-armv7` |
+| multiarch | 2 | `lejianwen/rustdesk-server-s6:2` |
+| amd64 | 2 | `lejianwen/rustdesk-server-s6:2-amd64` |
+| i386 | 2 | `lejianwen/rustdesk-server-s6:2-i386` |
+| arm64v8 | 2 | `lejianwen/rustdesk-server-s6:2-arm64v8` |
+| armv7 | 2 | `lejianwen/rustdesk-server-s6:2-armv7` |
+| multiarch | 2.0.0 | `lejianwen/rustdesk-server-s6:2.0.0` |
+| amd64 | 2.0.0 | `lejianwen/rustdesk-server-s6:2.0.0-amd64` |
+| i386 | 2.0.0 | `lejianwen/rustdesk-server-s6:2.0.0-i386` |
+| arm64v8 | 2.0.0 | `lejianwen/rustdesk-server-s6:2.0.0-arm64v8` |
+| armv7 | 2.0.0 | `lejianwen/rustdesk-server-s6:2.0.0-armv7` |
-* amd64
-* i386
-* arm64v8
-* armv7
+强烈建议您使用`major version` 或 `latest` tag 的 `multiarch` 架构的镜像。
-You could use `latest` tag or major version tag `1` with supported architectures:
+S6-overlay 在此处作为监控程序,用以保证两个进程的运行,因此使用此镜像,您无需运行两个容器。
-| Version | image:tag |
-| ------------- | ------------------------------------ |
-| latest | `rustdesk/rustdesk-server-s6:latest` |
-| Major version | `rustdesk/rustdesk-server-s6:1` |
-
-The S6-overlay acts as a supervisor and keeps both process running, so with this image, there's no need to have two separate running containers.
-
-You can start these images directly with `docker run` with this command:
+您可以使用 `docker run` 命令直接启动镜像,如下:
```bash
docker run --name rustdesk-server \
--net=host \
-e "RELAY=rustdeskrelay.example.com" \
-e "ENCRYPTED_ONLY=1" \
- -v "$PWD/data:/data" -d rustdesk/rustdesk-server-s6:latest
+ -v "$PWD/data:/data" -d lejianwen/rustdesk-server-s6:latest
```
-or without `--net=host`, but P2P direct connection cannot work.
+或刪去 `--net=host` 参数, 但 P2P 直连功能将无法工作。
```bash
docker run --name rustdesk-server \
@@ -163,10 +207,10 @@ docker run --name rustdesk-server \
-p 21117:21117 -p 21118:21118 -p 21119:21119 \
-e "RELAY=rustdeskrelay.example.com" \
-e "ENCRYPTED_ONLY=1" \
- -v "$PWD/data:/data" -d rustdesk/rustdesk-server-s6:latest
+ -v "$PWD/data:/data" -d lejianwen/rustdesk-server-s6:latest
```
-Or you can use a docker-compose file:
+或着您也可以使用 docker-compose 文件:
```yaml
version: '3'
@@ -175,13 +219,14 @@ services:
rustdesk-server:
container_name: rustdesk-server
ports:
+ - 21114:21114
- 21115:21115
- 21116:21116
- 21116:21116/udp
- 21117:21117
- 21118:21118
- 21119:21119
- image: rustdesk/rustdesk-server-s6:latest
+ image: lejianwen/rustdesk-server-s6:latest
environment:
- "RELAY=rustdesk.example.com:21117"
- "ENCRYPTED_ONLY=1"
@@ -190,26 +235,26 @@ services:
restart: unless-stopped
```
-For this container image, you can use these environment variables, **in addition** to the ones specified in the following **ENV variables** section:
+对于此容器镜像,除了在下面的环境变量部分指定的变量之外,您还可以使用以下`环境变量`
-| variable | optional | description |
-| --- | --- | --- |
-| RELAY | no | the IP address/DNS name of the machine running this container |
-| ENCRYPTED_ONLY | yes | if set to **"1"** unencrypted connection will not be accepted |
-| KEY_PUB | yes | public part of the key pair |
-| KEY_PRIV | yes | private part of the key pair |
+| 环境变量 | 是否可选 | 描述 |
+|----------------|------|--------------------------|
+| RELAY | 否 | 运行此容器的宿主机的 IP 地址/ DNS 名称 |
+| ENCRYPTED_ONLY | 是 | 如果设置为 **"1"**,将不接受未加密的连接。 |
+| KEY_PUB | 是 | 密钥对中的公钥(Public Key) |
+| KEY_PRIV | 是 | 密钥对中的私钥(Private Key) |
-### Secret management in S6-overlay based images
+### 基于 S6-overlay 镜像的密钥管理
-You can obviously keep the key pair in a docker volume, but the best practices tells you to not write the keys on the filesystem; so we provide a couple of options.
+您可以将密钥对保存在 Docker volume 中,但我们建议不要将密钥写入文件系統中;因此,我们提供了一些方案。
-On container startup, the presence of the keypair is checked (`/data/id_ed25519.pub` and `/data/id_ed25519`) and if one of these keys doesn't exist, it's recreated from ENV variables or docker secrets.
-Then the validity of the keypair is checked: if public and private keys doesn't match, the container will stop.
-If you provide no keys, `hbbs` will generate one for you, and it'll place it in the default location.
+在容器启动时,会检查密钥对是否存在(`/data/id_ed25519.pub` 和 `/data/id_ed25519`),如果其中一個密钥不存在,则会从环境变量或 Docker Secret 中重新生成它。
+然后检查密钥对的可用性:如果公钥和私钥不匹配,容器将停止运行。
+如果您未提供密钥,`hbbs` 将会在默认位置生成一个。
-#### Use ENV to store the key pair
+#### 使用 ENV 存储密钥对
-You can use docker environment variables to store the keys. Just follow this examples:
+您可以使用 Docker 环境变量來存储密钥。如下:
```bash
docker run --name rustdesk-server \
@@ -219,7 +264,7 @@ docker run --name rustdesk-server \
-e "DB_URL=/db/db_v2.sqlite3" \
-e "KEY_PRIV=FR2j78IxfwJNR+HjLluQ2Nh7eEryEeIZCwiQDPVe+PaITKyShphHAsPLn7So0OqRs92nGvSRdFJnE2MSyrKTIQ==" \
-e "KEY_PUB=iEyskoaYRwLDy5+0qNDqkbPdpxr0kXRSZxNjEsqykyE=" \
- -v "$PWD/db:/db" -d rustdesk/rustdesk-server-s6:latest
+ -v "$PWD/db:/db" -d lejianwen/rustdesk-server-s6:latest
```
```yaml
@@ -229,13 +274,14 @@ services:
rustdesk-server:
container_name: rustdesk-server
ports:
+ - 21114:21114
- 21115:21115
- 21116:21116
- 21116:21116/udp
- 21117:21117
- 21118:21118
- 21119:21119
- image: rustdesk/rustdesk-server-s6:latest
+ image: lejianwen/rustdesk-server-s6:latest
environment:
- "RELAY=rustdesk.example.com:21117"
- "ENCRYPTED_ONLY=1"
@@ -247,11 +293,11 @@ services:
restart: unless-stopped
```
-#### Use Docker secrets to store the key pair
+#### 使用 Docker Secret 來保存密钥对
-You can alternatively use docker secrets to store the keys.
-This is useful if you're using **docker-compose** or **Docker Swarm**.
-Just follow this examples:
+您还可以使用 Docker Secret 來保存密钥。
+如果您使用 **docker-compose** 或 **docker swarm**,推荐您使用。
+只需按照以下示例操作:
```bash
cat secrets/id_ed25519.pub | docker secret create key_pub -
@@ -263,7 +309,7 @@ docker service create --name rustdesk-server \
-e "ENCRYPTED_ONLY=1" \
-e "DB_URL=/db/db_v2.sqlite3" \
--mount "type=bind,source=$PWD/db,destination=/db" \
- rustdesk/rustdesk-server-s6:latest
+ lejianwen/rustdesk-server-s6:latest
```
```yaml
@@ -273,13 +319,14 @@ services:
rustdesk-server:
container_name: rustdesk-server
ports:
+ - 21114:21114
- 21115:21115
- 21116:21116
- 21116:21116/udp
- 21117:21117
- 21118:21118
- 21119:21119
- image: rustdesk/rustdesk-server-s6:latest
+ image: lejianwen/rustdesk-server-s6:latest
environment:
- "RELAY=rustdesk.example.com:21117"
- "ENCRYPTED_ONLY=1"
@@ -298,57 +345,55 @@ secrets:
file: secrets/id_ed25519
```
-## How to create a keypair
+## 如何生成密钥对
-A keypair is needed for encryption; you can provide it, as explained before, but you need a way to create one.
+加密需要一对密钥;您可以按照前面所述提供它,但需要一个工具去生成密钥对。
-You can use this command to generate a keypair:
+您可以使用以下命令生成一对密钥:
```bash
/usr/bin/rustdesk-utils genkeypair
```
-If you don't have (or don't want) the `rustdesk-utils` package installed on your system, you can invoke the same command with docker:
+如果您沒有(或不想)在系统上安装 `rustdesk-utils` 套件,您可以使用 Docker 执行相同的命令:
```bash
-docker run --rm --entrypoint /usr/bin/rustdesk-utils rustdesk/rustdesk-server-s6:latest genkeypair
+docker run --rm --entrypoint /usr/bin/rustdesk-utils lejianwen/rustdesk-server-s6:latest genkeypair
```
-The output will be something like this:
+运行后的输出内容如下:
```text
Public Key: 8BLLhtzUBU/XKAH4mep3p+IX4DSApe7qbAwNH9nv4yA=
Secret Key: egAVd44u33ZEUIDTtksGcHeVeAwywarEdHmf99KM5ajwEsuG3NQFT9coAfiZ6nen4hfgNICl7upsDA0f2e/jIA==
```
-## .deb packages
+## .deb 套件
-Separate .deb packages are available for each binary, you can find them in the [Releases](https://github.com/rustdesk/rustdesk-server/releases).
-These packages are meant for the following distributions:
+每个可执行文件都有单独的 .deb 套件可供使用,您可以在 [releases](https://github.com/lejianwen/rustdesk-server/releases) 页面中找到它們。
+這些套件适用于以下发行版:
-- Ubuntu 24.04 LTS
- Ubuntu 22.04 LTS
- Ubuntu 20.04 LTS
- Ubuntu 18.04 LTS
-- Debian 12 bookworm
- Debian 11 bullseye
- Debian 10 buster
-## ENV variables
+## ENV 环境变量
-`hbbs` and `hbbr` can be configured using these ENV variables.
-You can specify the variables as usual or use an `.env` file.
+可以使用这些`环境变量`参数來配置 hbbs 和 hbbr。
+您可以像往常一样指定参数,或者使用 .env 文件。
-| variable | binary | description |
-| --- | --- | --- |
-| ALWAYS_USE_RELAY | hbbs | if set to **"Y"** disallows direct peer connection |
-| DB_URL | hbbs | path for database file |
-| DOWNGRADE_START_CHECK | hbbr | delay (in seconds) before downgrade check |
-| DOWNGRADE_THRESHOLD | hbbr | threshold of downgrade check (bit/ms) |
-| KEY | hbbs/hbbr | if set force the use of a specific key, if set to **"_"** force the use of any key |
-| LIMIT_SPEED | hbbr | speed limit (in Mb/s) |
-| PORT | hbbs/hbbr | listening port (21116 for hbbs - 21117 for hbbr) |
-| RELAY | hbbs | IP address/DNS name of the machines running hbbr (separated by comma) |
-| RUST_LOG | all | set debug level (error\|warn\|info\|debug\|trace) |
-| SINGLE_BANDWIDTH | hbbr | max bandwidth for a single connection (in Mb/s) |
-| TOTAL_BANDWIDTH | hbbr | max total bandwidth (in Mb/s) |
+| 参数 | 可执行文件 | 描述 |
+|-----------------------|---------------|--------------------------------------------------|
+| ALWAYS_USE_RELAY | hbbs | 如果设定为 **"Y"**,将关闭直接点对点连接功能 |
+| DB_URL | hbbs | 数据库配置 |
+| DOWNGRADE_START_CHECK | hbbr | 降级检查之前的延迟是啊尽(以秒为单位) |
+| DOWNGRADE_THRESHOLD | hbbr | 降级检查的阈值(bit/ms) |
+| KEY | hbbs/hbbr | 如果设置了此参数,将强制使用指定密钥对,如果设为 **"_"**,则强制使用任意密钥 |
+| LIMIT_SPEED | hbbr | 速度限制(以Mb/s为单位) |
+| PORT | hbbs/hbbr | 监听端口(hbbs为21116,hbbr为21117) |
+| RELAY_SERVERS | hbbs | 运行hbbr的机器的IP地址/DNS名称(用逗号分隔) |
+| RUST_LOG | all | 设置 debug level (error\|warn\|info\|debug\|trace) |
+| SINGLE_BANDWIDTH | hbbr | 单个连接的最大带宽(以Mb/s为单位) |
+| TOTAL_BANDWIDTH | hbbr | 最大总带宽(以Mb/s为单位) |
\ No newline at end of file
diff --git a/img.png b/img.png
new file mode 100644
index 0000000000000000000000000000000000000000..adabf28bceb8b01fa6dc05403ae5955ed3898517
GIT binary patch
literal 49462
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