Cleep 0.4.4 配置参数详解
Cleep 0.4.4 全量配置参数详解:必填环境变量与启动时序、数据库连接、会话 Cookie、四组限流参数(附 429 实测)、反向代理与 HTTPS 联动、附件存储、注册开关与管理员引导、安全响应头与生产配置模板。
Cleep 0.4.4 配置参数详解
目标:Cleep 的全部运行时行为都由「启动期环境变量 + 一项运行期开关」控制,官方
.env.example只写了用途、没写坑。本篇基于官方仓库源码(server/app.ts、server/middleware/*、server/db/bootstrapAdmin.ts,2026-10-25 实查 v0.4.4)与真实部署环境逐项实测,讲清每个配置参数的作用、默认值、生效时机与相互联动,重点还原三处最容易踩的坑:/api/auth整路由限流计数、COOKIE_SECURE与 HTTPS 的联动关系、TRUST_PROXY开关对限流准确性的影响。部署过程见《Cleep 0.4.4 Docker Compose 部署指南》,定位与选型见《Cleep 0.4.4 介绍与选型指南》。
一、环境信息
本篇配置实测与取证环境如下,读者操作时请替换为自己的取值:
- 操作系统:Ubuntu 24.04 LTS,x86_64
- Cleep 版本:0.4.4(官方 GHCR
latest标签,digestsha256:60da6a78…,与源码 tagv0.4.4一致) - 数据库:PostgreSQL 16.15(
postgres:16-alpine) - 部署目录:
/opt/cleep/(compose 编排文件与.env所在),数据目录/opt/cleep/data/postgres/与/opt/cleep/data/attachments/ - 服务端口:应用服务在 6169 端口监听,对外发布 8140(
8140:6169) - 演示管理员账号:
admin@quzuo.net/q1w2e3r4(.env的ADMIN_EMAIL/ADMIN_PASSWORD首次启动引导创建)
取证方式说明:配置项的「官方定义」逐条对照仓库内 .env.example 与服务端 TypeScript 源码(本地已克隆 blindpassasjer/cleep 仓库 v0.4.4);「实际行为」全部通过 curl 在 8140 端口实测取证,回显原文见文中代码块,证据文件留存于本地 tmp/cleep/ev_c1_*.txt。
二、配置体系总览
Cleep 没有配置文件,全部配置走两条通道,生效时机完全不同:
| 通道 | 载体 | 生效时机 | 覆盖内容 |
|---|---|---|---|
| 启动期配置 | 环境变量(compose 项目目录 .env) | 服务进程启动时读取一次,改完必须重新应用编排才生效 | 数据库、会话、限流、代理、附件目录、管理员引导 |
| 运行期配置 | 数据库 app_settings 表 | 管理员在后台修改,立即生效、无需重启 | 目前仅一项:registrationOpen(注册开关) |
启动时序(源码 server/index.ts → server/app.ts)按固定顺序执行:
- fail-fast 校验必填变量(
assertRequiredEnv()):DATABASE_URL、SESSION_SECRET、ATTACHMENTS_DIR三项缺任何一个直接抛错退出,错误信息即变量名本身,例如DATABASE_URL environment variable is required.;ADMIN_EMAIL与ADMIN_PASSWORD校验成对出现(见第八章)。 - 数据库迁移:对
DATABASE_URL指向的库自动执行 schema 迁移,无需手工建表。 - 管理员引导(
bootstrapAdmin(),幂等,见第八章)。 - 监听端口:
Number(process.env.PORT) || 6169,未设置PORT时默认 6169。
💡 「改了
.env不生效」是最高频的误用:环境变量在进程启动时读取一次,修改后必须docker compose up -d重新应用编排让服务进程重建;而注册开关这类运行期配置改了立即生效,不要为它重启服务。
环境变量总表
以下为 v0.4.4 全部环境变量(来源:仓库 .env.example + 源码 process.env 引用点逐条核对,2026-10-25):
| 变量 | 必填 | 默认值 | 作用 | 详解章节 |
|---|---|---|---|---|
DATABASE_URL | ✅ 必填 | 无(缺失启动即退出) | 应用服务连接 PostgreSQL 的连接串 | 第三章 |
SESSION_SECRET | ✅ 必填 | 无(缺失启动即退出) | 会话 Cookie 签名密钥 | 第四章 |
ATTACHMENTS_DIR | ✅ 必填 | 无(缺失启动即退出;Compose 模板已固定注入 /data/attachments) | 附件落盘根目录 | 第七章 |
ADMIN_EMAIL / ADMIN_PASSWORD | 可选 | 不设则跳过引导 | 首次启动创建首个管理员账号,两者必须同时设或同时不设 | 第八章 |
PORT | 可选 | 6169 | 应用服务监听端口 | 第四章 |
NODE_ENV | 可选 | Compose 模板固定 production | 运行模式 | — |
PUID / PGID | 可选 | 999 | 数据库服务进程运行 uid/gid,须与 ./data/postgres 属主一致 | 第三章 |
POSTGRES_PASSWORD | Compose 必填 | 无(compose 用 :? 语法强制) | 数据库服务初始化密码,须与 DATABASE_URL 中密码一致 | 第三章 |
COOKIE_SECURE | 可选 | false | 会话 Cookie 是否加 Secure 属性,同时控制是否下发 HSTS | 第六章 |
TRUST_PROXY | 可选 | false | 是否信任上一跳的 X-Forwarded-For(影响限流按 IP 计数) | 第五、六章 |
AUTH_RATE_LIMIT_MAX / AUTH_RATE_LIMIT_WINDOW_MS | 可选 | 20 / 60000 | /api/auth/* 限流:窗口内最大请求数 / 窗口时长(毫秒) | 第五章 |
UPLOAD_RATE_LIMIT_MAX / UPLOAD_RATE_LIMIT_WINDOW_MS | 可选 | 60 / 60000 | 附件上传与数据导入导出限流 | 第五章 |
NOTE_LOCK_RATE_LIMIT_MAX / NOTE_LOCK_RATE_LIMIT_WINDOW_MS | 可选 | 20 / 60000 | 笔记密码锁定/解锁限流(源码支持,.env.example 未列出) | 第五章 |
LINK_PREVIEW_RATE_LIMIT_MAX / LINK_PREVIEW_RATE_LIMIT_WINDOW_MS | 可选 | 300 / 60000 | 链接预览元数据/图片代理限流(源码支持,.env.example 未列出) | 第五章 |
⚠️ 注意两个「文档与源码不一致」的点:
NOTE_LOCK_*与LINK_PREVIEW_*两组限流变量在源码(server/middleware/rateLimit.ts)中真实生效,但官方.env.example没有列出——按默认值使用无需关心,需要调整时直接写进.env即可(Compose 模板未透传这两个变量时,需自行在编排文件environment:段补一行透传)。
三、数据库连接
Cleep 把「应用服务连什么库」与「数据库服务本身怎么初始化」拆成两组变量,两者必须人工保持一致:
# .env(Compose 部署的标准写法)
POSTGRES_PASSWORD=cleepdb2026
DATABASE_URL=postgres://cleep:cleepdb2026@postgres:5432/cleep
DATABASE_URL标准连接串格式postgres://用户:密码@主机:端口/库名。Compose 部署下主机名固定写服务名postgres(编排内部 DNS 解析),库名与用户名由编排模板固定为cleep。密码必须与POSTGRES_PASSWORD完全一致,否则应用服务连库失败、接口全部 500。POSTGRES_PASSWORD仅数据库服务使用(首次初始化时创建cleep用户与cleep库)。Compose 模板用${POSTGRES_PASSWORD:?Set POSTGRES_PASSWORD in .env}语法强制要求设置,漏填时编排直接报错拒绝启动,不静默回退。PUID/PGID(默认 999):数据库服务进程的运行身份,须与宿主机./data/postgres数据目录属主一致。首次启动前chown -R 999:999 data/postgres(999 是 PostgreSQL 官方运行用户的固定 uid);改了 PUID/PGID 就同步改目录属主,否则数据库首次初始化因无写权限失败。- 首次启动自动建表:应用服务启动即对目标库执行迁移,v0.4.4 库内共 8 张表(users、sessions、notes、labels、note_labels、attachments、link_previews、app_settings),全程无需手工执行任何 SQL。
💡 换密码的正确姿势:
POSTGRES_PASSWORD只在数据目录首次初始化时生效,对已初始化的库改.env里的它不会改变实际密码。正确做法是进数据库执行ALTER USER cleep PASSWORD '...',再同步改DATABASE_URL,最后重新应用编排。
四、会话与 Cookie
SESSION_SECRET
会话签发采用「随机 token + 服务端存储 + Cookie 签名」三件套,SESSION_SECRET 是 Cookie 签名的 HMAC 密钥:
# 官方推荐的生成方式(64 位十六进制随机串)
openssl rand -hex 32
实测生成回显(每次不同,请使用自己生成的值):
784e82cbbf04d24479a87fb9263bd51b836e8db2f09ddde4701dd0eeebfdd001
- 必填项,缺失时启动即退出(
SESSION_SECRET environment variable is required.)。 - 更换密钥的代价:所有已签发 Cookie 的签名校验失败,全体用户被登出(服务端 session 行仍在,但浏览器带的旧 Cookie 过不了签名验证),重新登录即可,无数据损失。
- 泄露即等于「可伪造任意用户登录态」,按生产密钥管理,不要提交进版本库(官方
.env.example明确写明.env已被 gitignore)。
Cookie 属性实测
登录成功后服务端下发的 Set-Cookie 原文(2026-10-25 实测抓取):
Set-Cookie: session=s%3Ad266250270c5473f9baa972788077a5fd09c83023b684fc3ad3aaf5e4a075477.GTwyzvT0UCWMdyMUnpa0NRl4P0eNLZWX46VjlqM7774; Path=/; Expires=Tue, 24 Nov 2026 05:31:57 GMT; HttpOnly; SameSite=Strict
逐属性解读:
| 属性 | 实测值 | 含义与联动 |
|---|---|---|
| 名称 | session | 固定,不可配置 |
| 值 | s%3A<64位hex>.<签名> | URL 编码的 s:<token>.<HMAC签名>——token 为 64 位十六进制(服务端 sessions 表主键),s: 前缀与点后签名是 cookie-parser 的签名格式,密钥即 SESSION_SECRET |
HttpOnly | ✅ | JavaScript 不可读,防 XSS 偷 Cookie |
SameSite | Strict | 最严格档:跨站请求一律不带 Cookie,天然免疫 CSRF |
Secure | 实测未出现(COOKIE_SECURE=false) | 设 COOKIE_SECURE=true 后追加,仅 HTTPS 连接发送——纯 HTTP 访问下开了它会导致浏览器静默丢弃 Cookie,「登录成功但刷新即 401」(第六章) |
Expires | 登录时刻 + 30 天 | 服务端会话 TTL 同为 30 天(源码 SESSION_TTL_MS = 30 天);30 天后无论 Cookie 是否还在,服务端 sessions 表记录过期,强制重新登录 |
- 「保持登录」差异:登录时若勾选保持登录,Cookie 带
Expires(关浏览器后仍有效,上限 30 天);不勾则是会话 Cookie(无Expires,关浏览器即失效,但服务端记录仍在)。 - 服务端存储:token 存
sessions表(token、userId、expiresAt),每个请求查库鉴权——所以管理员重置某用户密码时会删除该用户全部 session 行,强制其所有已登录设备下线重新认证(实测行为,源码POST /api/admin/users/:id/password)。 - 退出登录:
POST /api/auth/logout删除服务端 session 行并清 Cookie。
未登录态的行为
未登录访问身份接口不是 401 而是 200(2026-10-25 实测):
$ curl -s http://localhost:8140/api/auth/me
{"user":null} # HTTP 200
前端据此区分「未登录/已登录」渲染界面;真正需要登录的接口(笔记、管理等)才返回 401 {"error":"Authentication required."}。做探活监控时不要拿 /api/auth/me 的 200 当「服务可用且已登录」。
五、限流参数:四组独立计数器
机制
源码 server/middleware/rateLimit.ts,实现是单进程内存里的固定窗口计数器:
- 按
req.ip(客户端 IP)分桶计数,窗口内达到上限返回429 {"error":"Too many requests. Please try again shortly."}(无Retry-After头,错误体固定这一句)。 - 窗口到期由惰性清扫删除,不重启也能自然恢复。
- 内存态,不落库:服务重启计数清零;未来若多实例部署,各实例独立计数(v0.4.4 未提供共享存储,官方注释明示单实例自托管定位)。
- 数值可通过环境变量调整,窗口与上限是分开的两个变量;读取时校验「正整数」,非法值静默回退默认。
四组参数与覆盖范围
| 组 | 默认(次/窗口) | 窗口 | 覆盖的接口 | 说明 |
|---|---|---|---|---|
AUTH_RATE_LIMIT_* | 20 次 / 60000ms | 1 分钟 | 整个 /api/auth 前缀:注册开关查询、注册、登录、登出、身份查询(me)、改密码 | 源码写法是 app.use('/api/auth', authRateLimit, …)——挂在路由前缀上,该前缀下所有请求都计数 |
UPLOAD_RATE_LIMIT_* | 60 次 / 60000ms | 1 分钟 | 附件上传(POST)、数据导出(GET /api/export)、Keep zip 导入 | 按接口逐个挂载 |
NOTE_LOCK_RATE_LIMIT_* | 20 次 / 60000ms | 1 分钟 | 笔记加锁/解锁/解锁附件/移除锁四个接口 | 密码试错面,与登录同级防护;.env.example 未列出 |
LINK_PREVIEW_RATE_LIMIT_* | 300 次 / 60000ms | 1 分钟 | 链接预览元数据 + 图片代理 | 上限最高:一条带多条链接的笔记展开即产生成倍的预览请求;.env.example 未列出 |
实测:20 次上限如何被打满
在默认配置(AUTH_RATE_LIMIT_MAX=20)下,同一来源 IP 先后触发了 4 次 /api/auth 请求(打开页面时的 registration-status、me,加上两次登录态查询),随后脚本连续 POST 错误密码登录(ev_c1_ratelimit.txt 原文摘录):
try1 HTTP 200 {"user":null,"error":"Invalid email or password."}
try2 HTTP 200 {"user":null,"error":"Invalid email or password."}
…(try3 ~ try15 同样输出,略)
try16 HTTP 200 {"user":null,"error":"Invalid email or password."}
try17 HTTP 429 {"error":"Too many requests. Please try again shortly."}
try18 HTTP 429 {"error":"Too many requests. Please try again shortly."}
…(try19 ~ try21 同样输出,略)
数字对得上:窗口内先有 4 次,try1~try16 又 16 次,合计 20 次封顶;第 21 次起全部 429,直到 60 秒窗口滚动过期。错误密码尝试在 20 次以内始终返回 HTTP 200 + {"user":null,"error":"Invalid email or password."}——Cleep 不用 401 区分「密码错」与「未认证」,接口语义上前端自行处理。
三个必须知道的坑
/api/auth整前缀计数:打开一次 Cleep 页面,前端就会发registration-status+me两次请求,全部计入 20 次的桶。多人共用出口 IP 的办公室/校园网环境,1 分钟内 20 次「打开页面 + 登录」的组合很容易触发。对策:调大AUTH_RATE_LIMIT_MAX,或缩短前端轮询类调用(无配置项,只能调上限)。- 反代场景下全站共享一个桶:
TRUST_PROXY=false(默认)时req.ip恒为直连对端——若前面有反向代理,所有访客的请求在应用服务看来都来自代理地址,全站共用同一个 20 次的桶,表现为「没人暴力破解却频繁 429」。开了反代必须同时把TRUST_PROXY设为true(第六章)。 - 429 无
Retry-After:客户端拿不到确切等待时长,按窗口时长(默认 60 秒)退避即可;服务重启计数立即清零,急用时可直接重建服务恢复(仅建议自托管测试环境这么干)。
六、反向代理与 HTTPS
两个开关 + 一个响应头,三者联动,官方 .env.example 对每个都写了警示注释,这里按场景给出组合结论:
| 场景 | COOKIE_SECURE | TRUST_PROXY | 结果 |
|---|---|---|---|
纯 HTTP 直连(如 http://<nas-ip>:8140) | false(默认) | false(默认) | 正常可用;无 HSTS;限流按真实来源 IP 计数 |
| 反向代理终止 HTTPS,内部仍 HTTP | true | true | Cookie 加 Secure 仅经 HTTPS 传输;下发 HSTS;限流按 X-Forwarded-For 还原的真实客户端 IP 计数 |
反代但忘开 TRUST_PROXY | true | false ❌ | 能用,但全站共享一个限流桶(第五章坑 2),恶意方还可伪造 X-Forwarded-For 绕过登录限流 |
纯 HTTP 直连但误开 COOKIE_SECURE | true ❌ | — | 浏览器静默丢弃 Cookie:登录接口返回成功,之后所有请求 401,表现为「无限登录循环」 |
TRUST_PROXY=true的确切语义(源码app.set('trust proxy', 1)):只信任直接上游一跳的X-Forwarded-For。多层代理链要在代理层收敛该头,或按 Express 文档改为自实现解析——Cleep 未暴露更细的配置项。COOKIE_SECURE=true的附加效果——HSTS(源码server/middleware/securityHeaders.ts):此时所有响应追加Strict-Transport-Security: max-age=15552000; includeSubDomains(180 天,含子域)。官方注释解释了为什么默认不发:纯 HTTP 源站下发 HSTS 会把浏览器钉死在https://上,而该源站根本没有证书,用户直接被锁在门外。所以 HSTS 与SecureCookie 绑定同一个开关,切 HTTPS 时一次到位。
七、附件存储
ATTACHMENTS_DIR:附件落盘根目录,必填项。Compose 模板已硬编码注入ATTACHMENTS_DIR=/data/attachments并挂载宿主机./data/attachments,Compose 用户无需也不应该在.env里再设它——该变量只对手工(非 Compose)部署有意义。- 落盘布局为普通目录树:
<ATTACHMENTS_DIR>/<用户ID>/<笔记ID>/<文件名>,实测当前环境为空目录(16KB 起步),笔记删除、用户注销时服务端会同步清理对应文件(源码deleteAttachmentFilesForNotes)。 - 备份即目录备份:与数据库导出(
pg_dump)分开,仓库自带scripts/backup.sh已把两者打包(部署篇已初验)。迁移服务器时「库 + 附件目录」成对搬运即可。 - 上传受
UPLOAD_RATE_LIMIT_MAX限流(默认 60 次/分钟),与下载无关——下载接口不在限流范围。
八、注册开关与管理员引导
ADMIN_EMAIL / ADMIN_PASSWORD:首启引导,成对出现
- 成对校验:
assertRequiredEnv()强制两者同时设置或同时不设,只设一个启动即退出(ADMIN_EMAIL and ADMIN_PASSWORD must both be set, or both left unset.)。 - 幂等且不提权(源码
bootstrapAdmin.ts逻辑,2026-10-25 通读确认):- 目标邮箱账号不存在 → 创建,角色
admin,用户名取邮箱@前缀,密码 bcrypt 12 轮哈希入库; - 目标邮箱已存在且是管理员 → 打日志
bootstrapAdmin: admin account already exists, nothing to do.,不重置密码——改.env里的ADMIN_PASSWORD再重启不会修改已有管理员密码; - 目标邮箱已存在但只是普通用户 → 打警告日志跳过,绝不静默把普通账号提升为管理员。
- 两者都不设 → 整个引导跳过(库里有历史管理员时推荐留空)。
- 目标邮箱账号不存在 → 创建,角色
- 引导在迁移之后、监听之前执行,失败则启动中止。
registrationOpen:唯一的运行期配置
注册开关存数据库 app_settings 表(默认 false,即安装后默认禁止自助注册),由管理员经后台接口在线切换,无需重启。2026-10-25 实测完整闭环(ev_c1_settings.txt):
$ curl -s -b /tmp/cleep_admin.jar http://localhost:8140/api/admin/settings
{"registrationOpen":false}
$ curl -s -b /tmp/cleep_admin.jar -X PATCH http://localhost:8140/api/admin/settings \
-H 'Content-Type: application/json' -d '{"registrationOpen":true}'
{"registrationOpen":true,"error":null}
$ curl -s http://localhost:8140/api/auth/registration-status
{"open":true}
$ curl -s -b /tmp/cleep_admin.jar -X PATCH http://localhost:8140/api/admin/settings \
-H 'Content-Type: application/json' -d '{"registrationOpen":false}'
{"registrationOpen":false,"error":null}
GET /api/admin/settings需管理员登录态(未登录实测返回{"error":"Authentication required."});PATCH只接受布尔值,传其他类型返回{"error":"registrationOpen must be a boolean."};- 切到
true后公开注册接口立即放行(registration-status变{"open":true}),注册出的都是普通用户,管理员仍需后台创建或提权。 - 家庭/小团队部署建议保持
false,账号由管理员逐个创建(对应专栏 API 篇详述)。
九、安全响应头
Cleep 未引入第三方安全头中间件,而是在 server/middleware/securityHeaders.ts 手工设置了固定一组,全部响应无条件下发,无配置项可关。实测响应头原文(未登录访问注册开关接口,COOKIE_SECURE=false,2026-10-25 抓取):
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
Content-Security-Policy: default-src 'self'; script-src 'self'; style-src 'self'; img-src 'self' https: http: blob: data:; media-src 'self' blob:; connect-src 'self'; object-src 'none'; base-uri 'self'; frame-ancestors 'none'
Referrer-Policy: strict-origin-when-cross-origin
Permissions-Policy: camera=(self), microphone=(self), geolocation=(), payment=(), usb=()
Cross-Origin-Opener-Policy: same-origin
Cross-Origin-Resource-Policy: same-origin
X-Permitted-Cross-Domain-Policies: none
逐项速读:
| 头 | 值 | 对使用者的实际影响 |
|---|---|---|
Content-Security-Policy | default-src 'self',脚本/样式仅同源,图片放宽到任意 https/http/blob/data,对象插件全禁,禁止被嵌入(frame-ancestors 'none') | 前端无法加载第三方 JS;笔记内的外部图片、链接预览图正常显示(img-src 放宽即为它服务);不能把 Cleep 页面 iframe 进别的系统 |
X-Frame-Options | DENY | 同上,双层禁止嵌入 |
Strict-Transport-Security | max-age=15552000; includeSubDomains | 仅 COOKIE_SECURE=true 时下发(实测未出现,符合预期),见第六章 |
Permissions-Policy | 摄像头/麦克风同源可用,地理定位/支付/USB 全禁 | 录音附件功能(浏览器录音)要求页面同源且 HTTPS 安全上下文 |
COOP / CORP | 均 same-origin | 防跨窗口信息泄漏;跨站引用 Cleep 的图片资源会被拦(CORP) |
Referrer-Policy | strict-origin-when-cross-origin | 跳出站外只带源不带路径 |
另有两处由框架层设置的细节:x-powered-by 已显式关闭(不暴露技术栈指纹);JSON 请求体上限 1MB(express.json({ limit: '1mb' }),超限 413,配置不可调——附件走 multipart 不受此限)。前端静态资源中 index.html 与 Service Worker 脚本强制 Cache-Control: no-cache,保证 PWA 升级能被发现,代理层请勿覆写这两个文件的缓存策略。
十、生产环境配置模板
综合以上各章,家庭/小团队「反向代理 + HTTPS」形态的推荐 .env(在官方 .env.example 基础上补齐源码支持的两个限流组,并显式写全默认值以便审计):
# /opt/cleep/.env —— 生产模板(反代 TLS 形态)
PUID=999
PGID=999
POSTGRES_PASSWORD=<强密码A>
DATABASE_URL=postgres://cleep:<强密码A>@postgres:5432/cleep
SESSION_SECRET=<openssl rand -hex 32 生成>
# —— 网络 / 代理 ——
PORT=6169
COOKIE_SECURE=true # 前置反代已终止 HTTPS
TRUST_PROXY=true # 限流按真实客户端 IP 计数(与 COOKIE_SECURE 一起开)
# —— 限流(显式写全,含 .env.example 未列出的两组)——
AUTH_RATE_LIMIT_MAX=20
AUTH_RATE_LIMIT_WINDOW_MS=60000
UPLOAD_RATE_LIMIT_MAX=60
UPLOAD_RATE_LIMIT_WINDOW_MS=60000
NOTE_LOCK_RATE_LIMIT_MAX=20
NOTE_LOCK_RATE_LIMIT_WINDOW_MS=60000
LINK_PREVIEW_RATE_LIMIT_MAX=300
LINK_PREVIEW_RATE_LIMIT_WINDOW_MS=60000
# —— 首启管理员引导(账号建好后可整段删掉)——
ADMIN_EMAIL=admin@example.com
ADMIN_PASSWORD=<首启密码>
⚠️
NOTE_LOCK_*、LINK_PREVIEW_*两组变量官方 Compose 模板未透传,使用时在编排文件app.environment:段按同样写法各补两行(与既有AUTH_RATE_LIMIT_MAX透传行同格式),否则.env里的值进不了服务进程。纯 HTTP 直连形态把COOKIE_SECURE、TRUST_PROXY都改回false即可,其余不变。
变更操作速查:
| 想改什么 | 操作 | 生效 |
|---|---|---|
| 限流阈值、代理开关、数据库密码 | 改 .env → docker compose up -d | 重建服务进程后生效 |
| 注册开关 | 管理员调 PATCH /api/admin/settings | 立即 |
| 会话有效期、Cookie 属性、CSP | 无配置项,需改源码重构建 | — |
十一、FAQ
Q1:登录接口返回成功,但一刷新就回到登录页/接口全 401?
COOKIE_SECURE=true 但你在用纯 HTTP 访问——浏览器把带 Secure 的 Cookie 静默丢弃了。纯 HTTP 形态把它改回 false 并重新应用编排;或尽快给服务配上 HTTPS(推荐,第六章组合表)。
Q2:没人暴力破解,却频繁 429 Too many requests?
两种可能:① 反代场景忘开 TRUST_PROXY,全站共享一个 20 次的桶(第五章坑 2);② 多人共用出口 IP,/api/auth 整前缀计数把正常打开页面也算进去(坑 1)。分别开 TRUST_PROXY、调大 AUTH_RATE_LIMIT_MAX。
Q3:改了 .env 里的 ADMIN_PASSWORD,管理员密码没变?
引导逻辑幂等:账号已存在时什么都不做(既不建号也不改密码)。改管理员密码走管理端重置接口(见 API 篇)或登录后自行改密;.env 里的 ADMIN_PASSWORD 只影响「该邮箱账号尚不存在」的首次引导。
Q4:唯一的管理员密码忘了怎么办?
三个途径,按代价从小到大:① 若还有另一个管理员账号,用它调 POST /api/admin/users/:id/password 重置(会强制目标账号全设备下线);② 直接改库:对 users 表该行 UPDATE password_hash 为新 bcrypt 哈希(12 轮);③ 删除该用户行后重启服务,让 ADMIN_EMAIL/ADMIN_PASSWORD 重新引导——注意 notes、sessions 对用户是级联删除,该账号全部笔记会一并消失,务必先导出。
Q5:限流是分布式的吗?多实例部署共享计数吗? 不是。计数在单进程内存里(源码注释明示单实例自托管定位),重启清零、多实例不共享。v0.4.4 官方不支持水平扩展形态。
Q6:能把 Cleep 嵌进公司门户的 iframe 里吗?
不能。X-Frame-Options: DENY + CSP frame-ancestors 'none' 双重禁止,属硬编码安全设计,无开关(第九章)。跳转或 SSO 改造需等官方支持。
Q7:PORT 改成 8080 后访问不通?
PORT 只是应用服务内部监听端口;对外端口由编排 ports 映射决定。官方模板 ports 写作 "${PORT:-6169}:${PORT:-6169}" 时改 PORT 两端同步变;若你的编排把映射写死为 8140:6169(本文实测环境即如此),改 PORT 只会改变服务内部监听而映射左侧不变,需同步修改映射。改完记得数据库连接串不受影响(走内部服务名)。
十二、参考链接
- Cleep 官方仓库(
.env.example与源码均出自 tagv0.4.4):https://github.com/blindpassasjer/cleep (查询日期 2026-10-25) - Compose 模板:https://github.com/blindpassasjer/cleep/blob/main/docker-compose.yml
- 环境变量样例:https://github.com/blindpassasjer/cleep/blob/main/.env.example
- 限流实现:https://github.com/blindpassasjer/cleep/blob/main/server/middleware/rateLimit.ts
- 会话实现:https://github.com/blindpassasjer/cleep/blob/main/server/middleware/session.ts
- 安全响应头实现:https://github.com/blindpassasjer/cleep/blob/main/server/middleware/securityHeaders.ts
- 管理员引导实现:https://github.com/blindpassasjer/cleep/blob/main/server/db/bootstrapAdmin.ts
- 本专栏系列:《Cleep 0.4.4 介绍与选型指南》、《Cleep 0.4.4 Docker Compose 部署指南》