01. 部署与配置¶
1. 环境要求¶
| 依赖 | 建议版本 | 必需性 | 说明 |
|---|---|---|---|
| Go | 见根目录 go.mod | 必需 | 当前 toolchain 为 1.26.8;后端构建使用该版本。 |
| Node.js | 20+ | 前端构建必需 | www 使用 Vite 7 和 React 19。 |
| MySQL/MariaDB | MySQL 5.7+ / MariaDB 10.3+ | 必需 | 主业务数据库。 |
| Redis | 6.0+ | release 构建必需 | refresh token、登录失败和注册/验证码保护存储;development/test 构建不可用时可降级到内存。 |
| MinIO | 兼容 minio-go/v7 | 可选 | 对象存储;也可改用本地磁盘(Storage.Driver=local)。 |
| Keycloak | 可选 | 可选 | SSO 登录。 |
Docker Compose 快速部署(Linux)¶
仓库根目录的 compose.yaml 提供 DraARL、MySQL、Redis 和 MinIO 的完整
单机部署。DraARL 镜像使用多阶段构建,最终镜像包含静态 Go 二进制、证书、
时区数据、配置生成工具及固定版本的 ffmpeg/ffprobe,并以非 root 用户运行。
cp .env.example .env
部署前必须修改 .env 中的 MySQL、Redis、MinIO 密码,并核对:
DRAARL_PUBLIC_URL:浏览器访问 DraARL 的 Origin,例如https://radio.example.com。DRAARL_MINIO_ENDPOINT:DraARL 容器和浏览器都可以直接访问的 MinIO 已发布地址host:port或反代域名;不要填写 Compose 内部服务名minio:9000。DRAARL_MINIO_USE_SSL:上述已发布地址是否使用 HTTPS。DRAARL_HTTP_PORT、DRAARL_UDP_PORT:宿主机发布端口。DRAARL_BROADCAST_ENABLED:自动播报部署级硬开关,默认false;由负责接入射频 设备的台站管理员按其设备管理责任显式启用。DRAARL_GO_PROXY:仅影响镜像构建时的 Go 模块下载;默认使用官方代理,所在 网络无法访问时可改为可信的兼容代理。
启动并检查健康状态:
docker compose up -d --build
docker compose ps
curl -fsS http://127.0.0.1:${DRAARL_HTTP_PORT:-9000}/healthz
docker compose logs draarl
首次启动过程如下:
- MySQL、Redis、MinIO 分别通过健康检查。
- DraARL 入口脚本在
draarl-config命名卷中生成一次/var/lib/draarl/config.yaml;未显式提供的 JWT/AES 密钥使用系统随机源生成。 - 默认携带
-auto-migrate初始化或升级结构;旧版minio驱动会在桶不存在时 创建 MinIO bucket,并输出首次管理员凭据。 - 后续重启复用同一配置和全部数据卷,不会重新生成密钥。
DraARL 容器使用只读根文件系统,临时转码只允许写入 64 MiB、noexec/nosuid
的 /tmp。Docker 健康检查除请求 /healthz 外,还会用 60ms 的 16kHz 单声道
PCM 实际编码 Opus 并通过 ffprobe 校验输出;因此容器显示 healthy 时也证明自动
播报转码工具链可用。
Compose 默认将 MinIO 设为 MINIO_BROWSER=off,只发布 9000 S3 API 端口,
不启动或发布 9001 Web Console。DraARL 不会修改 bucket policy;安装包、固件和
其他对象都通过短期预签名 URL 访问,桶应始终保持私有。前端静态资源由 DraARL
主程序直接提供,不写入对象存储。
DRAARL_AUTO_MIGRATE=false 可关闭后续容器启动时的显式迁移;完全空库仍会按
DraARL 的空库规则自动初始化。Compose 环境变量只负责首次生成配置,已有配置
不会被重写,包括 DRAARL_BROADCAST_ENABLED。需要修改完整配置时可导出、编辑
并放回命名卷:
docker compose cp draarl:/var/lib/draarl/config.yaml ./config.yaml
# 编辑 config.yaml
docker compose cp ./config.yaml draarl:/var/lib/draarl/config.yaml
docker compose restart draarl
docker compose down 保留数据;docker compose down -v 会删除数据库、Redis、
MinIO 和 DraARL 配置卷,仅限明确需要清空部署时使用。生产升级前应备份命名卷,
并在宿主机按需要提高 UDP rmem_max/wmem_max,容器不能突破宿主机内核上限。
2. 创建数据库¶
CREATE DATABASE draarl CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
建议为 DraARL 单独创建数据库账号,并只授予该数据库所需权限。
3. 配置文件¶
默认配置文件为 config.yaml。如果命令行未指定 -c,程序会在可执行文件所在目录查找 config.yaml。
复制模板:
cp config.yaml.example config.yaml
Windows:
Copy-Item config.yaml.example config.yaml
4. 核心配置说明¶
4.1 System¶
| 字段 | 说明 |
|---|---|
Host |
UDP 监听地址,空字符串表示所有网卡。 |
Port |
UDP 服务端口,示例为 60050。 |
LogPath |
日志文件路径,空字符串表示不输出到文件。 |
IPfile |
IP 地址库路径,默认 ./ipinfo.ipdb。 |
ProxyProtocol |
可配置 v2,用于从 frp 等代理获取真实客户端 IP。 |
4.2 UDP 实时转发¶
| 字段 | 默认值 | 说明 |
|---|---|---|
SendWorkers |
0 |
并发发送 worker 数;0 按 CPU 自动选择,模板说明的自动上限为 8,手动范围 1-32。 |
IngressWorkers |
0 |
按设备身份分片的入站处理 worker;0 按 CPU 自动选择,模板说明的自动上限为 16。 |
FrameQueueSize |
64 |
fan-out 队列按完整帧计数;队列满时淘汰最旧实时帧。 |
MaxFrameAgeMS |
500 |
超过该本地排队时间的实时帧不再发送;默认覆盖约 4 个 120ms 播报包的短暂抖动。 |
ReadBufferBytes / WriteBufferBytes |
4194304 |
请求的 UDP socket 缓冲;系统实际值以启动日志和 /api/udp/metrics 为准。 |
自动 worker 值适合通用部署;只有经过目标机器压测后才应手工放大。队列和帧龄是实时 保护机制,不是可靠消息队列,过载时允许丢弃过期媒体以避免延迟无限累积。
4.3 幽灵 Session 与频道消息¶
GhostSessions 在单机、中心和边缘均参与校验。中心和所有边缘应保持相同上限,
避免同一账号迁移入口后出现不同的接纳结果。幽灵多端/多收始终启用,没有旧协议降级开关。
| 字段 | 默认值 | 有效范围 | 说明 |
|---|---|---|---|
GhostSessions.MaxSessionsPerOwner |
8 |
1-64 | 同一账号可同时在线的 UDP/WS 幽灵 Session 总数。 |
GhostSessions.MaxSubscriptionsPerSession |
16 |
1-256 | 每个 Session 的接收频道上限;发送频道也计入并必须属于接收集合。 |
MessageAPI 保护频道历史列表与详情查询:
| 字段 | 默认值 | 有效范围 | 说明 |
|---|---|---|---|
DefaultPageSize |
50 |
1 至 MaxPageSize |
未传 limit 时的列表条数。 |
MaxPageSize |
100 |
1-1000 | 单次消息列表最大条数。 |
RequestsPerMinutePerUser |
120 |
1-1000000 | 每账号共享的列表/详情请求窗口。 |
RequestsPerMinutePerIP |
300 |
1-1000000 | 每来源 IP 共享的列表/详情请求窗口。 |
MaxConcurrentQueries |
32 |
1-4096 | 全局同时执行的消息数据库查询数。 |
账号/IP 超限返回 429 和 Retry-After;查询槽满返回 503 message_api_busy。
提高上限前应使用真实 MySQL 数据量检查游标索引与查询延迟。
4.4 Database¶
| 字段 | 说明 |
|---|---|
Host / Port |
MySQL 地址。 |
User / Password |
数据库账号。 |
DBName |
数据库名。 |
Charset / Collate |
默认 utf8mb4 / utf8mb4_unicode_ci。 |
Timezone |
数据库时间解释。默认 Local 保持旧行为;显式填写 IANA 时区(如 UTC 或 Asia/Shanghai)会同时设置 Go 解码位置、GORM NowFunc 和 MySQL session time_zone。 |
MaxOpenConns |
最大打开连接数,默认 25。 |
MaxIdleConns |
最大空闲连接数,默认 5。 |
MaxLifetime |
连接最大存活时间,单位秒,默认 300。 |
4.5 Redis¶
Redis 用于 refresh token、登录失败和注册/验证码保护。release 构建启动时必须连接 Redis,连接失败会拒绝启动;development/test 构建连接失败时可降级到内存。内存模式只适合开发测试,服务重启后 refresh token 和共享限速状态会丢失。
| 字段 | 说明 |
|---|---|
Host / Port |
Redis 地址。 |
Password |
Redis 密码。 |
DB |
Redis 数据库编号。 |
Prefix |
Key 前缀,默认 draarl。 |
DialTimeoutSec / ReadTimeoutSec / WriteTimeoutSec |
连接和读写超时。 |
PoolSize |
连接池大小。 |
4.6 Web¶
| 字段 | 说明 |
|---|---|
Host |
HTTP 监听地址,空字符串表示所有网卡。 |
Port |
HTTP/API/WebSocket 服务端口。 |
FrontendURL |
前端对外地址,用于 SSO 回调重定向,也会加入 Origin 白名单。 |
AllowedOrigins |
允许访问 API 和 WebSocket 的页面来源。生产环境必须正确配置。 |
生产环境注意:
- 后端会校验
Origin/Referer。 - release 构建下如果没有可解析的
FrontendURL或AllowedOrigins,程序会启动失败。 - API 网关会拒绝 URL query 中出现 token 类参数,例如
token、access_token、refresh_token、jwt。
4.7 Keycloak¶
Keycloak 为可选 SSO 配置。启用后,登录页会显示 SSO 登录入口。
| 字段 | 说明 |
|---|---|
Enabled |
是否启用 SSO。 |
Name |
前端显示名称。 |
BaseURL |
Keycloak 服务器地址。 |
Realm |
Realm 名称。 |
ClientID / ClientSecret |
客户端配置。 |
RedirectURI |
后端 /api/sso/callback 回调地址。 |
4.8 存储(Storage / S3 兼容对象存储)¶
系统通过统一存储抽象支持 local、MinIO、Cloudflare R2、腾讯云 COS 和阿里云 OSS。除 local 外,所有实现都通过同一个 S3 V4 驱动工作,不会为每个厂商复制上传、校验或发布流程:
Storage.Driver |
说明 |
|---|---|
minio |
使用 Storage.MinIO 连接对象存储;支持 S3 预签名直传。 |
s3 / r2 / cos / oss |
使用 Storage.S3;r2、cos、oss 是 S3 兼容别名。 |
local |
文件写入 Storage.Local.RootPath;明确允许公开的站点图片可走 /files/*,其他对象使用签名 GET。 |
| 空 | 若 Storage.MinIO.Endpoint 非空则选 minio,否则 local。 |
| 字段 | 说明 |
|---|---|
Storage.Local.RootPath |
本地存储根目录,默认 ./data/storage。 |
Storage.Local.BaseURL |
公开 URL 前缀,空则使用 /files。 |
Storage.UseCDN |
默认 false;启用后,对象 GET 链接统一使用 EdgeOne TypeA 签名。适用于当前 active profile 或旧配置。 |
Storage.CDNBaseURL |
CDN 的完整 http(s):// 访问前缀,可包含路径;仅在 UseCDN=true 时生效。 |
Storage.CDNSignParam |
鉴权参数名称,默认 sign;支持 1-100 位英文字母、数字或下划线。 |
Storage.CDNExpirySeconds |
CDN 链接有效秒数,默认 3600(1 小时),范围 1-630720000;必须与 EdgeOne 鉴权规则一致。 |
Storage.CDNKey |
EdgeOne 鉴权密钥,支持精确的 ${ENV_NAME} 引用。 |
Storage.UploadLimits.ClientResourceBytes |
通用客户端资源直传上限,默认 536870912(512 MiB)。固件继续使用独立的 16 MiB 限制。 |
Storage.MinIO.Endpoint |
后端连接 MinIO 的地址,可以使用容器网络或内网地址。 |
Storage.MinIO.PublicEndpoint |
可选的对外 host:port;预签名 URL 使用此地址,留空回退到 Endpoint。 |
Storage.MinIO.AccessKey / SecretKey |
凭据。 |
Storage.MinIO.UseSSL |
是否使用 HTTPS。 |
Storage.MinIO.PublicUseSSL |
PublicEndpoint 是否使用 HTTPS。 |
Storage.MinIO.Bucket |
默认桶名。 |
Storage.MinIO.DownloadURLPrefix |
可选,仅替换预签名 GET 的访问前缀;预签名 PUT 不使用它。 |
Storage.ActiveProfile |
当前运行的命名 profile。设置后优先于旧的 Driver/MinIO 配置。 |
Storage.Profiles.<name>.Driver |
local、s3、minio、r2、cos 或 oss。 |
Storage.Profiles.<name>.S3.Endpoint |
后端连接的 S3 API 地址,可写 host:port 或完整 http(s):// URL;显式 scheme 优先于 UseSSL。 |
Storage.Profiles.<name>.S3.PresignEndpoint |
浏览器实际访问的 S3 API 地址,只用于生成 PUT/GET 签名;显式 scheme 优先于 PresignUseSSL。 |
Storage.Profiles.<name>.S3.DownloadURLPrefix |
高级选项:替换预签名 GET 的 URL 前缀,供用户自行配置的反向代理使用;不代表对象公开。 |
Storage.Profiles.<name>.S3.Region / BucketLookup |
region 和桶寻址方式(auto、path、dns)。 |
Storage.Profiles.<name>.S3.SessionToken |
可选 STS 会话令牌。 |
Storage.Profiles.<name>.S3.AutoCreateBucket |
仅开发 MinIO 建议设为 true;公有云保持 false,由部署侧预创建 bucket。 |
未显式填写 BucketLookup 时,r2 和 minio 默认使用 path,cos 和 oss 默认使用 dns,通用 s3 使用 auto;其他值会在启动时直接报错,不会静默回退。推荐端点格式:R2 使用 <account-id>.r2.cloudflarestorage.com,Region 留空时自动设为 auto;COS 使用 cos.<region>.myqcloud.com、真实 Region 及包含 AppID 的 bucket 名;OSS 使用 oss-<region>.aliyuncs.com 和真实 Region。COS、OSS 缺少 Region 时会拒绝启动。完整 profile 示例见 config.yaml.example。
运行凭据至少需要检查 bucket、列举指定前缀、读取对象、写入对象和删除对象的权限;Promote 还需要读取 staging 源对象并在 final key 执行服务端复制。建议把权限限制到业务 bucket,并尽可能限制到 staging/、client-resources/、firmware/、assets/ 等应用前缀。应用不会修改 bucket policy;若启用存储迁移,还需覆盖迁移源和目标所需权限。
AccessKey、SecretKey 和 SessionToken 支持精确的 ${ENV_NAME} 引用。变量在创建存储客户端时解析,解析值不会回写配置文件;变量缺失或为空会使存储初始化失败并明确指出字段。也可以通过容器 Secret 生成未跟踪的生产配置。
旧版本顶层 MinIO: 配置会在启动时自动迁移到 Storage.MinIO;显式设置 Storage.Driver: local 时不会迁移旧 MinIO 配置。旧 BasePath 和 PublicBaseURL 会打印弃用提示并迁移为 DownloadURLPrefix,不再产生匿名、无签名 URL。
上传策略固定为:
- 代理上传(需服务端图像处理):头像、Logo、Favicon
- 浏览器直传(presign → PUT → complete):资源中心、固件、操作证、通用客户端资源(含安装包、模型和字库)
直传对象先写入按用户隔离的 staging 路径,complete 校验签名授权和实际大小后才提升为不可变对象。超过 24 小时未完成的 staging 对象会自动清理;管理员可在资源页重新识别自己的已完成 staging 上传并重签 complete 凭证。客户端资源和固件通过短时下载 URL 返回;local 驱动也使用 /api/storage/get 的短时签名 URL,client-resources/、firmware/ 和 staging/ 不能由 /files/* 永久访问。
资源中心、头像、站点图片、操作证和通联录音的历史响应字段也通过统一读取 URL 策略生成。未启用 CDN 时,local 仅对明确允许的头像、Logo 和 Favicon 返回稳定 /files/* 地址,其他对象使用签名 GET;S3 兼容存储返回预签名 GET URL。启用 CDN 后,这些对象读取链接和固件、客户端资源下载链接统一使用 CDN TypeA 签名。前端不应持久化签名 URL,页面长时间打开后应重新请求相应业务接口。
EdgeOne CDN 配置示例(与现有存储配置合并):
Storage:
UseCDN: true
CDNBaseURL: "https://cdn.example.com"
CDNSignParam: "sign"
CDNExpirySeconds: 3600
CDNKey: "${EDGEONE_CDN_KEY}"
在 EdgeOne 控制台启用 TypeA 鉴权,把鉴权参数名、密钥和有效时长设为与上面相同的值。签名格式为 ?sign=timestamp-rand-0-md5hash,其中 md5hash=MD5(Path-timestamp-rand-0-key);Path 为 URL 编码后的完整访问路径,包含 CDNBaseURL 的路径前缀,不含查询参数。程序按 CDNBaseURL + / + object_key 拼接,不自动添加 bucket 名;若 CDN 访问路径需要 bucket 或其他前缀,应将它写入 CDNBaseURL。
TypeA 的 timestamp 是签发时间,EdgeOne 按 timestamp + 有效时长 判断过期。启用 CDN 后以 CDNExpirySeconds 为所有 CDN 链接的有效期,覆盖业务接口原有的 15 分钟或 1 小时设定;客户端资源的 url_expires_at 也按该配置返回。调整有效期时需同步修改 EdgeOne 规则。鉴权在缓存命中前执行,EdgeOne 鉴权通过后会忽略鉴权参数进行缓存。
CDN 需配置能访问私有源站的回源鉴权,bucket 可继续保持私有。上传、对象校验、复制和删除仍使用原存储驱动;S3 预签名 PUT 使用原 PresignEndpoint,CDN GET 不使用 DownloadURLPrefix 或 X-Amz-* 参数。历史绝对 URL 按原值返回。配置后重启服务生效。
S3 兼容直传 CORS 要求:
- 允许前端 Origin 的
PUT、GET、HEAD(以及预检OPTIONS) - 允许请求头
Content-Type以及供应商签名流程需要的x-amz-*请求头 - 暴露响应头
ETag - 生产建议 HTTPS 反代 MinIO,并保证签名 URL 中的 host 浏览器可达
- 预签名依赖服务端与对象存储时间一致;生产环境应启用 NTP 时间同步
- 应通过 Secret、环境变量或未跟踪配置提供 AccessKey/SecretKey,示例文件不得填写生产密钥
未启用 UseCDN 时,DownloadURLPrefix 继续用于 S3 预签名 GET 的反向代理。程序先针对 PresignEndpoint 生成完整 S3 V4
预签名 GET,再把浏览器访问前缀替换为该值,并保留对象路径和全部 X-Amz-*
查询参数。代理必须在回源时恢复签名使用的 Host 和原始 S3 路径,否则会返回
SignatureDoesNotMatch。DraARL 不配置或检测 CDN 缓存键、回源 Header、方法限制
和边缘鉴权;未充分理解 S3 V4 canonical request 时应保持该字段为空。
对私有对象使用缓存时,不要简单从缓存键中忽略全部签名参数。否则合法请求预热后, 伪造、缺失或过期签名也可能直接命中缓存并绕过源站鉴权。缓存 TTL 也不应超过预签名 URL 有效期。此类高级代理配置由部署方自行验证,项目只保证未配置前缀时的标准 S3 预签名行为。
可使用同一套可选契约测试验证 MinIO、R2、COS 或 OSS;当前 MinIO 已通过含 CORS 的契约,R2、COS 和 OSS 已通过除部署 Origin CORS 外的存储契约和完整客户端资源 HTTP 生命周期。测试会在指定桶的
contract-tests/ 和 staging/contract-tests/ 前缀创建并清理临时对象,覆盖 Put、Stat、Open、Walk、Delete、预签名 PUT/GET、服务端复制、不可覆盖 final key 和 CORS:
DRAARL_S3_TEST_PROVIDER=minio \
DRAARL_S3_TEST_ENDPOINT=127.0.0.1:9000 \
DRAARL_S3_TEST_PRESIGN_ENDPOINT=127.0.0.1:9000 \
DRAARL_S3_TEST_ACCESS_KEY=test-access-key \
DRAARL_S3_TEST_SECRET_KEY=test-secret-key \
DRAARL_S3_TEST_BUCKET=draarl-contract \
DRAARL_S3_TEST_BUCKET_LOOKUP=path \
DRAARL_S3_TEST_CORS_ORIGIN=https://admin.example.com \
go test ./pkg/storage -run '^TestS3CompatibleContract$' -count=1 -v
设置 DRAARL_S3_TEST_CORS_ORIGIN 后还会对预签名 PUT URL 发起浏览器等价的 OPTIONS 预检,并验证 Origin、PUT 和 Content-Type。只有使用无并发上传的专用测试桶时,
才可设置 DRAARL_S3_TEST_DESTRUCTIVE_CLEANUP=true 验证过期 staging 删除;默认
模式不会删除桶内其他 staging 对象。
R2 使用 <account-id>.r2.cloudflarestorage.com、Region=auto、BucketLookup=path,并启用 API 和预签名地址的 SSL。COS 使用 cos.<region>.myqcloud.com、真实 Region、包含 AppID 的 bucket 名和 BucketLookup=dns;OSS 使用 oss-<region>.aliyuncs.com、真实 Region 和 BucketLookup=dns。仓库不为存储契约保留常驻 GitHub Actions;此类测试使用专用测试环境按需手动执行,测试凭据不得写入仓库。GitHub Actions 只保留 Release 和 MkDocs Pages。
客户端资源的完整 HTTP 生命周期测试还需要名称以 draarl_test_ 开头的专用
MySQL 数据库。它会先使用临时 local 目录,再在提供 DRAARL_S3_TEST_* 时使用
同一 S3 目标,覆盖 JWT 管理员鉴权、多目标直传、服务端 SHA-256、complete、
发布、manifest、按需签名下载、Range、ETag、撤回和固件隔离:
DRAARL_CLIENT_RESOURCE_E2E=true \
DRAARL_TEST_MYSQL_DSN='user:password@tcp(127.0.0.1:3306)/draarl_test_client_resource_http?charset=utf8mb4&parseTime=true&loc=Local' \
DRAARL_S3_TEST_PROVIDER=minio \
DRAARL_S3_TEST_ENDPOINT=127.0.0.1:9000 \
DRAARL_S3_TEST_PRESIGN_ENDPOINT=127.0.0.1:9000 \
DRAARL_S3_TEST_ACCESS_KEY=test-access-key \
DRAARL_S3_TEST_SECRET_KEY=test-secret-key \
DRAARL_S3_TEST_BUCKET=draarl-contract \
DRAARL_S3_TEST_BUCKET_LOOKUP=path \
go test ./internal/handler -run '^TestClientResourceHTTPE2E$' -count=1 -v
4.9 JWT 与设备认证¶
| 字段 | 说明 |
|---|---|
JWT.Secret |
JWT 签名密钥,最少 32 字符。不符合要求时程序会自动生成并写入配置文件。 |
DeviceAuth.AESKey |
设备密码加密密钥,必须为 16、24 或 32 字节。不符合要求时程序会自动生成并写入配置文件。 |
4.10 中心间群组互联¶
dev 的中心互联只使用两个现有端口:HTTP/HTTPS 服务承载低频邀请准入,System.Port
承载普通设备和互联音频。不存在第三个中心互联 TLS 端口。
管理员在“群组管理 → 中心互联”生成邀请。A 选择本地群组和收发控制后得到一次性 Token;
B 填入 Token、A 的 HTTP/HTTPS 地址、B 的本地群组和 B 侧收发控制。B 服务端用 Token
secret 生成 HMAC 准入证明,A 校验后创建 AES-GCM UDP 会话;响应中的会话、端点、群组和
策略摘要也带有 HMAC,B 校验后才落库。HTTP 响应不会返回会话密钥,两端用 Token verifier
和 session ID 独立派生密钥,随后在主 UDP 端口交换经过认证的 CPUD 音频数据。两端的用户、
设备和权限保持独立,远端音频在本地显示为 Server-* 虚拟设备。
邀请按 Interconnect.RegistrationTokenTTL 自动过期;过期后需要重新生成邀请。
启用中心互联所需的配置如下:
Interconnect:
Enabled: false
CenterID: "center-a"
RegistrationTokenTTL: 86400
CredentialRotationGraceSeconds: 600
SessionRecoveryWindowSeconds: 180
生产部署应让管理 HTTP 经过 HTTPS。准入接口有请求体、超时、响应大小和源 IP 限速;UDP 会话有地址绑定、重放窗口、包速率和队列上限。详细的接口、数据面和故障处理见 多中心群组互联。
旧无数据库边缘运行时只保留在 edge 分支。dev 不读取边缘配置,也不启动旧 Type 0
控制面;需要维护旧边缘部署时应在 edge 分支查看对应文档。
4.11 设备接入点发现¶
设备接入点发现在管理员后台的“站点配置 → 接入点”中管理,不再读取
config.yaml。当前列表只发布本主站的中心入口;管理员可以调整发现凭证和客户端
缓存时长,保存后立即生效。平台只返回入口列表;网络延迟由客户端自行 ICMP 测量,
不由服务器代测。
中心位于 NAT 或 FRP 后方时,“公网 UDP 地址”和“公网 UDP 端口”应填写设备实际 访问的外部地址和映射端口,而不是中心的内网监听地址。列表不会返回控制地址、凭据 或运维指标。多收发器和多个中心入口暂不加入该接口。
4.12 群组自动播报¶
自动播报只在中心完整模式执行。Broadcast.Enabled 是部署级硬开关,默认关闭;Compose
首次生成配置时由 DRAARL_BROADCAST_ENABLED 写入,已有配置卷不会因修改环境变量而
自动重写。启用后还需保证统一对象存储可用,并安装可执行的 ffmpeg/ffprobe;官方镜像
已经固定版本并通过容器健康检查验证 16kHz 单声道 Opus 编码链路。
| 字段 | 默认值 | 有效范围/说明 |
|---|---|---|
Enabled |
false |
部署级开关;修改配置后重启 |
QuietWindowSeconds |
5 |
1-30 秒,触发前活动通信域必须持续静默 |
MaxAudioDurationSeconds |
30 |
1-60 秒,服务端硬上限 60 秒 |
MaxUploadBytes |
20971520 |
1 KiB-100 MiB,原始文件上限 |
TranscodeTimeoutSeconds |
90 |
5-300 秒,探测与转码总超时 |
TranscodeMemoryLimitMB |
512 |
512-1024 MiB,Linux 子进程地址空间上限 |
TranscodeCPULimitSeconds |
60 |
1-300 秒,Linux 子进程累计 CPU 时间上限 |
ScanIntervalMS |
1000 |
250-5000ms,到期计划扫描间隔 |
RecoveryWindowSeconds |
10 |
1-300 秒,只恢复重启附近的短暂到期轮次 |
ClaimBatchSize |
20 |
1-100,每轮最大认领数 |
FFmpegPath / FFprobePath |
程序名 | 可执行文件路径 |
站点管理员可用 PUT /api/broadcast/runtime 持久化日常运行开关,或用
POST /api/broadcast/emergency-stop 取消当前任务。这两项不修改部署级配置;运行态重新
开启时不会补发停用期间错过的轮次。监控使用 /api/broadcast/health 和
/api/broadcast/metrics。完整计划、互联、状态和记录契约见
群组自动播报 API。
射频台站设备由相应台站管理员自行接入、配置并对其射频运行负责。平台只向已经审核的 用户提供服务;自动播报音频和计划仅允许平台管理员或实体组群主管理,并由相应管理员 维护和审查播报内容。
5. 后端运行¶
go mod download
go build -o draarl ./cmd/draarl
./draarl -c config.yaml
常用启动参数:
| 参数 | 说明 |
|---|---|
-c <path> |
指定配置文件。 |
--edge / --interconnect |
仅 edge 分支提供的无中心依赖边缘启动参数;dev 分支不包含该入口。 |
-v |
打印版本信息。 |
-p json |
打印关键配置。 |
-auto-migrate |
显式创建或升级数据库结构;目标数据库完全没有表时,省略该参数也会自动初始化。 |
-reset-admin-pass <password> |
重置管理员密码。 |
-migrate-storage <from:to> |
跨存储驱动或 profile 迁移对象(如 minio:local 或 minio-prod:r2-prod),纯命令行,不启动主服务。 |
-migrate-dry-run |
配合 -migrate-storage,仅统计迁移计划,不实际写入。 |
-migrate-delete-source |
配合 -migrate-storage,迁移并校验成功后删除源端对象(默认保留)。 |
-migrate-max-bytes-per-second |
配合 -migrate-storage,限制所有迁移 worker 合计读取源端的速率(字节/秒;默认 0 不限速)。 |
6. 存储引擎迁移¶
在不同存储引擎之间迁移文件对象(例如从 MinIO 迁到本地磁盘,或反向)。该命令为纯命令行工具,不启动主服务,也不修改数据库——因为数据库中保存的是 object key,两种引擎通用,迁移只是按 key 把对象从源端拷贝到目标端。
# 预览:只统计不写入
./draarl -c config.yaml -migrate-storage minio:local -migrate-dry-run
# 通过命名 profile 从 MinIO 迁移到 R2
./draarl -c config.yaml -migrate-storage minio-prod:r2-prod -migrate-dry-run
# 正式迁移(保留源端,便于验证)
./draarl -c config.yaml -migrate-storage minio:local
# 验证无误后,迁移并删除源端对象
./draarl -c config.yaml -migrate-storage minio:local -migrate-delete-source
要点:
- 源与目标从同一份配置读取:
minio:local使用旧的Storage.MinIO与Storage.Local;minio-prod:r2-prod使用Storage.Profiles中两个独立 profile。迁移完成后,把Storage.ActiveProfile或Storage.Driver改成目标再启动服务。 - 仅支持跨引擎:
local:local、minio:minio会被拒绝。同引擎换桶/换路径属高级场景,请用专用工具(如mc mirror、rsync)。 - 断点续传:目标端已存在同 key 且大小一致的对象会被跳过,因此进程意外退出后直接重跑即可,不会重复传输。写入为原子操作,崩溃不会残留半个对象。
- 非破坏:默认只拷贝不删除源端。确认迁移结果无误后,再用
-migrate-delete-source清理源端。 - 跳过范围:
staging/(未完成的临时上传)和frontend/(CDN 同步产物)不迁移。 - 历史绝对 URL:早期以完整 URL 存储的 logo/favicon 不在迁移范围内,如更换引擎后断链需重新上传。
7. 数据库迁移¶
当目标数据库完全没有表时,普通启动会自动执行 GORM 迁移并初始化表结构:
./draarl -c config.yaml
只要数据库中已经存在任意一张表,普通启动就不会修改数据库结构。创建缺失表、升级已有结构或清理遗留字段时,必须显式传入 -auto-migrate:
./draarl -c config.yaml -auto-migrate
群组自身呼号和设备准入白名单停用后,普通启动会直接忽略历史
public_groups.call_sign、public_groups.allow_callsign_ssid 列;显式执行
-auto-migrate 时会删除遗留列。表或列已经不存在时会安全跳过。
如果准入白名单列仍有非空配置,迁移会中止并要求先人工确认清理,避免静默丢失数据。
自动迁移会:
- 清理部分重复或孤儿数据。
- 自动创建/更新核心表结构。
- 建立级联外键约束。
- 确保
users.callsign、devices(owner_id, ssid)等唯一索引。 - 删除
group_members历史设备级字段。
生产环境首次升级前建议备份数据库。
历史 v1.1.5-alpha1 的 Type 0 首次上线资料见历史升级说明。
从更早版本升级到 v2.0.0-alpha3 时,幽灵多端、频道消息和投递快照迁移见历史升级说明。
8. 管理员初始化¶
首次启动时,如果数据库中不存在名为 admin 的用户,程序会创建默认管理员并在日志输出随机密码。该用户:
- 用户名:
admin - 角色:
admin - 审核状态:已通过
重置管理员密码:
./draarl -c config.yaml -reset-admin-pass "NewPassword123"
9. 前端开发运行¶
cd www
npm install
npm run dev
当前 vite.config.ts 中开发服务器端口为 9001,并将 /api 代理到 http://localhost:9002。如果后端 Web 端口不是 9002,需要调整开发环境的 API 地址或代理配置。
10. 发布构建¶
Unix/macOS/Linux:
./build.sh v1.2.3
Windows:
.\build.bat v1.2.3
发布脚本流程:
- 清理旧产物。
- 构建
www/dist。 - 将前端产物复制到
internal/server/web/dist。 - 使用
-tags=embed构建后端,将前端嵌入二进制。 - 清理临时嵌入目录。
发布模式下,Go 二进制可同时提供 API 和前端页面。非 embed 构建只提供 API,访问前端路由会返回 frontend not embedded, build with -tags=embed。
11. 相关 API¶
| Method | Path | Auth | 说明 |
|---|---|---|---|
| GET | /api/platform/info |
Public | 平台信息。 |
| GET | /api/platform/totalstats |
Public | 平台统计。 |
| GET | /api/config/public |
Public | 公开站点配置。 |
| GET | /api/config/category/:category |
JWT | 分类配置读取。 |
| GET | /api/config/all |
Admin | 全部配置。 |