kmenta 文档
隐私优先的开源评论系统:邮箱只存哈希、IP 永不下发前端、自带违禁词过滤 / AI 审核 / 人机验证 / 图片上传,一段脚本即可嵌入任何网站。
产品介绍
kmenta(原名 KComment)是一个对标 Twikoo 的开源评论系统,核心差异在「隐私」与「治理」两件事上做到了默认就安全:
| 能力 | 说明 |
|---|---|
| 隐私设计 | 邮箱只保存加盐哈希(仅用于生成头像),数据库被拖走也还原不出邮箱;IP / UA 只进管理后台的治理视图,任何对外接口都不下发。 |
| 评论审核链 | 违禁模式库(命中秒拒)→ AI 审核(可选,任意 OpenAI 兼容接口)→ 预审核队列(人工放行),三道闸门互相兜底。 |
| 人机验证 | 支持 hCaptcha、Google reCAPTCHA v2 / v3、Cloudflare Turnstile,后台选择厂商填 Key 即可。 |
| 表情与图片 | 颜文字 + Emoji 双栏选择器;图片上传大小上限后台可调(默认 2048KB),存 Cloudflare R2 或本地磁盘。 |
| 登录安全 | 每 IP 每小时失败限次、连续失败锁 IP(阈值可调、可解封),多管理员账号管理。 |
| 部署形态 | Cloudflare Pages(D1 + R2)、Vercel(MongoDB)、自建 Node.js(SQLite),三种方式下文逐一说明。 |
五分钟快速开始
- 往下看,在三种部署方式里选一种(没有服务器就选①Cloudflare,全部免费额度);
- 按对应章节部署完成后,打开
https://你的域名/admin/,会自动进入安装向导; - 向导里设置管理员账号,按需打开 AI 审核 / 人机验证;
- 把下面这段代码贴到你网站的评论区位置,完成接入:
<div id="kcomment"></div>
<script src="https://你的评论域名/widget/comment-widget.js"
data-server="https://你的评论域名"></script>
① Cloudflare Pages + D1 + R2(推荐)
适合:没有自己服务器、想要全球加速与免费额度的人。整套都在 Cloudflare 免费计划内。
前置条件
- 一个 GitHub 账号、一个 Cloudflare 账号;
- 已安装 Node.js 18+ 与
npm。
第一步:创建 D1 数据库
- 登录 Cloudflare Dashboard → 左侧 Workers 和 Pages → D1 SQL 数据库 → 创建数据库,名字填
kcomment; - 创建后进入数据库页 → 控制台,把仓库里的
schema.sql全部内容粘贴进去执行(建表)。
第二步:创建 R2 存储桶(图片上传用,可跳过)
左侧 R2 对象存储 → 创建存储桶,名字填 kmsg-files。如果不需要评论传图,可以跳过这一步并在后台关闭图片功能。
第三步:Fork 仓库并连接 Pages
- 在 GitHub 上 Fork 本仓库;
- Cloudflare → Workers 和 Pages → 创建 → Pages → 连接到 Git,选中你 Fork 的仓库;
- 构建配置:框架预设留空、构建命令留空、输出目录填
site(如果用仓库自带的wrangler.toml则无需改动); - 在 设置 → 函数 → D1 数据库绑定 里添加绑定:变量名
DB,选择刚才建的kcomment库;如果有 R2 桶,再添加 R2 绑定:变量名FILES,选择kmsg-files; - 点 保存并部署,得到一个
*.pages.dev域名。
第四步:初始化与绑定域名
- 打开
https://你的项目.pages.dev/admin/完成安装向导; - 想用自定义域名(例如
kmta.example.com):项目 → 自定义域 → 添加域名,然后到该域名的 DNS 里加一条 CNAME 指向你的项目.pages.dev即可。
如何接入到你的页面
<div id="kcomment"></div>
<script src="https://你的评论域名/widget/comment-widget.js"
data-server="https://你的评论域名"></script>
② Vercel + MongoDB
适合:习惯 Vercel 生态的人。存储从 SQLite 换成 MongoDB Atlas 免费集群,代码完全一致。
第一步:创建 MongoDB Atlas 免费库
- 注册 MongoDB Atlas,新建 M0 Free 集群;
- Database Access → 添加数据库用户(记下用户名密码);
- Network Access → 允许
0.0.0.0/0(Vercel 没有固定出口 IP); - 复制连接串:
mongodb+srv://用户:密码@cluster0.xxxxx.mongodb.net/kcomment(末尾库名写kcomment)。
第二步:导入 Vercel
- Fork 本仓库后,Vercel → Add New Project 导入该仓库,框架预设选 Other(仓库自带
vercel.json); - Settings → Environment Variables 添加:
变量 值 DB_TYPEmongoMONGODB_URI你的 Atlas 连接串 MONGODB_DBkcommentALLOWED_ORIGINS你主站的地址,如 https://example.com - 点 Deploy。
第三步:初始化
打开 https://你的项目.vercel.app/admin/ 完成安装向导。绑自定义域名:Vercel 项目 Settings → Domains 添加后,按提示到 DNS 加 CNAME(一般是 cname.vercel-dns.com)。
如何接入到你的页面
<div id="kcomment"></div>
<script src="https://你的评论域名/widget/comment-widget.js"
data-server="https://你的评论域名"></script>
③ 自建服务器(Node.js + SQLite)
适合:有自己的 VPS / 家里的小主机,数据想完全握在自己手里。
第一步:拉代码并安装
git clone https://github.com/Kang0234/KComment.git
cd KComment
npm install
第二步:配置环境变量(可选)
复制 .env.example 为 .env。推荐只改两项:
| 变量 | 说明 |
|---|---|
PORT | 服务端口,默认 3000 |
ALLOWED_ORIGINS | 允许挂评论区的站点来源,逗号分隔,生产环境务必收敛 |
其余(管理员密码、JWT 密钥)都可以在首次启动的安装向导里设置,.env 里留空即可。
第三步:启动与守护
# 直接跑
npm start
# 用 pm2 守护(推荐)
npm i -g pm2
pm2 start server.js --name kmenta
pm2 save
第四步:Nginx 反代示例
server {
listen 443 ssl;
server_name kmta.example.com;
location / {
proxy_pass http://127.0.0.1:3000;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $host;
}
}
X-Forwarded-For,否则限流与 IP 记录会拿到 Nginx 的地址。数据文件在 data/comments.db,上传图片在 data/uploads/,备份这两个目录即可。如何接入到你的页面
<div id="kcomment"></div>
<script src="https://你的评论域名/widget/comment-widget.js"
data-server="https://你的评论域名"></script>
一段脚本接入(最简)
组件会自动挂载到页面上 id 为 kcomment 或 comment-widget 的元素:
<div id="kcomment"></div>
<script src="https://你的评论域名/widget/comment-widget.js"
data-server="https://你的评论域名"
data-page-key="/post/hello"></script>
| 属性 | 说明 |
|---|---|
data-server | 评论服务地址。若脚本本身就托管在评论域名下,可省略(自动取脚本来源) |
data-page-key | 评论楼层标识。省略时取当前页面路径 location.pathname,即每个页面天然独立 |
手动初始化(SPA 推荐)
window.addEventListener('load', function () {
kcomment.init({
el: '#box', // 挂载元素,选择器或 DOM 均可
server: 'https://你的评论域名',
pageKey: '/post/hello-world', // 楼层标识,路由变化时重新 init 即可
});
});
手动初始化会跳过自动挂载,适合 Vue / React 等单页应用在路由切换时反复调用。
一页多个评论区 / 每篇文章独立楼层
<div class="cmt" data-key="/articles/one"></div>
<div class="cmt" data-key="/articles/two"></div>
<script>
document.querySelectorAll('.cmt').forEach(function (el) {
kcomment.init({ el: el, server: 'https://你的评论域名', pageKey: el.dataset.key });
});
</script>
给每个容器不同的 pageKey,数据完全隔离。本站的文章页就是这样实现的。
安装向导(首次初始化)
部署后第一次打开 /admin/ 会强制进入向导,共四步:
- 管理员账号:设置用户名与密码(≥8 位,PBKDF2 加盐哈希存储);
- AI 审核(可选):填 OpenAI 兼容接口的调用地址、API Key、模型名;
- 人机验证(可选):选厂商并填 Site Key / Secret Key;
- 审核策略(可选):开启后所有新评论先进待审队列。
向导完成后,所有选项都可以在后台「设置」里随时修改,不需要重新部署。
审核策略与 AI 审核
一条评论从提交到展示,会经过这条流水线:
发布 → ① 违禁模式库(命中秒拒)
→ ② AI 审核(开启时):通过 / 拒绝 / 转人工
→ ③ 预审核开关:开启则一律先进「待审」,人工放行
→ 展示
AI 审核参数说明
| 参数 | 怎么填 |
|---|---|
| 调用地址 | OpenAI 兼容的 base url,填到版本号为止 |
| API Key | 对应平台的密钥,服务端保存,永不下发浏览器 |
| 模型名 | 如 deepseek-chat、glm-4-flash、gpt-4o-mini |
人机验证(验证码)
| 厂商 | 特点 | Key 获取入口 |
|---|---|---|
| Cloudflare Turnstile | 免费、无感验证,推荐 | CF Dashboard → Turnstile |
| hCaptcha | 国际常用,隐私友好 | dashboard.hcaptcha.com |
| reCAPTCHA v2 | 经典勾选框 | google.com/recaptcha/admin |
| reCAPTCHA v3 | 无感打分,低于阈值自动拒绝 | 同上 |
通用流程:在厂商控制台为你的评论域名创建站点 → 拿到 Site Key(公开)与 Secret Key(保密)→ 后台选厂商粘贴两把 Key → 保存。前端组件会自动加载对应脚本,无需改任何页面代码。
图片与表情
- 输入框下方 😊 打开表情面板:颜文字 / Emoji 两个标签页,点击插入光标处;
- 📷 选择图片上传,成功后以
形式插入正文,展示时渲染为缩略图,点击全屏; - 后台「设置 → 图片与表情」:总开关、单张大小上限(1–8192KB,默认 2048);
- 支持格式 PNG / JPG / WebP / GIF,服务端做魔数校验,伪装后缀的文件会被拒绝。
违禁模式库
后台「违禁库」页签维护一批「一旦出现就拒绝展示」的模式。匹配前会做归一化:
- 全角字母数字 → 半角(ABC → abc);
- 中文句号、冒号、顿号 → 统一为
.和:; - 去掉所有空格与零宽字符;忽略大小写。
因此模式库里存一条 骗:example。com,就能同时拦住 骗:example.com、骗 : EXAMPLE。COM 这类变体。命中后:评论立刻标记为「已拒绝」且永不展示、写入拦截日志(含命中的模式与评论原文,仅供管理员审计);后台不能把命中记录直接改成「展示」,需先删除对应日志。
登录安全(IP 限流 / 锁定)
| 设置项 | 默认 | 说明 |
|---|---|---|
| 每 IP 每小时失败上限 | 5 次 | 超出后返回 429,窗口按自然小时滚动 |
| 连续失败锁定阈值 | 30 次 | 达到后该 IP 直接 403 封禁,登录成功会清零计数 |
两个阈值在后台「安全与管理员」页可调。被封的 IP 在「IP 封禁管理」里查看并一键解封;也可以手动输入 IP 主动封禁。除登录限流外,评论发布、点赞、上传接口都有独立的频率限制,配合 Cloudflare 的 WAF 构成双层防 CC 体系。
管理员管理
- 「安全与管理员 → 管理员账号」可添加多个管理员(用户名 3–24 位字母/数字/下划线);
- 不能删除当前登录的账号,站点至少保留一个管理员;
- 所有管理员密码一律 PBKDF2/Scrypt 加盐哈希存储,服务器上不存在明文。
日常评论治理
- 待审队列:预审核或 AI 转人工的评论集中在这里,「通过」后才会出现在前台;
- 举报处理:访客可举报评论,后台按举报数排序查看,可一键删除;
- 删除评论:级联删除其所有回复、举报记录与图片引用;
- 治理字段:IP / UA / 邮箱哈希只在后台列表可见,用于定位滥用来源。
HTTP API
| 方法 | 路径 | 说明 |
|---|---|---|
| GET | /api/comment?page_key=… | 树形拉取某页面已展示的评论(已脱敏) |
| POST | /api/comment | 发表评论。JSON 字段:page_key(必填)、content(≤1000 字)、user_name、user_email、is_anonymous、parent_id |
| POST | /api/comment/:id/like | 点赞 / 取消点赞(IP+UA 指纹去重) |
| POST | /api/comment/:id/report | 举报,body 可带 reason |
| POST | /api/upload | 图片上传,multipart 字段 file,返回 { url } |
| GET | /api/comment/site-config | 站点公开配置(是否要求验证码等,自托管版) |
| GET / POST | /api/admin/… | 管理接口,需 Bearer Token,详见后台「设置」页与源码 |
环境变量
| 变量 | 默认 | 说明 |
|---|---|---|
DB_TYPE | sqlite | mongo 时启用 MongoDB 后端(Vercel 必须) |
MONGODB_URI / MONGODB_DB | — | Mongo 连接串与库名 |
PORT | 3000 | 自建版监听端口 |
DB_PATH | data/comments.db | SQLite 文件位置 |
ALLOWED_ORIGINS | * | CORS 白名单,生产务必收敛为主站域名 |
TRUST_PROXY | 1 | 是否信任反代的 X-Forwarded-For |
SEED_DEMO | true | 首次启动写入演示评论 |
常见问题
评论发不出去,提示「操作过于频繁」?
发布接口限速每 IP 每分钟若干条(防 CC),等一分钟再试;如果你在反代后面部署,检查 X-Forwarded-For 是否正确传递。
换了域名 / 迁移后,老评论还在吗?
在。评论按 page_key 存储,只要新页面用相同的 pageKey(默认是路径),楼层会原样跟随;换域名只影响接口地址,把接入代码里的 data-server 换成新域名即可。
忘了管理员密码?
自建版:删除数据库中的 settings 表里 initialized 那一行(或直接清空 settings 表),重新打开后台即会再次进入安装向导。Cloudflare 版同理,在 D1 控制台执行 DELETE FROM settings WHERE key='initialized';
如何完全重置?
备份 data/ 目录后清空即可(Cloudflare 版在 D1 控制台执行 DROP TABLE 后重跑 schema.sql)。
