生产环境必须通过 HTTPS/WSS 访问。推荐在 RemoteCI 前放置 Caddy、Nginx、Traefik 或 NAS 自带反向代理,并把外部 HTTPS 转发到容器的 HTTP 8080 端口。
首次部署不需要预先设置管理员密码:第一次在浏览器打开 WebUI 时会进入初始化向导,在页面上创建系统管理员的登录 ID 与密码,然后手动新建第一个班级。服务端不再生成随机初始密码,也不会把它写进日志。
无人值守部署(例如脚本或 CI)仍可在 .env 中预先提供,不要提交到仓库:
# 可选:预先创建系统管理员(登录 ID 为 admin),留空则在 WebUI 初始化向导中设置
REMOTECI_ADMIN_PASSWORD=请替换为至少8位的强密码
# 可选:插件引导配对码,使用它接入的设备进入“未分配设备”,需在班级管理中分配到班级
REMOTECI_PLUGIN_PAIR_CODE=请替换为一次性随机配对码数据库创建完成后,这些初始值不会再次使用;不要把密码写入镜像、Compose 文件或版本库。
docker compose up -d --build
docker compose logs remoteciCompose 只把 127.0.0.1:8080 暴露给宿主机,并把 SQLite 挂载到命名卷 remoteci-data:/app/data。反向代理必须转发以下内容:
- 普通 HTTP 请求和 Cookie。
/ws的 WebSocket Upgrade。X-Forwarded-For与X-Forwarded-Proto。
WebUI 的浏览器通知(换课申请提醒,关闭网页后仍可收到)要求 WebUI 通过 HTTPS 访问(本机 localhost 除外),并由服务端向浏览器自己的推送服务发出 HTTPS 请求:Chrome 使用 FCM(国内网络可能不可达),Edge 使用 WNS,Firefox 使用 Mozilla Push。服务端需要能访问对应域名。HTTP 局域网部署只能在打开网页时通过顶栏铃铛看到提醒。VAPID 密钥在第一次开启浏览器通知时自动生成并保存在数据库里;恢复到更早的数据库备份后,已订阅的浏览器需要重新开启通知。
iPhone/iPad 可通过主屏幕 PWA 接收通知,服务端需额外放通 *.push.apple.com 的 HTTPS 出站访问。安装、手机界面与个人日历订阅见手机端说明。
生产手表的云端地址必须填写 https:// URL。局域网 ws://电脑IP:8765/ws 只用于同一可信网络内的手表到插件连接。
服务端只在 WebSocket 握手时完整查询令牌,正常的每秒状态推送复用连接内身份;插件凭据、设备会话、密码或账号权限发生变化时会主动刷新或断开对应连接。另有每分钟一次的数据库授权兜底复查,可用 Server__ConnectionAuthorizationRefreshInterval 调整;生产环境建议保留默认 00:01:00,不应把它改成每秒轮询。
- 打开公开 HTTPS 地址,按初始化向导创建系统管理员(登录 ID、显示名称与密码)。系统管理员拥有全部权限,并且只能由本人修改:其他管理员不能编辑、停用、重置密码或删除它。
- 向导第二步新建第一个班级。RemoteCI 不再自动创建“默认班级”,新账号也不会自动加入任何班级;在“概览”生成配对码即可把教室端插件连接到当前班级。
- 登录页勾选“保持登录”后,WebUI 会话有效期 30 天并在持续访问时自动续期,关闭浏览器后仍保持登录;未勾选时会话随浏览器关闭失效。
- 在“个人账号”中修改密码;改密会撤销所有手表设备会话。
- 在“人员权限”中为每个同学建立唯一 ID、账号名、初始密码并选择所属班级;登录时只输入 ID。
- 管理员拥有全部权限且不显示附加权限选项;学生默认只看当前课,可按需勾选六项附加权限。
- 学生登录后可以在个人页面修改自己的密码和撤销设备。
从旧版本升级时,系统会把原引导管理员(默认 admin)标记为系统管理员。旧版自动创建的“默认班级”如果从未改名且已经有其他班级,会在首次启动新版本时移除:其中仍在使用的设备转入“班级管理 → 未分配设备”,保留凭据,分配到正确班级后即可继续使用;单班级部署中的默认班级会保留为普通班级,可以改名或删除。
现有账号区域只列出账号名、ID 和角色。需要修改账号资料、启用状态、学生附加权限、密码或删除账号时,先点击该行右侧的“编辑”打开对话框。
新建账号校验失败时,页面只清空格式错误或已被占用的字段,其他输入、角色和权限选择 保持不变。错误响应只返回无效字段名,不回传密码或其他表单原值。
系统拒绝删除、禁用或降级最后一个管理员。
- 在 WebUI 概览页生成一次性插件配对码;该码在使用前持续有效,成功配对后立即作废。
- 在 ClassIsland 的“RemoteCI 设置”填写云端 HTTPS 地址和该配对码。
- 重启 ClassIsland。
- 在同一设置页确认服务器状态为“已连接”;失败时可查看脱敏后的最近错误,并点击“测试服务器连接”立即执行一次真实 WebSocket 配对、鉴权和初始化。
- 插件用配对码换取长期凭据后会清空本地配对码,随后自动接收账号、权限与设备验证器镜像。
如果服务端在 WebSocket 握手时明确返回 401 或 403,插件会清除被拒绝的长期凭据,并在已保存新配对码时于下一次重试重新配对。404、5xx 等路径或代理错误不会清除凭据,避免临时部署故障导致无谓的重新配对。
普通“RemoteCI 设置”不提供关闭云端中转的开关,避免插件意外停止向 WebUI 同步。“显示开发者设置菜单”默认关闭;开启并重启 ClassIsland 后,“RemoteCI 开发者设置”才会出现。该页保留连接开关和“测试接收语音”,关闭云端后插件只能提供局域网服务,账号权限镜像也无法继续从服务端刷新。
插件每次连接云端后,服务端都会立即请求一次最新七日课表。ClassIsland 的“RemoteCI 设置”可点击“立即推送当前课表”,主动把当前七日课表发送到服务端和在线手表。所有已登录账号都能在 WebUI“七日课表”查看缓存;从插件拉取课表和配置自动拉取仅对系统管理员、当前班级班主任开放。教师账号无需在建号时选择班级,登录后按显示名与课表中的教师姓名匹配任教班级,并可在侧栏“我的日程”查看自己在各班的课次。班主任(原“班管理员”)同样按显示名拥有“我的日程”。插件推送、WebUI 拉取、手表拉取、自动拉取和连接初始化使用同一个课表任务锁;任一任务运行时,各端显示任务来源并拒绝重复请求,任务成功、失败或 15 秒超时后自动释放。插件离线时不会排队,重新连接后会按连接机制再次拉取。
学生不接触插件配对码。原有项目级共享配对码不能用于协议 V3。
- 首次打开手表应用,填写个人账号、密码和云端地址。生产环境推荐 HTTPS;使用 HTTP 时手表会持续提示连接不安全。
- 登录成功后密码被丢弃,30 天设备密钥由 Android Keystore AES-GCM 加密保存。
- 后续可优先局域网直连;失败时自动使用设备会话续登云端。
- 在“连接与消息”中单独开关上课、下课、放学、课表变更和自定义消息。
手表普通“连接”页不再提供云服务器开关,云端地址仍可修改。只有“设置 → 开发者”允许关闭云端中转;即使开发者已关闭该选项,退出账号后的下一次密码登录仍会临时连接云端完成认证,成功后再遵循开发者设置选择后续连接。
Android 手机首次登录可以填写服务器地址、ID 和密码,也可以在登录页扫描 WebUI 概览页生成的“手机扫码登录”二维码,用 5 分钟有效的一次性票据直接登录当前账号。WebUI 经反向代理或内外网地址不同时,系统管理员可在“系统配置 → 手机扫码登录”中指定二维码使用的服务器地址;留空则使用当前访问地址,该设置不改变服务端监听地址。登录后打开“账号与设置 → 连接与服务器”,可以直接修改服务器地址或 ID 并重新连接:只要账号或服务器发生变化,就必须在该页输入密码;密码只用于本次登录,不会保存到设备。服务器和账号未变化时可以直接复用 Android Keystore 中的设备会话重连。切换成功后,当前班级与通知等本地设置会随新账号继续使用;退出账号会清除本机设备会话。
Android 手机还提供当前时间状态、今日课表和 1×2 换课桌面小组件;组件由最近一次有效快照驱动并按尺寸动态显示课程数量,使用标准 AppWidget/RemoteViews 兼容小米澎湃 OS。上学期间手机端会发布一条可更新的“上课状态”持续通知,学生显示当前时间状态、这节课、剩余时间和下一节课(剩余时间由系统计时器倒数到本阶段结束时刻,超级岛右侧同样显示“距下课/上课”倒计时;正文第一行为本时段时间,第二行为“下一节:课程 时间”,上课时图标为日历、课间为勿扰月亮;课间超级岛显示“课间-下一节课名”,进入 ClassIsland 上课提醒设置的准备时长(室内/室外课分别生效,含科目/时间点附加设置)后切换为“即将上课-下一节课名”;上课期间“下一节”为当堂课结束后的第一节课);放学或没有课程时自动撤销。老师账号使用“我的日程”跨班级接口计算当前课与下一节课,不会误用当前选中的班级;老师模式上课中倒计时到下课;下一节课开始前 10 分钟内显示“即将上课”并倒计时到上课(通知出现时提醒一次);今天稍后还有课但未到这 10 分钟时首页显示“空闲”、通知收起,今天没有课了显示“放学”,不会因为下一节在明天或下周而整晚、整个周末显示“即将上课”。通知带有小米 HyperOS 焦点通知/超级岛及息屏(AOD)字段;Android 16+ 还会请求 Live Update promoted ongoing。在支持且已开启对应系统权限的设备上由系统显示;其他 Android 设备继续显示普通持续通知。小米 17 Pro、17 Pro Max、18 Pro、18 Pro Max 的原生 Smart Assistant 背屏卡片仍由 HyperOS 系统服务和设备白名单控制,正式上线还需要按小米平台要求提交场景审核和设备白名单联调。
停服后备份 SQLite 卷最稳妥:
docker compose stop remoteci
docker run --rm -v remoteci-data:/data -v ${PWD}:/backup alpine `
tar czf /backup/remoteci-data-backup.tgz -C /data .
docker compose start remoteci恢复前应先保存现有卷副本,再把备份解压回 /app/data。数据库包含账号哈希、权限、插件凭据和设备会话验证器,应按敏感数据管理。
当前稳定版服务端、插件、手机和手表的软件发布版本统一为 3.3.1.8,通信协议号独立为整数 3。稳定 Release 使用四段纯数字标签;保留的 Beta 使用 v3.x.x-beta.y,仅用于测试且不会进入插件市场。协议号为 3 的组件可以互连,新功能由能力协商决定是否显示和转发。升级前仍应备份 SQLite 卷。插件离线时 WebUI 的换课与通知会立即失败,不会排队补发。
未显式上报能力的旧 V3 端会按 V3 基础能力处理(该基线自 3.1.0 引入)。WebUI 按“服务端 ∩ 当前主插件”隐藏不支持的功能,手表按“手表 ∩ 服务端 ∩ 当前主插件”隐藏;管理员可在概览页查看当前班级插件连接的软件版本、能力来源、有效能力和缺失能力。破坏既有消息或命令语义的升级必须使用 V4,并通过单独的协调升级流程发布。
如果 ClassIsland 插件声明的协议号不是整数 3,WebUI 概览会显示“协议不匹配”,列出插件协议与 WebUI 协议并提示升级插件。该故障在插件断开后仍保留,直到兼容插件真正发送一条 V3 消息才会清除。连接能力诊断中的稳定英文标识后会附带中文说明,例如 schedule.read(读取课表)。
管理员登录后在“系统配置 → 系统更新”中点击“检查更新”,页面会从 GitHub 仓库
Edge-HH/RemoteCI 读取版本和更新说明(按 GitHub Markdown 渲染)。默认“正式版”渠道只检查非预发布 release;
选择“Beta 版”后会同时检查正式版和预发布 release。更新渠道点击“保存更新设置”后保存在数据库中,手动检查、
后台自动检查和 POST /api/admin/updates/check(未指定渠道时)都按此渠道。
“自动检查更新”默认开启,服务端启动约 2 分钟后及之后每 6 小时检查一次,页面显示上次检查时间和结果;
开启“发现新版本后自动下载”后,后台会预先下载当前平台的更新包并校验 SHA-256 与包内版本,
面板显示“已下载并校验”,管理员点击“安装并重启”时直接使用该包,不会自动安装或重启。发现新版本后点击
“下载并更新”,服务端会下载当前平台(linux-x64 / win-x64)的更新包并就地覆盖,
然后自动退出进程。Docker 的 restart: unless-stopped 策略会以新文件重新启动容器;
Windows 与裸机 Linux 会先启动独立更新器,等待旧进程退出和文件锁释放后再替换文件,
随后自动重新启动服务端。
普通用户看不到该面板,且该操作仅对管理员开放。
账号页的“修改密码”与“系统更新”是独立表单;检查或执行更新不会触发空密码字段校验,
只有提交“修改并撤销设备登录”时才会校验当前密码和新密码。
启用“强制更新”后,同一版本也可以重新下载并覆盖安装;该选项不会允许降级。 强制更新状态会随提交传入安装流程,但不会绕过平台包匹配与版本校验。
Visual Studio 或 dotnet run 的 Development 环境由开发工具管理,WebUI 会禁用在线覆盖更新。
正式部署更新时只替换 RemoteCI.Server.dll 所在的实际程序集目录,不使用可能指向源码的
Content Root;源码修改后请直接停止旧进程并重新构建、启动。
下载完成后会核对压缩包内服务端版本是否与 release 标签一致,避免误装名称正确但 内容仍是旧版本的发布包。
飞牛 fnOS 安装包(RemoteCI-<版本>.fpk)部署时,容器通过环境变量
REMOTECI_RUNTIME=fnos 识别运行环境。“系统更新”面板提示由 fnOS 应用中心管理,
不从容器内检查、下载或安装 fpk。GitHub Release 同时提供在线多架构包和 x86_64/ARM64
单架构离线包;升级时下载合适的新版本 FPK,并在应用中心手动安装。
飞牛把 Intel/AMD NAS 标成 x86 时仍应使用 x86_64-offline 包,不要寻找 32 位安装包。
离线包会在应用文件落盘前从包内导入镜像,不依赖尚未创建的应用数据临时目录。
导入阶段的生命周期脚本需要访问 fnOS Docker daemon,因此由应用中心以 root 执行;该权限不改变 RemoteCI 容器内的运行身份与权限。
fpk 工程的构建与发布流程见 fnos/README.md。
插件不做内置更新界面,升级统一交给 ClassIsland 的插件市场管理。稳定版使用同一个纯数字四段 Release,固定包含 RemoteCI.Plugin.cipx,正文包含与该文件名完全一致的 CLASSISLAND_PKG_MD5 校验标记;Beta Release 使用 v3.x.x-beta.y,不会进入插件市场。
仓库根目录的 remoteci.plugin.yml 是已按市场字段准备好的提交文件,内容与
plugin/RemoteCI.Plugin/manifest.yml 保持一致。提交到 ClassIsland/PluginIndex 时将该文件放入
index/plugins-v2/(文件名保持 remoteci.plugin.yml)。描述中的 tagPattern: "3.*.*.*" 选择同一份稳定多端 Release,不需要额外创建市场专用 Release;artifactName 固定为 RemoteCI.Plugin.cipx。
手表端在“设置 → 更新”中选择“正式版”或“Beta 版”渠道:正式版排除预发布,
Beta 版同时包含正式版和预发布。发现可用版本后下载
RemoteCI.Watch-<版本>.apk 并通过系统安装器覆盖安装。更新要求发布包与当前
安装包签名一致:首次安装正式签名版后,后续更新才能在同一签名下自动覆盖。
手表必须先连接 WebUI,正式渠道只选择协议主版本相同的四段纯数字 Release,Beta 渠道额外选择 v3.x.x-beta.y及在 GitHub 标为预发布的四段 Release;旧的 v3.x.x 稳定标签和 V4 Release 不会进入自动更新候选。APK 可以高于所连接 WebUI 的软件版本;启用“强制更新”时
可重新下载并覆盖安装当前版本,但仍不允许降级,也不能绕过 APK 签名校验。
旧版更新器只识别 v3.x.x 稳定标签,因此现有 v3.2.0 安装不会自动发现 3.2.1.2。首次迁移请手动安装 3.2.1.2 的服务端压缩包或 FPK、RemoteCI.Plugin.cipx 和 RemoteCI.Watch-3.2.1.2.apk;手表 APK 必须沿用原正式签名。迁移完成后,后续四段稳定版本可通过更新器正常检查和升级。
“人员权限”页面支持管理员维护学生默认权限和自定义角色。管理员角色固定拥有全部权限;普通账号的有效权限为查看当前课程、角色默认权限与个人附加权限的并集。自定义角色只有在未被账号使用时才可删除。
“系统配置”页面默认每天 02:00 自动备份到数据库目录下的 backups 文件夹并保留 7 份,可调整为每小时、每天或每周执行。页面支持立即备份、下载、恢复和删除本地备份。
“角色配置”中的“老师主动换课”(默认对内置老师和班主任开启)和“强制换课”(默认关闭)控制老师能否发起换课申请、能否不经审批直接强制换课。换课申请一律是临时换课;永久换课仍由班主任在课表页完成。
手动导出的 .rcicfg 配置包使用管理员输入的至少 8 位密码加密。配置包保存密码哈希而非原始密码;导入会先备份当前配置,完整替换课程、账号、角色、插件长期凭据和可修改设置,清除设备会话与临时配对码,然后重启服务。换课申请记录、个人通知、单节临时任课老师和浏览器推送订阅属于运行数据,不进入 .rcicfg;它们随数据库备份一起保存。
角色配置默认仅显示角色名称和编辑按钮;角色权限、删除操作和新角色创建表单都在对话框中完成。
自动备份选择“每小时”时不需要执行时间;选择“每天”时显示执行时间;选择“每周”时同时显示执行时间和每周执行日。
课表页使用统一表格展示:第一列集中显示节次,后续各天的单元格只显示课程名和时间。课程名与时间均保持单行,宽度不足时使用省略号并可通过鼠标悬停查看完整内容。
侧栏“个人”区的“换课”页分为“发起申请”“待我处理”“我的申请”三个页签。发起时选择互换(两节课各选班级、日期、节次)或替换(只选目标课和自己任教的学科),并填写理由。有强制换课权限时,表单右侧会出现红色“强制换课”按钮,点击后先弹窗确认。顶栏铃铛显示未读通知数,点击进入“通知”页;在通知页可以开启或关闭本浏览器的系统通知。
课表页的“立即拉取课表”按钮位于卡片右上角,“提交换课”按钮位于换课表单右下角;小屏幕下两者自动恢复为整行按钮。
控制页的扩展功能以列表显示扩展名和 ID,右侧提供“执行”和“编辑”。管理员可逐项启用扩展、向非管理员开放,并设置是否显示在自己的手表;已获开放且具备扩展调用权限的普通账号只能修改自己的手表展示开关。
人员权限中的“WebUI”已更名为“概览”;发送与清除通知、扩展功能、主界面和电源控制分别授权,音量归入电源控制。
人员管理的现有账号列表会在非管理员账号的“编辑”按钮左侧显示“删除”快捷按钮;管理员账号不显示该入口。