Backend Configuration.zh CN - houyhlouis/LLMOJ GitHub Wiki

后端配置完整参考

English · Wiki 首页

原有字段核对版本 43a88bdd62fbf200889b36932fa921439a293190,本次在 20dec6f 基础上增加注册模式,覆盖 AppConfig 的全部 111 个末级字段、结构对象和开放字典。它解释服务器级 backend.yaml,不把每道题或每场比赛的业务参数当作全站配置。

文件、默认值与生效方式

后端从环境变量 LIBREOJ_CONFIG_FILE 指定的文件读取配置;一键安装通常为 /opt/LLMOJ/config/backend.yaml。ConfigService 只做 YAML 读取、类型转换、字段校验和跨字段关系校验,不与示例文件合并,也没有通用默认值填充。因此下表“示例值”不是“省略即可得到的默认值”;除标明可选或派生的项外,应保留完整配置。

所有项均在进程启动时读取,没有文件热重载。调整后要按运维流程重启后端;preference(除 serverSideOnly)经 auth/getSessionInfo 返回浏览器,后端重启后还需刷新浏览器或重新初始化应用。修改这些运行时偏好一般无需重新构建前端。judge.limit 在评测客户端连接时下发,应确认评测端重新连接后采用新值。不要把后端 server.clusters 当成评测槽数。

配置 schema 没有为所有对象使用 IsDefined,也没有开启配置对象的未知字段白名单剔除。不能把“拼错键没有立即报错”理解为生效;缺失对象也可能到消费者初始化时才失败。不要加入未文档化的字段,尤其不要把秘密放在公开的 preference 中。

依据:字段 schema、关系校验、源码示例、安装配置生成器。

示例值与首次安装值并不相同

安装器仅在配置不存在时创建文件,重跑会保留已有文件。首次安装会替换示例中的数据库、Redis、MinIO、session 和维护密钥;将 MinIO 外部地址改为站点 origin 加 /storage/;设置 metrics.allowedIps: [127.0.0.1];以 --site-name 设置站名;设置 services.mail.address: null、services.mail.transport: {jsonTransport: true} 和 preference.security.requireEmailVerification: false。示例里的 SMTP URL、@example 和 REPLACE_WITH_* 都不是可直接运行的真实凭据。

backend.yaml 含敏感凭据,不要放进 Git 或上传 Wiki;安装器设置为 root 所有、后端服务组可读(0640)。修改数据库/Redis/MinIO 密码须与服务端自身配置协调;改这里不会替其它服务轮换密码。

下表用“必填”表示完整运行配置应有该项;“可选”表示可省略/null,具体消费者回退见说明;可选对象内部的必填项只在该对象启用时要求。数字是 YAML 数字,布尔值用 true/false,不要写成带引号的字符串。

server — 监听与后端进程

结构对象 规则
server 必需结构对象;其子字段见下表。
完整字段 类型 / 是否必填 源码示例值(非默认) 作用、约束和回退
server.hostname string; 必填 127.0.0.1 后端监听 IP;必须是 IP,不是域名。单机安装保持回环地址,公网入口由 Nginx 提供。
server.port number; 必填 2002 后端监听端口,整数 1–65535;修改时同时检查 Nginx upstream 和本机评测 serverUrl。
server.trustProxy 字符串数组; 必填 ["loopback"] 可信反向代理的字符串数组(Express 地址/网段/预定义名称,如 loopback)。影响真实 IP、协议识别及按 IP 限流;只信任实际代理。源码类型注解写 string,但校验和使用需要数组。
server.clusters number; 可选 null 可选非负整数:省略/null 为单进程;0 开启集群且按 os.cpus().length 创建 worker;正整数为 worker 数量。不是评测槽位;增加后端进程会增加内存和监控端口占用。

metrics — 监控

结构对象 规则
metrics 可省略/null 关闭监控监听。
完整字段 类型 / 是否必填 源码示例值(非默认) 作用、约束和回退
metrics.hostname string; 必填(父对象启用时) 127.0.0.1 启用 metrics 时必填的监听 IP;建议回环地址或受保护的监控网络。
metrics.basePort number; 必填(父对象启用时) 2020 整数 1–65535。主进程使用该端口,worker 使用 basePort + worker.id;预留整个端口范围,基准值校验不会替你检查最后一个 worker 的端口。
metrics.allowedIps string[]; 可选 [] 可选 IP 数组。省略/null/[] 均不限制来源;非空时精确匹配 socket.remoteAddress(不是代理头),不接受 CIDR。安装生成 [127.0.0.1]。

services — 数据库、对象存储、Redis 与邮件

结构对象 规则
services 必需结构对象;其子字段见下表。
services.database 必需结构对象;其子字段见下表。
services.minio 必需结构对象;其子字段见下表。
services.minio.default 必需结构对象;其子字段见下表。
services.minio.forUserUpload 可省略/null,使用 default。
services.minio.forUserDownload 可省略/null,使用 default。
services.minio.forJudge 可省略/null,使用 default。
services.mail 必需结构对象;其子字段见下表。
完整字段 类型 / 是否必填 源码示例值(非默认) 作用、约束和回退
services.database.type "mysql" | "mariadb"; 必填 mariadb 数据库驱动,仅 mysql 或 mariadb。
services.database.host string; 必填 127.0.0.1 数据库主机字符串,可为主机名或 IP。
services.database.port number; 必填 13306 数据库端口,整数 1–65535。
services.database.username string; 必填 libreoj 连接数据库的用户,不是 OJ 网站管理员。
services.database.password string; 必填 REPLACE_WITH_DATABASE_PASSWORD 敏感:数据库登录密码;安装器生成随机值,不能使用示例占位符。
services.database.database string; 必填 libreoj 使用的数据库名称;变更不会自动迁移旧库数据。
services.minio.default.endpoint string; 必填 http://127.0.0.1:19000 默认服务端对象存储连接。HTTP(S) origin,只允许根路径 /,不能含用户名密码、query 或 fragment。必需。
services.minio.default.urlEndpoint string; 可选 null 默认服务端对象存储连接生成的 URL 对外替换前缀,可包含 /storage/ 等路径,必须以 / 结尾,不可有 query/fragment。省略/null 不替换。
services.minio.forUserUpload.endpoint string; 必填(父对象启用时) http://127.0.0.1:19000 用户浏览器上传签名连接。HTTP(S) origin,只允许根路径 /,不能含用户名密码、query 或 fragment。省略此整个覆盖对象时使用 default;对象存在则应完整提供 endpoint。
services.minio.forUserUpload.urlEndpoint string; 可选 http://localhost/storage/ 用户浏览器上传签名连接生成的 URL 对外替换前缀,可包含 /storage/ 等路径,必须以 / 结尾,不可有 query/fragment。省略/null 回退 default.urlEndpoint;后者为空则不替换。
services.minio.forUserDownload.endpoint string; 必填(父对象启用时) http://127.0.0.1:19000 用户浏览器下载签名连接。HTTP(S) origin,只允许根路径 /,不能含用户名密码、query 或 fragment。省略此整个覆盖对象时使用 default;对象存在则应完整提供 endpoint。
services.minio.forUserDownload.urlEndpoint string; 可选 http://localhost/storage/ 用户浏览器下载签名连接生成的 URL 对外替换前缀,可包含 /storage/ 等路径,必须以 / 结尾,不可有 query/fragment。省略/null 回退 default.urlEndpoint;后者为空则不替换。
services.minio.forJudge.endpoint string; 必填(父对象启用时) http://127.0.0.1:19000 评测客户端下载签名连接。HTTP(S) origin,只允许根路径 /,不能含用户名密码、query 或 fragment。省略此整个覆盖对象时使用 default;对象存在则应完整提供 endpoint。
services.minio.forJudge.urlEndpoint string; 可选 http://localhost/storage/ 评测客户端下载签名连接生成的 URL 对外替换前缀,可包含 /storage/ 等路径,必须以 / 结尾,不可有 query/fragment。省略/null 回退 default.urlEndpoint;后者为空则不替换。
services.minio.accessKey string; 必填 REPLACE_WITH_MINIO_ACCESS_KEY 敏感凭据:MinIO 访问标识;安装生成 libreoj-local,须与对象存储一致。
services.minio.secretKey string; 必填 REPLACE_WITH_MINIO_SECRET_KEY 敏感:MinIO 密钥,安装器随机生成;仅改这里会导致存储认证失败。
services.minio.bucket string; 必填 libreoj-files 文件所在 bucket 名;对象权限与签名访问仍由应用控制,改名不会搬移旧对象。
services.redis string; 必填 redis://:[email protected]:16379/0 敏感:传给 ioredis 的连接字符串,可包含密码和库编号;安装使用带随机密码的本机 16379/0。
services.mail.address string; 可选 [email protected] 可选有效发件邮箱;需要真正发邮件时配置,并满足 SMTP 服务允许的发件身份。安装值 null。
services.mail.transport URL 字符串/对象; 必填 smtp://username:[email protected]:25 直接传给 Nodemailer createTransport 的 URL 或配置对象;源码没有逐项 schema 校验。含密码/OAuth 凭据时敏感。安装值 {jsonTransport: true} 只构造邮件,不投递。详见下面的开放字典说明。

security — 会话、验证码、PoW 与限流

结构对象 规则
security 必需结构对象;其子字段见下表。
security.captcha 保留对象;两个提供商均 null 时关闭第三方验证码,不关闭 PoW。
security.captcha.turnstile 可选;null 关闭该提供商。
security.captcha.tencentCaptcha 可选;null 关闭该提供商。
security.proofOfWork 必需结构对象;其子字段见下表。
security.crossOrigin 必需结构对象;其子字段见下表。
security.rateLimit 可省略/null 关闭全局按 IP 限流;不关闭其它固定限流。
完整字段 类型 / 是否必填 源码示例值(非默认) 作用、约束和回退
security.sessionSecret string; 必填 REPLACE_WITH_SESSION_SECRET 敏感:签名及验证登录会话 JWT 的字符串;安装随机生成。更换后现有登录令牌失效,需要重新登录。
security.maintainceKey string; 必填 REPLACE_WITH_MAINTENANCE_KEY 敏感:维护接口 POST /api/runMaintainceTasks 的 maintaince-key 请求头密钥。必须保留源码的 maintaince 拼写;不是管理员登录密码。
security.captcha.turnstile.siteKey string; 必填(父对象启用时) 未设置 启用 Turnstile 时必填非空字符串;公开站点标识,将发送给浏览器。
security.captcha.turnstile.secretKey string; 必填(父对象启用时) 未设置 启用 Turnstile 时必填非空字符串;敏感,服务端向 Cloudflare 校验用。
security.captcha.tencentCaptcha.appSecretKey string; 必填(父对象启用时) 未设置 敏感,腾讯验证码应用密钥;1–32 个 ASCII 可见非空白字符(0x21–0x7e)。
security.captcha.tencentCaptcha.appId number; 必填(父对象启用时) 未设置 腾讯验证码应用 ID,整数 ≥1;不是云账号 SecretId。
security.captcha.tencentCaptcha.secretId string; 必填(父对象启用时) 未设置 敏感凭据,腾讯云非空 SecretId 字符串。
security.captcha.tencentCaptcha.secretKey string; 必填(父对象启用时) 未设置 敏感,腾讯云非空 SecretKey 字符串。
security.proofOfWork.difficulty number; 必填 4 普通受保护操作的工作量证明难度,整数 1–8;不是开关,0 不合法。值越大浏览器计算越重。
security.proofOfWork.expensiveActionDifficulty number; 必填 5 提交评测及获取腾讯验证码等昂贵操作的 PoW 难度,整数 1–8;它与第三方验证码、全局限流相互独立。
security.crossOrigin.enabled boolean; 必填 false 是否提供 xdomain 跨域代理页面/脚本;不是通用 Access-Control-Allow-Origin 开关,也不自动为所有 API 开 CORS。
security.crossOrigin.whiteList string[]; 必填 [] xdomain 允许的前端 origin 字符串数组,如 https://oj.example.com;不填未经控制的站点。仅 enabled=true 时使用。
security.rateLimit.maxRequests number; 必填(父对象启用时) 200 每个客户端 IP、每个窗口的请求点数上限。schema 只要求整数,运维应使用正数;超限返回 HTTP 429。rateLimit 整段省略/null 才是关闭该层。
security.rateLimit.durationSeconds number; 必填(父对象启用时) 10 限流窗口秒数。schema 只校验整数,应设置正数。单进程内存计数,Node cluster 通过主进程协调;不跨独立服务器共享。
security.sessionIdleTimeoutDays number; 可选 30 登录会话连续这么多天未使用即失效,需要重新登录。整数 ≥0;0 表示不限制;省略时为 30。服务器在每次请求时检查。
security.sessionMaxAgeDays number; 可选 90 登录会话自登录起这么多天后失效,即使一直在使用。整数 ≥0;0 表示不限制;省略时为 90。

preference — 公开偏好与服务端偏好

结构对象 规则
preference 公开结构,除 serverSideOnly;不要存放秘密。
preference.security 必需结构对象;其子字段见下表。
preference.pagination 必需结构对象;其子字段见下表。
preference.misc 必需结构对象;其子字段见下表。
preference.serverSideOnly 必需结构;不会发送给浏览器。
完整字段 类型 / 是否必填 源码示例值(非默认) 作用、约束和回退
preference.siteName string; 必填 LLMOJ 公开的网站名称,用于页面、动态页脚、邮件和事件通知;安装取 --site-name(默认 LLMOJ)。
preference.copyrightNotice string; 必填 LLMOJ 自定义页脚署名/版权文字,显示在“站点名称 Powered by LLMOJ”下方。空白及精确默认值 LLMOJ、LibreOJ Open Source Project 不另显示重复行;其他文案保留,配置文件及项目许可证不变。
preference.security.captchaEnabled boolean; 派生,不手填 自动派生 公开派生字段:实际输出由 security.captcha 是否配置任一提供商决定;这里手填 true/false 会被覆盖。
preference.security.turnstileSiteKey string; 派生,不手填 自动派生 公开派生字段:由 security.captcha.turnstile.siteKey 复制;不要把 secretKey 填到这里。
preference.security.registrationMode "open" | "approval" | "closed"; 可选 open 网页未保存覆盖时的注册默认方式:开放/待人工审核/关闭;省略或 null 默认 open。管理员在网站管理保存的数据库设置优先,切换不改变已有申请状态,见 注册审核。
preference.security.requireEmailVerification boolean; 必填 true 注册是否验证邮箱验证码。示例 true、安装生成 false;设 true 前先配置并验证邮件投递。false 并不关闭密码重置/改邮箱等邮件需求,也不是关闭注册。
preference.security.allowUserChangeUsername boolean; 必填 true 允许普通用户修改自己的用户名;仍须有 EditOwnProfile。ManageUser 权限可走管理路径。
preference.security.allowEveryoneCreateProblem boolean; 必填 true 已登录用户建题的默认回退;不是允许访客建题,显式 CreateProblem 允许/拒绝规则仍参与判定。
preference.security.allowNonPrivilegedUserEditPublicProblem boolean; 必填 true 允许原本有权的题主或 Write ACL 用户编辑公开题;不是让任意用户编辑所有公开题,仍受全局编辑权限限制。
preference.security.allowOwnerManageProblemPermission boolean; 必填 false 题主能否管理自身题目 ACL 的回退;公开题同时受 allowNonPrivilegedUserEditPublicProblem 约束。不是授予站点 /permissions 管理。
preference.security.allowOwnerDeleteProblem boolean; 必填 true 题主删除自身题目的回退;公开题受上述公开编辑开关约束,另受显式删除权限限制。
preference.security.discussionDefaultPublic boolean; 必填 true 新建讨论默认公开标志;不追溯修改旧讨论,也不越过题目/讨论访问控制。
preference.security.discussionReplyDefaultPublic boolean; 必填 true 新回复默认公开标志;不修改既有回复。
preference.security.allowEveryoneCreateDiscussion boolean; 必填 true 已登录用户建讨论的默认回退;仍受 CreateDiscussion 显式权限和关联对象权限约束。
preference.pagination.homepageUserList number; 必填 10 公开的首页用户榜人数,整数 ≥1;没有额外的跨配置关系校验。
preference.pagination.homepageProblemList number; 必填 10 公开的首页题目数,整数 ≥1;没有额外的跨配置关系校验。
preference.pagination.problemSet number; 必填 50 公开的题库每页数量,整数 ≥1;不得超过 queryLimit.problemSet。
preference.pagination.searchProblemsPreview number; 必填 7 公开的题目搜索预览数量,整数 ≥1;不得超过 queryLimit.problemSet。
preference.pagination.submissions number; 必填 10 公开的提交列表每页数量,整数 ≥1;不得超过 queryLimit.submissions。
preference.pagination.submissionStatistics number; 必填 10 公开的提交统计每页数量,整数 ≥1;不得超过 queryLimit.submissionStatistics。
preference.pagination.userList number; 必填 30 公开的用户列表每页数量,整数 ≥1;不得超过 queryLimit.userList。
preference.pagination.userAuditLogs number; 必填 10 公开的用户审计日志每页数量,整数 ≥1;不得超过 queryLimit.userAuditLogs。
preference.pagination.discussions number; 必填 10 公开的讨论列表每页数量,整数 ≥1;不得超过 queryLimit.discussions。
preference.pagination.searchDiscussionsPreview number; 必填 7 公开的讨论搜索预览数量,整数 ≥1;不得超过 queryLimit.discussions。
preference.pagination.discussionReplies number; 必填 40 公开的讨论回复页完整数量,整数 ≥1;不得超过 queryLimit.discussionReplies。
preference.pagination.discussionRepliesHead number; 必填 20 公开的折叠时先展示的回复数,整数 ≥1;必须小于 preference.pagination.discussionReplies。
preference.pagination.discussionRepliesMore number; 必填 20 公开的继续展开时请求的回复数,整数 ≥1;不得超过 queryLimit.discussionReplies。
preference.misc.appLogo string; 必填 '' Logo URL/路径字符串;空字符串使用前端默认表现。前端 window.appLogo 可覆盖,主题字典还可指定其它图片。
preference.misc.appLogoForTheme Record<string, string>; 必填 {"pure":"original","far":"inverted"} 主题名到字符串的开放字典,如 pure: original、far: inverted。值 original 使用普通 Logo,inverted 对该 Logo 反色,其它字符串作为图片路径;default 表示默认 Logo。未知主题回退 original。
preference.misc.googleAnalyticsId string; 可选 null 可选 Google Analytics 标识;null/空值不加载。公开配置,启用后浏览器会请求相应统计服务。
preference.misc.plausibleApiEndpoint string; 可选 null 可选 Plausible API URL,须通过 URL 校验;null 关闭其加载。
preference.misc.gravatarCdn string; 必填 https://gravatar.com 头像服务基础 URL 字符串,前端在后面拼 avatar/;window.gravatarCdn 可覆盖。
preference.misc.redirectLegacyUrls boolean; 必填 false 是否启用前端已定义的旧路径重定向;不自动导入老站数据或创建任意重定向规则。
preference.misc.legacyContestsEntryUrl 字符串/null; 可选 null 兼容保留字段,可选字符串/null。schema 的 TypeScript 注解误写 boolean,但运行时用 IsString 校验;本版本没有找到该值的页面消费者,不应承诺会显示旧比赛入口。
preference.misc.homepageUserListOnMainView boolean; 必填 true 控制首页用户列表是否放在主内容区。
preference.misc.sortUserByRating boolean; 必填 false 用户列表默认按 rating 排序的显示偏好;不计算或更新 rating。
preference.misc.renderMarkdownInUserBio boolean; 必填 false 是否将用户简介按 Markdown 渲染;不是对简介开放任意 HTML。
preference.misc.discussionReactionEmojis string[]; 必填 ["👍","👎","😄","😕","❤️","🤔","🤣","🌿","🍋","🕊️"] 默认反应表情的非空、无重复数组,每项为单个有效 emoji,UTF-8 长度不超过 28 字节。
preference.misc.discussionReactionAllowCustomEmojis boolean; 必填 true 是否允许用户选择默认列表外的 emoji;仍需通过 emoji 校验及服务端黑名单。
preference.serverSideOnly.discussionReactionCustomEmojisBlacklist string | unknown[]; 必填 /(\uD83C[\uDDE6-\uDDFF]){2}/ 仅服务端:单个 emoji、/正则表达式/ 字符串,或它们的一层数组;空数组表示无黑名单。示例屏蔽旗帜。schema 递归接受嵌套数组,但消费者只 flat 一层,因此配置使用扁平数组;正则没有 flags 语法,必须本身有效。
preference.serverSideOnly.dynamicTaskPriority boolean; 必填 true 仅服务端:按题目、用户及评测状态动态计算队列优先级;false 返回统一优先级。不是并发数或限流开关。

resourceLimit — 题目与文件资源上限

结构对象 规则
resourceLimit 必需结构对象;其子字段见下表。
完整字段 类型 / 是否必填 源码示例值(非默认) 作用、约束和回退
resourceLimit.problemTestdataFiles number; 必填 2005 每题测试数据文件数量上限,整数 ≥0。
resourceLimit.problemTestdataSize number; 必填 8589934592 每题测试数据总字节数上限,整数 ≥0;示例 8 GiB。
resourceLimit.problemAdditionalFileFiles number; 必填 40 每题附加文件数量上限,整数 ≥0。
resourceLimit.problemAdditionalFileSize number; 必填 134217728 每题附加文件总字节数上限,整数 ≥0;示例 128 MiB。
resourceLimit.problemSamplesToRun number; 必填 10 提交时最多运行的样例组数,整数 ≥0;0 不运行该样例阶段。
resourceLimit.problemTestcases number; 必填 1000 题目评测配置的测试点数量上限,整数 ≥1。
resourceLimit.problemTimeLimit number; 必填 2000 题目允许设置的时间上限(毫秒),整数 ≥1;不是后端 HTTP 超时。
resourceLimit.problemMemoryLimit number; 必填 512 题目允许设置的内存上限(MiB),整数 ≥1;不是后端 Node 堆内存。
resourceLimit.submissionFileSize number; 必填 10485760 提交文件的字节数上限,整数 ≥0;示例 10 MiB。反向代理、具体题型和 AI 上传限制可能更小。

queryLimit — 查询上限

结构对象 规则
queryLimit 必需结构对象;其子字段见下表。
完整字段 类型 / 是否必填 源码示例值(非默认) 作用、约束和回退
queryLimit.problemSet number; 必填 100 题库查询单次结果数量上限,整数 ≥1。它是服务端请求上限,不是默认页面大小;同步检查对应 pagination 关系。
queryLimit.submissions number; 必填 10 提交列表查询单次结果数量上限,整数 ≥1。它是服务端请求上限,不是默认页面大小;同步检查对应 pagination 关系。
queryLimit.submissionStatistics number; 必填 10 提交统计查询单次结果数量上限,整数 ≥1。它是服务端请求上限,不是默认页面大小;同步检查对应 pagination 关系。
queryLimit.searchUser number; 必填 10 用户搜索单次结果数量上限,整数 ≥1。它是服务端请求上限,不是默认页面大小;同步检查对应 pagination 关系。
queryLimit.searchGroup number; 必填 10 用户组搜索单次结果数量上限,整数 ≥1。它是服务端请求上限,不是默认页面大小;同步检查对应 pagination 关系。
queryLimit.userList number; 必填 100 用户列表单次结果数量上限,整数 ≥1。它是服务端请求上限,不是默认页面大小;同步检查对应 pagination 关系。
queryLimit.userAuditLogs number; 必填 20 用户审计日志单次结果数量上限,整数 ≥1。它是服务端请求上限,不是默认页面大小;同步检查对应 pagination 关系。
queryLimit.discussions number; 必填 20 讨论列表及搜索单次结果数量上限,整数 ≥1。它是服务端请求上限,不是默认页面大小;同步检查对应 pagination 关系。
queryLimit.discussionReplies number; 必填 50 讨论回复查询单次结果数量上限,整数 ≥1。它是服务端请求上限,不是默认页面大小;同步检查对应 pagination 关系。

judge — 下发给评测端的限制

结构对象 规则
judge 必需结构对象;其子字段见下表。
judge.limit 必需结构对象;其子字段见下表。
完整字段 类型 / 是否必填 源码示例值(非默认) 作用、约束和回退
judge.limit.compilerMessage number; 必填 524288 编译输出保留上限,正整数字节数;示例 512 KiB。
judge.limit.outputSize number; 必填 104857600 选手输出大小上限,正整数字节数;示例 100 MiB。评测端 binaryCacheMaxSize 不可小于此值。
judge.limit.dataDisplay number; 必填 128 普通题评测结果展示的输入/输出片段上限,正整数字节数。
judge.limit.dataDisplayForSubmitAnswer number; 必填 128 提交答案题中选手答案文件的展示片段上限,正整数字节数;测试输入和标准答案预览仍用 dataDisplay。
judge.limit.stderrDisplay number; 必填 5120 选手标准错误输出的展示上限,正整数字节数;示例 5 KiB。

eventReport — 事件通知

结构对象 规则
eventReport 保留对象;token 为 null 时关闭上报。
完整字段 类型 / 是否必填 源码示例值(非默认) 作用、约束和回退
eventReport.telegramBotToken string; 可选 null 可选敏感 Telegram Bot token;省略/null/空字符串关闭事件上报。启用会联网向 Telegram 报告事件,集群仅主进程持有机器人。
eventReport.telegramApiRoot string; 可选 null 可选 API 根 URL;省略/null 使用 Telegraf 的默认 Telegram API。
eventReport.sentTo string | number; 可选 @example 目标 chat ID(字符串或数字)或允许机器人发消息的频道,如 @example;token 启用后需设置真实目标。
eventReport.proxyUrl string; 可选 null 可选 ProxyAgent 代理地址字符串;含认证信息时敏感。只影响 Telegram,不是 AI 提供商的全局代理。

vendor — IP 地理位置库

结构对象 规则
vendor 保留对象,即使 ip2region 为 null。
vendor.ip2region 可选;null 使用库默认行为。
完整字段 类型 / 是否必填 源码示例值(非默认) 作用、约束和回退
vendor.ip2region.ipv4db string; 必填(父对象启用时) 未设置 启用自定义 ip2region 时提供的 IPv4 数据库文件路径字符串;服务用户须能读取。整段省略/null 时向库传 {} 使用其内置行为。
vendor.ip2region.ipv6db string; 必填(父对象启用时) 未设置 启用自定义 ip2region 时提供的 IPv6 数据库文件路径字符串;服务用户须能读取。整段省略/null 时向库传 {} 使用其内置行为。

开放字典与数组通配项

路径 值与实际支持
services.mail.transport.* Nodemailer 透传字典,不是由 LLMOJ 固定枚举的配置项;可用 URL 或对象。常用 SMTP 项是 host、port、secure、auth.user、auth.pass;auth.* 可包含认证方式特定值,tls.* 是 TLS 选项,pool 控制连接池,jsonTransport 为不投递的 JSON transport。填写库当前支持的有效选项,LLMOJ 不会合并这些子项或替你验证账号可用性。auth.*、带密码的 URL 均敏感。
preference.misc.appLogoForTheme.* * 为前端主题名,每个值必须是字符串;可设置任意主题键,但只有实际选择的主题会被读取。不是嵌套对象。
server.trustProxy[] 每项为代理地址、网段或 Express 预定义名称字符串,不要传单字符串替代数组。
metrics.allowedIps[] 每项必须是 IP;空数组允许全部连接来源,非空时精确匹配。
security.crossOrigin.whiteList[] 每项为允许 xdomain 代理的 origin 字符串。
preference.misc.discussionReactionEmojis[] 每项为有效单个 emoji,列表不得空或重复。
preference.serverSideOnly.discussionReactionCustomEmojisBlacklist[] 使用扁平数组中的 emoji 或 /pattern/,不要依赖 schema 对深层嵌套的宽松接受。

services.mail.transport.auth.* 与 services.mail.transport.tls.* 属于上述传输字典,并非额外的 LLMOJ secret store;所有 transport 内容留在服务端配置。配置邮件后先自行验证投递、发件人及域名策略,再开启注册邮箱验证。安装的 JSON transport 不会把验证码真正发到邮箱。

注册、权限与限流的组合

站点管理员可在“网站管理”(/site-management)修改注册方式,保存或恢复服务器配置立即生效,无需重启。此设置独立保存在数据库,不修改 YAML;恢复后使用后端当前已加载的 YAML 默认值。只有直接修改 YAML 才需重启后端加载新值,且尚未清除的网页覆盖仍优先。审核权限或首页编辑权限不能更改网站注册设置。

本站 schema 没有 registrationEnabled、邮件域名白名单、任意 permissions.* 或每接口限流字典,不能通过添加自创 YAML 键实现这些功能。requireEmailVerification 只控制注册验证码验证;用户名规则等仍由业务校验控制。

用户级允许/拒绝、管理员权限和题目/讨论/组 ACL 存在数据库中,不是本文件的子树。allowEveryone* 提供默认回退,不等于越过显式拒绝;ManagePermissions 仍只允许站点管理员;ManageRegistrationReviews 默认关闭,可由管理员逐用户授权审核注册申请,不会授予权限管理能力,见 注册审核。AI 的 ManageAiConfiguration、UseAi、GenerateTestdata、ImportProblem 及每账号提供商密钥也不在本 schema;参考 AI 配置。业务权限变化通常按请求从数据库读取,无需为此改 YAML 或重启。依据:权限判定、题目授权。

security.rateLimit 在 HTTP 层按 req.ip 计数,必须配合准确的 server.trustProxy;代理配置错误会使多个用户共用一个 IP 配额。PoW 和第三方验证码是另外两层保护:将验证码提供商置 null 不会关闭 PoW。当前 PoW 挑战有效期 5 分钟,发放限制为每 IP/已登录用户 10 秒内 20 次,这些是代码常量,不是此 YAML 的字段。不要把调整全局 maxRequests 误认为能改变它们。参见 HTTP 限流、PoW 实现。

修改时核对

  1. 从正在使用的完整 backend.yaml 备份后调整,保留身份和存储凭据;不要用示例覆盖现有文件。
  2. 同步检查 pagination 与 queryLimit 的大小关系,以及端口、外部对象存储 URL、邮件和验证码的相关项。
  3. 按运维流程安排后端重启;监听端口/代理/凭据变更需协调对应服务。公开偏好修改后刷新浏览器;评测限制修改后确认评测客户端重新连接。
  4. 实际验证登录、需要改变的功能和日志;不要把配置通过类型校验等同于 SMTP、Telegram、数据库或对象存储已经连通。

资源限制中的 0 只在声明允许 ≥0 的字段合法,不普遍表示无限;具有忽略限制权限的管理路径可能绕过部分题目限制。AI 导入图片、ZIP、模型响应和本地生成器还有各自的独立限制,调大 resourceLimit 不会自动改那些上限。评测扩容应按 分布式评测 中对应运维入口核对,不靠 server.clusters 完成。