bewCloud v4.21.0 Docker Compose 部署指南

在 Linux 服务器上用官方发行版从零部署 bewCloud v4.21.0:三服务 Compose 编排逐行说明、数据库迁移、首个管理员注册、文件上传与分享、CalDAV 连通性验证,以及目录权限、Cookie 安全与迁移缺失等部署期高频问题排障,全部命令与回显实测。

bewCloudbewCloudDocker Compose自托管2026/10/30

bewCloud v4.21.0 Docker Compose 部署指南

目标:在一台 Linux 服务器上用官方发行版 ghcr.io/bewcloud/bewcloud:v4.21.0 完成个人云从零到一的部署:三服务编排逐行说明、数据库迁移、首个管理员注册、文件上传与分享、CalDAV 连通性验证,以及部署期最常见的目录权限、Cookie 安全与迁移缺失问题排障。本文所有命令与回显均在 2026-10-30 的实测中逐条执行验证。

本文是 bewCloud 系列的第二篇。第一篇《bewCloud v4.21.0 介绍与选型指南》讲清了「它是什么、八个内置应用覆盖什么、适不适合你」,本篇解决「怎么把它跑起来」。配置文件的逐项参数讲解见 《bewCloud v4.21.0 配置参数详解》,JSON API 与 WebDAV/CalDAV 端点的调用方法见 《bewCloud v4.21.0 API 使用详解》。

一、环境信息

项目值
组件版本bewCloud v4.21.0(官方 GitHub Releases latest,2026-10-30 实查;该版本升级需执行数据库迁移)
发行形态官方 Docker 镜像 ghcr.io/bewcloud/bewcloud:v4.21.0(仅此一种官方发行形态,无裸机安装包)
依赖服务PostgreSQL 18.6(postgres:18.6)、Radicale 3.7.6.0(tomsquest/docker-radicale:3.7.6.0,官方编排指定版本)
服务器系统Linux x86_64(内核 6.x)
对外端口8155 → 应用 8000(Web 界面、JSON API、WebDAV)
内部端口5432(PostgreSQL)、5232(Radicale,仅编排内网可达)
实测日期2026-10-30

bewCloud 的对外面收敛在一个端口:Web 界面、JSON API、WebDAV 文件端点共用 8000,CalDAV/CardDAV 请求也由它统一接收再转发给内网的 Radicale。所以对外只需映射一个端口,这是与「多协议多端口」类服务(流媒体、数据库)显著不同的部署形态。

二、镜像选型说明

官方编排固定三个镜像,本篇实测与其保持一致:

镜像来源选型理由
ghcr.io/bewcloud/bewcloud:v4.21.0GitHub Container Registry(官方唯一发行渠道)应用本体,Deno 运行时内置,固定 tag 保证可复现
postgres:18.6Docker Hub 官方官方编排指定;bewCloud v4.21.0 的迁移脚本在此版本上验证
tomsquest/docker-radicale:3.7.6.0Docker Hub 社区维护(Radicale 官方无 Docker 镜像,这是事实上的社区标准镜像)官方编排指定;提供 CalDAV/CardDAV 数据后端

⚠️ 网络说明:ghcr.io 在部分网络环境拉取缓慢(实测约 40KB/s 量级)。实测可用的替代渠道是南京大学镜像源 ghcr.nju.edu.cn——拉取后用 docker tag ghcr.nju.edu.cn/bewcloud/bewcloud:v4.21.0 ghcr.io/bewcloud/bewcloud:v4.21.0 改回官方名,编排文件无需改动。两个渠道 2026-10-30 均验证可用。

三、前置条件

  1. 服务器已安装 Docker 与 Docker Compose v2(docker compose version 可执行);
  2. 宿主 8155 端口空闲:ss -ltn | grep 8155 确认无输出;
  3. 准备部署目录(示例为 /opt/bewcloud,读者可按自己的目录规范替换),并建好官方要求的三个子目录:
mkdir -p /opt/bewcloud/data-files /opt/bewcloud/data-radicale /opt/bewcloud/radicale-config
  1. 规划访问地址:本篇实测以 http://<服务器IP>:8155 经 HTTP 访问(内网环境),对应配置见 4.3 节的 skipCookieDomainSecurity 说明;若走 HTTPS 反向代理,baseUrl 要写成对外域名。

四、部署步骤

4.1 编写 docker-compose.yml

在 /opt/bewcloud/ 下编写编排文件。项目名显式声明为 bewcloud-v4.21.0-stack,网络名与子网一并显式固定——多套自托管服务并行部署时,显式资源命名能避免 Compose 随机命名带来的操作误伤:

name: bewcloud-v4.21.0-stack

services:
  website:
    image: ghcr.io/bewcloud/bewcloud:v4.21.0
    container_name: bewcloud-v4.21.0-web
    restart: always
    ports:
      - "8155:8000"                # 对外唯一端口:Web / API / WebDAV
    mem_limit: '256m'
    env_file:
      - path: .env                 # 密钥类环境变量(数据库口令、JWT 等)
        required: true
    volumes:
      - ./data-files:/app/data-files          # 用户文件本体
      - ./bewcloud.config.ts:/app/bewcloud.config.ts   # 业务配置(单文件挂载)
    networks:
      - bewcloud-net

  postgresql:
    image: postgres:18.6
    container_name: bewcloud-v4.21.0-db
    environment:
      - POSTGRES_USER=postgres
      - POSTGRES_PASSWORD=q1w2e3r4    # 演示口令,生产请换强口令并与 .env 保持一致
      - POSTGRES_DB=bewcloud
    restart: always
    volumes:
      - bewcloud-db:/var/lib/postgresql/18/docker
    ulimits:
      memlock:
        soft: -1
        hard: -1
    mem_limit: '256m'
    networks:
      - bewcloud-net

  radicale:
    image: tomsquest/docker-radicale:3.7.6.0
    container_name: bewcloud-v4.21.0-dav
    init: true
    read_only: true                    # Radicale 镜像按只读根文件系统设计
    security_opt:
      - no-new-privileges:true
    cap_drop:
      - ALL
    cap_add:
      - SETUID
      - SETGID
      - CHOWN
      - KILL
    restart: always
    volumes:
      - ./data-radicale:/data          # 日历/通讯录条目
      - ./radicale-config:/config:ro   # Radicale 配置(只读挂载)
    mem_limit: '256m'
    networks:
      - bewcloud-net

volumes:
  bewcloud-db:
    driver: local

networks:
  bewcloud-net:
    name: bewcloud-v4.21.0-net
    driver: bridge
    ipam:
      config:
        - subnet: 10.89.63.0/24

逐行说明:

  • website.ports:8155:8000 是对外唯一入口。官方样例写的是 127.0.0.1:8000:8000(仅本机访问),本篇要经局域网访问所以改为全网卡映射;如置于反向代理之后,建议改回绑定 127.0.0.1;
  • website.env_file:.env 是官方要求的必填文件(required: true),只放密钥类变量,逐项见第六节;
  • website.volumes 第一行:data-files 是用户上传文件的本体目录,容器内固定挂到 /app/data-files;第二行把 bewcloud.config.ts 以单文件挂进容器——bewCloud 的业务配置就是一个 TypeScript 文件,改完 docker compose restart website 生效;
  • postgresql.environment:三行与 .env 里的 POSTGRESQL_* 四项一一对应(口令必须一致,否则应用连库失败);
  • postgresql.ulimits.memlock:官方编排原样保留,PostgreSQL 18 的内存页锁定建议;
  • radicale 的 read_only/cap_drop/cap_add:官方编排的安全加固原样保留——Radicale 以非特权用户运行、根文件系统只读,仅保留改属主所需的四个能力;
  • networks.ipam.subnet:显式固定子网,避免与宿主上其他 bridge 网络冲突(实测环境已占用多段 10.89.x.x)。

4.2 编写 .env(密钥文件)

在 /opt/bewcloud/.env 写入(由官方 .env.sample 复制后修改):

PORT=8000
POSTGRESQL_HOST="postgresql"
POSTGRESQL_USER="postgres"
POSTGRESQL_PASSWORD="q1w2e3r4"
POSTGRESQL_DBNAME="bewcloud"
POSTGRESQL_PORT=5432
POSTGRESQL_CAFILE=""
JWT_SECRET="bewcloud-demo-jwt-7a3f9c2e"
PASSWORD_SALT="bewcloud-demo-salt-4d8b1f6a"
#SMTP_USERNAME=""
#SMTP_PASSWORD=""

逐项说明:PORT 是应用监听端口(与 ports 映射右侧一致);POSTGRESQL_HOST/PORT 用编排内服务名 postgresql 与默认 5432;POSTGRESQL_PASSWORD 必须与 4.1 节 POSTGRES_PASSWORD 完全一致;JWT_SECRET 是登录会话签名密钥、PASSWORD_SALT 是口令哈希盐——两者泄露即可伪造登录态,生产环境务必用长随机串替换(生成方式:openssl rand -hex 32);MFA_KEY/MFA_SALT(启用 MFA 时需要)与 OIDC_*(SSO)在本篇未启用故省略,说明见配置篇。

4.3 编写 bewcloud.config.ts(业务配置)

在 /opt/bewcloud/bewcloud.config.ts 写入(由官方样例精简而来,只保留本篇必需项):

import { Config, PartialDeep } from './lib/types.ts';

const config: PartialDeep<Config> = {
  auth: {
    baseUrl: 'http://<服务器IP>:8155',   // 对外访问地址;浏览器可达即可
    allowSignups: false,                  // 关闭开放注册(第一个注册仍会放行并成为管理员)
    enableEmailVerification: false,       // 未配 SMTP,关邮箱验证
    enableForeverSignup: true,            // 注册即长期有效,不过期
    enableMultiFactor: false,             // 演示不启用 MFA
    skipCookieDomainSecurity: true,       // HTTP + IP 访问必须:跳过 Cookie 域安全校验
  },
  files: {
    rootPath: 'data-files',
    allowPublicSharing: true,             // 开启公共分享链接(实测要用)
    allowDirectoryDownloads: true,        // 允许目录打包下载
    maxUploadSizeInMegabytes: 100,        // 单文件上传上限 100MB
  },
  core: {
    enabledApps: ['dashboard', 'files', 'news', 'notes', 'photos', 'expenses', 'contacts', 'calendar'],
    maxRequestSizeInMegabytes: 12,        // 除上传外的请求体上限
  },
  visuals: {
    title: 'My own cloud',
    description: 'This is my own cloud!',
    helpEmail: '',
  },
  email: {
    from: 'help@bewcloud.com',
    host: 'localhost',
    port: 465,
    tlsMode: 'auto',
    tlsVerify: true,
  },
  contacts: {
    enableCardDavServer: true,
    cardDavUrl: 'http://radicale:5232',   // 编排内 Radicale 服务地址
  },
  calendar: {
    enableCalDavServer: true,
    calDavUrl: 'http://radicale:5232',
  },
};

export default config;

关键项解读:auth.baseUrl 决定登录 Cookie 的作用域与绝对链接的生成基准,必须写成浏览器实际访问的地址;skipCookieDomainSecurity: true 是 HTTP + IP 访问的硬前置——bewCloud 默认拒绝在非安全上下文发 Cookie,不开启它登录会静默失败(实测踩坑,见第十一节);files.allowPublicSharing 默认关闭,本篇要实测公共分享链接所以开启。全部字段的完整语义见配置篇。

4.4 编写 Radicale 配置

在 /opt/bewcloud/radicale-config/config 写入(官方样例):

[server]
hosts = 0.0.0.0:5232

[auth]
type = http_x_remote_user

[storage]
filesystem_folder = /data/collections

[web]
type = none

[logging]
level = info
mask_passwords = True

解读:auth type = http_x_remote_user 是三服务协同的核心——Radicale 不自管认证,信任 bewCloud 应用反代进来时注入的 X-Remote-User 头;filesystem_folder 指向挂载的数据卷;[web] type = none 关闭 Radicale 自带 Web 界面(入口被 bewCloud 代理,直接访问无意义)。

4.5 启动与首启确认

cd /opt/bewcloud
docker compose up -d
docker compose ps

实测回显:

NAME                   IMAGE                               COMMAND                  SERVICE      CREATED          STATUS                    PORTS
bewcloud-v4.21.0-dav   tomsquest/docker-radicale:3.7.6.0   "docker-entrypoint.s…"   radicale     43 seconds ago   Up 43 seconds (healthy)   5232/tcp
bewcloud-v4.21.0-db    postgres:18.6                       "docker-entrypoint.s…"   postgresql   43 seconds ago   Up 43 seconds             5432/tcp
bewcloud-v4.21.0-web   ghcr.io/bewcloud/bewcloud:v4.21.0   "/tini -- docker-ent…"   website      13 seconds ago   Up 13 seconds             0.0.0.0:8155->8000/tcp, [::]:8155->8000/tcp

三个服务均为 Up 状态(radicale 会经健康检查转为 healthy)后,确认应用进程已监听:

curl -sI http://<服务器IP>:8155/ | head -5

实测回显:

HTTP/1.1 303 See Other
content-type: text/plain;charset=UTF-8
location: /login
Access-Control-Allow-Origin: *
Access-Control-Allow-Credentials: true

未登录访问根路径被 303 重定向到 /login——这不是故障,而是 bewCloud 全站登录墙的预期行为,说明应用进程已正常监听。

4.6 首次数据库迁移

首次启动后必须执行一次数据库迁移,否则注册用户时会报迁移缺失错误(官方 README 将其列为「首次与每次升级数据变更时」的固定动作):

docker compose run --rm website bash -c "cd /app && make migrate-db"

实测回显(输出节选,实测首尾):

Container bewcloud-v4210-stack-website-run-4c60e33cd3b3 Creating
Container bewcloud-v4210-stack-website-run-4c60e33cd3b3 Created
deno task migrate-db
Task migrate-db deno task execute-with-permissions ./migrate-db.ts
Task execute-with-permissions deno run --allow-env --allow-net --allow-sys=networkInterfaces,hostname,cpus,homedir --allow-read=.,/ --allow-write=data-files,/ --allow-run './migrate-db.ts'
Running "001-base.pgsql"...
Success!
Running "002-news-app.pgsql"...
Success!
Running "003-expenses-app.pgsql"...
Success!
Running "004-public-file-sharing.pgsql"...
Success!
Running "005-authentication-challenges.pgsql"...
Success!

五个迁移脚本逐个执行成功(001 基础表结构到 005 认证质询,v4.21.0 的完整迁移集)。迁移是幂等的:重复执行会提示无待执行迁移。

4.7 修正文件目录属主

应用以镜像内 deno 用户(uid 1993)运行,上传目录属主不对会导致文件写入失败。宿主上执行:

sudo chown -R 1993:1993 data-files
ls -ln data-files

实测回显(目录修正后立即查看为空目录;注册用户并上传文件后复查):

$ ls -ln data-files
total 0

# 注册用户并上传文件后复查:
$ ls -ln data-files
total 4
drwxr-xr-x 6 1993 1993 4096 Oct 30 13:39 9d5ebad4-f6a7-4588-884e-f8c8c8ede632

复查可见按用户 ID 命名的存储目录属主已是 1993:1993(deno 用户)——若不预先 chown,应用将因无写权限创建失败,上传报 500。

4.8 注册第一个用户(自动成为管理员)

浏览器打开 http://<服务器IP>:8155,进入注册页,用演示账号注册:

  • 邮箱:admin@example.com
  • 密码:q1w2e3r4

⚠️ 注意:官方 README 明确说明——即使 allowSignups=false,第一个注册的用户仍然会成功并自动成为管理员,之后的注册才会被关闭。这是单管理员场景的预期行为,不是配置失效。

命令行验证注册页可达与首用户登录(登录请求与 Cookie 验证的全过程见 API 篇 3.x 节,此处仅确认首页与登录跳转):

curl -s http://<服务器IP>:8155/signup | grep -o '<title>[^<]*</title>'

实测回显:

<title>Signup - bewCloud</title>

4.9 登录并进入文件应用

浏览器用 admin@example.com / q1w2e3r4 登录,落地页即 dashboard。命令行验证登录态(Cookie 获取):

curl -s -c /tmp/bewcloud-cookie.txt -X POST http://<服务器IP>:8155/login \
  -d 'email=admin@example.com&password=q1w2e3r4' \
  -o /dev/null -w '%{http_code} %{redirect_url}\n'

实测回显:

303 http://192.168.146.128:8155/

登录成功:303 跳转到 /(随后进入 dashboard 落地页),会话 Cookie 由 -c 参数写入 ~/bewcloud-cookie.txt。带 Cookie 访问受保护页面验证登录态:

curl -s -b ~/bewcloud-cookie.txt -o /dev/null -w '%{http_code}\n' http://<服务器IP>:8155/dashboard

实测回显:

200

五、数据持久化说明

三处持久化各司其职,备份策略围绕它们制定:

数据落点内容备份方式
元数据编排卷 bewcloud-db(宿主由 Docker 管理)用户、文件索引、笔记、RSS、记账、分享记录docker compose exec postgresql pg_dump -U postgres bewcloud > bewcloud.sql
文件本体./data-files上传文件,按用户 ID 分目录直接 rsync/tar 该目录
日历/通讯录./data-radicaleRadicale 集合文件(iCalendar/vCard)直接 rsync/tar 该目录

恢复:新机器上按本篇 4.1–4.4 重建编排后,docker compose up -d,把三个数据落回原位,再执行一次 docker compose run --rm website bash -c "cd /app && make migrate-db"(幂等操作),最后导入 pg_dump 备份即可。

六、环境变量表

.env 全部变量与默认值(来源:官方 .env.sample 与 lib/config.ts,2026-10-30 实查):

变量必填默认/样例值说明
PORT是8000应用监听端口,与 ports 映射右侧一致
POSTGRESQL_HOST是postgresql数据库主机名(编排内服务名)
POSTGRESQL_USER是postgres数据库用户
POSTGRESQL_PASSWORD是样例 fake数据库口令,与 postgresql 服务 environment 一致
POSTGRESQL_DBNAME是bewcloud数据库名
POSTGRESQL_PORT是5432数据库端口
POSTGRESQL_CAFILE否空数据库 TLS CA 文件路径(内网可空)
JWT_SECRET是样例 fake会话签名密钥,生产必须换长随机串
PASSWORD_SALT是样例 fake口令哈希盐,生产必须换长随机串
MFA_KEY / MFA_SALT启用 MFA 时必填空TOTP 加密密钥与盐
OIDC_CLIENT_ID / OIDC_CLIENT_SECRET启用 SSO 时必填空OIDC 单点登录凭据
SMTP_USERNAME / SMTP_PASSWORD启用邮件验证时必填空发信邮箱凭据

💡 技术拓展:为什么配置要拆成 .env + bewcloud.config.ts 两层?这是 v2 重写时的明确设计(官方 FAQ 记载 v1 时代配置全在环境变量里):密钥类值走环境变量便于用 secret 管理工具注入、且不会进版本库;业务配置是类型化的 TypeScript 文件,改配置时编辑器能补全和校验,且可用 git 管理。两类值的判断标准:会泄露身份的进 .env,描述行为的进 bewcloud.config.ts。

七、配置参数说明

bewcloud.config.ts 七个配置域与本篇部署相关的关键项(完整逐项详解见配置篇):

域关键项本篇取值取值原因
authbaseUrlhttp://<服务器IP>:8155浏览器实际访问地址,Cookie 作用域与跳转基准
authallowSignupsfalse封闭注册;首用户不受此限制
authskipCookieDomainSecuritytrueHTTP + IP 访问的硬前置
filesallowPublicSharingtrue实测公共分享链接所需
filesmaxUploadSizeInMegabytes100单文件上传上限
coreenabledApps全部 8 个第一个元素 dashboard 为登录落地页
contacts/calendarcardDavUrl/calDavUrlhttp://radicale:5232编排内 Radicale 地址,应用侧反代目标

八、配置文件挂载

本篇共四处外部文件/目录进容器,路径对应关系(宿主 → 容器):

宿主路径容器路径挂载方式改动后生效方式
.env环境变量注入(非文件挂载)env_filedocker compose up -d 重建
bewcloud.config.ts/app/bewcloud.config.ts单文件 bind mountdocker compose restart website
data-files//app/data-files目录 bind mount即时
data-radicale/ + radicale-config//data + /config(只读)目录 bind mount配置改动需重启 radicale 服务

验证挂载生效:进应用容器确认配置文件就是宿主那份(以 4.3 节的 visuals.title 为锚点):

docker compose exec website grep -n 'My own cloud' /app/bewcloud.config.ts

实测回显:

23:    title: 'My own cloud',

容器内第 23 行就是宿主配置文件里的 visuals.title——挂载与配置内容均确认生效。

九、等价 docker run 命令

不用 Compose 时,三条 docker run 可复现同一部署(先建网络,三条命令逐个执行):

# 1. 创建与 Compose 等价的 bridge 网络
docker network create --subnet 10.89.63.0/24 bewcloud-v4.21.0-net

# 2. PostgreSQL(数据卷 bewcloud-db)
docker run -d --name bewcloud-v4.21.0-db \
  --network bewcloud-v4.21.0-net \
  -e POSTGRES_USER=postgres -e POSTGRES_PASSWORD=q1w2e3r4 -e POSTGRES_DB=bewcloud \
  -v bewcloud-db:/var/lib/postgresql/18/docker \
  --memory 256m --restart always postgres:18.6

# 3. Radicale(只读根文件系统 + 最小能力集)
docker run -d --name bewcloud-v4.21.0-dav \
  --network bewcloud-v4.21.0-net --init --read-only \
  --security-opt no-new-privileges:true --cap-drop ALL \
  --cap-add SETUID --cap-add SETGID --cap-add CHOWN --cap-add KILL \
  -v /opt/bewcloud/data-radicale:/data \
  -v /opt/bewcloud/radicale-config:/config:ro \
  --memory 256m --restart always tomsquest/docker-radicale:3.7.6.0

# 4. bewCloud 应用(等 .env 写好、配置文件就位后)
docker run -d --name bewcloud-v4.21.0-web \
  --network bewcloud-v4.21.0-net \
  -p 8155:8000 --memory 256m --restart always \
  --env-file /opt/bewcloud/.env \
  -v /opt/bewcloud/data-files:/app/data-files \
  -v /opt/bewcloud/bewcloud.config.ts:/app/bewcloud.config.ts \
  ghcr.io/bewcloud/bewcloud:v4.21.0

# 5. 迁移(等价 docker compose run --rm website 的用法)
docker run --rm --network bewcloud-v4.21.0-net --env-file /opt/bewcloud/.env \
  ghcr.io/bewcloud/bewcloud:v4.21.0 bash -c "cd /app && make migrate-db"

说明:启动顺序上 PostgreSQL 与 Radicale 先行,应用最后启动;应用对数据库有启动重试,乱序启动一般也能自愈,但迁移必须等数据库就绪后执行。日常管理仍建议用 Compose(docker compose down 能一次性回收网络,docker run 方式需手动 docker network rm)。

十、常用运维命令

docker compose ps                       # 三服务状态
docker compose logs website --tail 50   # 应用日志(排查登录/上传问题先看这里)
docker compose logs radicale --tail 30  # CalDAV/CardDAV 后端日志
docker compose restart website          # 改 bewcloud.config.ts 后重启生效
docker compose down                     # 停止并回收网络(数据卷与 bind 目录保留)
docker compose down -v                  # 连同数据库卷一起删除(危险:元数据全丢)
docker compose run --rm website bash -c "cd /app && make migrate-db"   # 升级后重跑迁移

升级流程(小版本):改 compose 与 tag 中的版本号 → docker compose up -d → 重跑迁移命令 → 验证登录与大版本 Release Notes 中提到的功能。跨大版本(如 v3→v4)先读 Release Notes 的 breaking changes,备份三处数据后再动。

十一、常见问题

Q1:登录后立刻跳回登录页,或浏览器提示无法保持登录? auth.baseUrl 与实际访问地址不一致,或经 HTTP + IP 访问但没开 skipCookieDomainSecurity: true。bewCloud 默认只信任 HTTPS(localhost 例外)场景的 Cookie;内网 HTTP 访问必须显式跳过校验。改 bewcloud.config.ts 后 docker compose restart website 生效(实测确认)。

Q2:注册时报数据库迁移相关错误? 首次启动后漏执行 docker compose run --rm website bash -c "cd /app && make migrate-db"。补跑即可,该操作幂等。

Q3:文件上传失败或报权限错误? data-files 属主不是 1993(deno 用户 uid)。执行 sudo chown -R 1993:1993 data-files 后重试(实测确认属主正确后上传正常)。ls -ln data-files 可直接核 uid。

Q4:docker compose up 报 .env 缺失? env_file.required: true 是硬校验,.env 文件必须存在(哪怕只放官方样例值)。从官方仓库 .env.sample 复制改名。

Q5:CalDAV 客户端连不上日历? 先确认 calendar.enableCalDavServer 未被关掉;再确认客户端用的是应用端口(8155)而非 Radicale 的 5232——5232 只在编排内网可达,对外统一走应用反代。连通性探针方法见 API 篇 CalDAV 节。

十二、参考链接