kmenta 文档 / 总览 GitHub ↗ 后台 ↗

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),三种方式下文逐一说明。

五分钟快速开始

  1. 往下看,在三种部署方式里选一种(没有服务器就选①Cloudflare,全部免费额度);
  2. 按对应章节部署完成后,打开 https://你的域名/admin/,会自动进入安装向导;
  3. 向导里设置管理员账号,按需打开 AI 审核 / 人机验证;
  4. 把下面这段代码贴到你网站的评论区位置,完成接入:
<div id="kcomment"></div>
<script src="https://你的评论域名/widget/comment-widget.js"
        data-server="https://你的评论域名"></script>
提示:本站评论区就跑在 kmenta 上,页面底部可以直接体验。

① Cloudflare Pages + D1 + R2(推荐)

适合:没有自己服务器、想要全球加速与免费额度的人。整套都在 Cloudflare 免费计划内。

前置条件

第一步:创建 D1 数据库

  1. 登录 Cloudflare Dashboard → 左侧 Workers 和 Pages → D1 SQL 数据库 → 创建数据库,名字填 kcomment;
  2. 创建后进入数据库页 → 控制台,把仓库里的 schema.sql 全部内容粘贴进去执行(建表)。

第二步:创建 R2 存储桶(图片上传用,可跳过)

左侧 R2 对象存储 → 创建存储桶,名字填 kmsg-files。如果不需要评论传图,可以跳过这一步并在后台关闭图片功能。

第三步:Fork 仓库并连接 Pages

  1. 在 GitHub 上 Fork 本仓库;
  2. Cloudflare → Workers 和 Pages → 创建 → Pages → 连接到 Git,选中你 Fork 的仓库;
  3. 构建配置:框架预设留空、构建命令留空、输出目录填 site(如果用仓库自带的 wrangler.toml 则无需改动);
  4. 在 设置 → 函数 → D1 数据库绑定 里添加绑定:变量名 DB,选择刚才建的 kcomment 库;如果有 R2 桶,再添加 R2 绑定:变量名 FILES,选择 kmsg-files;
  5. 点 保存并部署,得到一个 *.pages.dev 域名。

第四步:初始化与绑定域名

  1. 打开 https://你的项目.pages.dev/admin/ 完成安装向导;
  2. 想用自定义域名(例如 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 免费库

  1. 注册 MongoDB Atlas,新建 M0 Free 集群;
  2. Database Access → 添加数据库用户(记下用户名密码);
  3. Network Access → 允许 0.0.0.0/0(Vercel 没有固定出口 IP);
  4. 复制连接串:mongodb+srv://用户:密码@cluster0.xxxxx.mongodb.net/kcomment(末尾库名写 kcomment)。

第二步:导入 Vercel

  1. Fork 本仓库后,Vercel → Add New Project 导入该仓库,框架预设选 Other(仓库自带 vercel.json);
  2. Settings → Environment Variables 添加:
    变量值
    DB_TYPEmongo
    MONGODB_URI你的 Atlas 连接串
    MONGODB_DBkcomment
    ALLOWED_ORIGINS你主站的地址,如 https://example.com
  3. 点 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/ 会强制进入向导,共四步:

  1. 管理员账号:设置用户名与密码(≥8 位,PBKDF2 加盐哈希存储);
  2. AI 审核(可选):填 OpenAI 兼容接口的调用地址、API Key、模型名;
  3. 人机验证(可选):选厂商并填 Site Key / Secret Key;
  4. 审核策略(可选):开启后所有新评论先进待审队列。

向导完成后,所有选项都可以在后台「设置」里随时修改,不需要重新部署。

审核策略与 AI 审核

一条评论从提交到展示,会经过这条流水线:

发布 → ① 违禁模式库(命中秒拒)
     → ② AI 审核(开启时):通过 / 拒绝 / 转人工
     → ③ 预审核开关:开启则一律先进「待审」,人工放行
     → 展示

AI 审核参数说明

参数怎么填
调用地址OpenAI 兼容的 base url,填到版本号为止
API Key对应平台的密钥,服务端保存,永不下发浏览器
模型名如 deepseek-chat、glm-4-flash、gpt-4o-mini
保险机制:AI 接口超时或报错时,评论自动转「待审」而不是直接丢弃或放行,评论永远不会因为审核故障而丢失。

人机验证(验证码)

厂商特点Key 获取入口
Cloudflare Turnstile免费、无感验证,推荐CF Dashboard → Turnstile
hCaptcha国际常用,隐私友好dashboard.hcaptcha.com
reCAPTCHA v2经典勾选框google.com/recaptcha/admin
reCAPTCHA v3无感打分,低于阈值自动拒绝同上

通用流程:在厂商控制台为你的评论域名创建站点 → 拿到 Site Key(公开)与 Secret Key(保密)→ 后台选厂商粘贴两把 Key → 保存。前端组件会自动加载对应脚本,无需改任何页面代码。

图片与表情

违禁模式库

后台「违禁库」页签维护一批「一旦出现就拒绝展示」的模式。匹配前会做归一化:

因此模式库里存一条 骗:example。com,就能同时拦住 骗:example.com、骗 : EXAMPLE。COM 这类变体。命中后:评论立刻标记为「已拒绝」且永不展示、写入拦截日志(含命中的模式与评论原文,仅供管理员审计);后台不能把命中记录直接改成「展示」,需先删除对应日志。

登录安全(IP 限流 / 锁定)

设置项默认说明
每 IP 每小时失败上限5 次超出后返回 429,窗口按自然小时滚动
连续失败锁定阈值30 次达到后该 IP 直接 403 封禁,登录成功会清零计数

两个阈值在后台「安全与管理员」页可调。被封的 IP 在「IP 封禁管理」里查看并一键解封;也可以手动输入 IP 主动封禁。除登录限流外,评论发布、点赞、上传接口都有独立的频率限制,配合 Cloudflare 的 WAF 构成双层防 CC 体系。

管理员管理

日常评论治理

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_TYPEsqlitemongo 时启用 MongoDB 后端(Vercel 必须)
MONGODB_URI / MONGODB_DB—Mongo 连接串与库名
PORT3000自建版监听端口
DB_PATHdata/comments.dbSQLite 文件位置
ALLOWED_ORIGINS*CORS 白名单,生产务必收敛为主站域名
TRUST_PROXY1是否信任反代的 X-Forwarded-For
SEED_DEMOtrue首次启动写入演示评论

常见问题

评论发不出去,提示「操作过于频繁」?

发布接口限速每 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)。