Skip to content
0

文章发布较早,内容可能过时,阅读注意甄别。

Twikoo评论

提示

本文是在 博主One 文章:《配置 twikoo 评论系统》 基础上增加了自己实践过程的一些细节,转载无需和我联系,但请注明文章来源。如果侵权之处,请联系博主进行删除,谢谢~

部署方式

官网:https://twikoo.js.org

Twikoo 支持多种部署方式:云函数,Vercel,私有部署、Docker.... 具体参见文档:https://twikoo.js.org/backend.html

‍ 最原始的方法,也就是直接在服务器上部署,步骤很简单:安装 node → 安装 tkserver → 启动。

sh
$ npm i -g tkserver

$ ln -s /opt/nodejs/node/bin/tkserver /usr/local/bin/tkserver

$ tkserver

然后就可以访问了,地址是:http://服务端IP:8080

Linux 服务器可以用 nohup tkserver >> tkserver.log 2>&1 & 命令后台启动。

提示

可能需要在云服务器上开启 8080 端口的防火墙

还是推荐用 Docker 来部署。我之前是用私有部署,几年后想升级 Twikoo,但是因为 node 版本太老了,导致升级失败... 然后试着升级 node,又是一堆报错...

Docker 部署

sh
docker run --name twikoo -e TWIKOO_THROTTLE=1000 -p 8080:8080 -v ${PWD}/data:/app/data -d imaegoo/twikoo

docker-compose.yaml 内容:

yaml
version: "3"
services:
  twikoo:
    image: imaegoo/twikoo
    container_name: twikoo
    restart: unless-stopped
    ports:
      - 8080:8080
    environment:
      TWIKOO_THROTTLE: 1000
    volumes:
      - ./data:/app/data

自己实际部署:😜

  • 创建并启动一个名为 twikoo 的 Docker 容器
sh
docker run --name twikoo -e TWIKOO_THROTTLE=1000 -p 8426:8080 -v ${PWD}/data:/app/data -d imaegoo/twikoo

并在其中生成了一个 docker-compose.yaml 文件

sh
# 创建名为 `twikoo` 的目录
mkdir /root/twikoo
# 创建docker-compose.yaml 文件并添加以下内容
cat >>/root/twikoo/docker-compose.yaml <<EOF
version: '3'
services:
  twikoo:
    image: imaegoo/twikoo
    container_name: twikoo
    restart: unless-stopped
    ports:
      - 8426:8080
    environment:
      TWIKOO_THROTTLE: 1000
    volumes:
      - ./data:/app/data
EOF

# 进入该目录
cd /root/twikoo
# 检查 8080 端口是否已经被其他进程占用
netstat -antlp|grep 8080
# 启动twikoo镜像服务
docker-compose  up -d
[+] Building 0.0s (0/0)                                                                                                  docker:default
[+] Running 2/2
 Network twikoo_default  Created                                                                                                 0.0s
 Container twikoo        Started                                                                                                 0.0s
 [root@VM-4-16-centos twikoo]# docker ps -l
CONTAINER ID   IMAGE            COMMAND                   CREATED          STATUS          PORTS                                       NAMES
dc43659872fe   imaegoo/twikoo   "docker-entrypoint.s…"   56 minutes ago   Up 56 minutes   0.0.0.0:8426->8080/tcp, :::8426->8080/tcp   twikoo
[root@VM-4-16-centos twikoo]#

在私有部署的情况下,在你执行 tkserver 的时候,就会在当前目录创建:

  • data 文件夹:存放评论数据、配置等
  • tkserver.log:日志文件

因此,有必要在你自己指定的目录下启动 tkserver,方便后期的数据备份、日志分析等。

如果你使用的是 Docker,在上述命令里其实也用了 ${PWD}/data 来指定数据文件的目录,请自行选择。

sh
[root@VM-4-16-centos twikoo]# ls
data  docker-compose.yaml
[root@VM-4-16-centos twikoo]# ls data/
db.json  db.json.0  db.json.1  db.json.2
[root@VM-4-16-centos twikoo]#

HTTPS配置

理论上这样部署,就完成后台的部分了,但鉴于我的网站用了 HTTPS,而 Twikoo 本身并不支持,因此还需要做反向代理

我这里配置 HTTPS 是用到cloudflare

  • 进入cloudflare,在【账户主页】找到您的域名点击进去(如果没有请添加域名),进去后找到 DNS 记录,添加二级域名
    • 类型:A
    • 名称:twikoo(自定义就行)
    • IPv4:填写服务器的 IP

image-20250215181017931.png

Nginx配置

nginx
upstream twi {
   server peterjxl.com:8080; #你的域名+加端口
}

server {
    listen  443 ssl;
    server_name  twikoo.peterjxl.com; #子域名
    ssl_certificate  /opt/nginxrun/conf/cert/8852603_twikoo.peterjxl.com.pem;
    ssl_certificate_key /opt/nginxrun/conf/cert/8852603_twikoo.peterjxl.com.key;

    # ssl_session_cache    shared:SSL:1m;
    ssl_session_timeout  5m;

    ssl_protocols SSLv3 TLSv1 TLSv1.1 TLSv1.2;
    ssl_ciphers  HIGH:!ADH:!EXPORT56:RC4+RSA:+MEDIUM;
    ssl_prefer_server_ciphers  on;

    location / {
	proxy_pass http://twi;
    }
}
  • 自己实际配置
nginx
# 进入该目录
cd /etc/nginx/conf.d/
# 创建文件
vim twikoo.seasir.top.conf

[root@VM-4-16-centos conf.d]#  cat twikoo.seasir.top.conf
server {
    listen 80;
    server_name  twikoo.seasir.top;
    #配置https重定向
    return 301 https://$host$request_uri;
}

server {
    listen  443 ssl;
    server_name  twikoo.seasir.top;

    location / {
        proxy_pass http://云服务器ip:8080/; # 实际的后台路径
        client_max_body_size 100M;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }

    access_log /var/log/nginx/photo.onedayxyy.cn.https.log;
}

# 用于测试 Nginx 配置文件的语法是否正确
nginx -t
  • 配置完成后需要重启 NGINX 服务
sh
nginx -s reload

image-20250215182647730.png

前端配置

  • 编辑 docs\.vitepress\config.ts文件或者前往查看博主Config配置,修改为如下代码:
ts
  comment: {
    // provider: "giscus",
    provider: "twikoo",
    options: {
      // twikoo 配置,官网:https://twikoo.js.org/
      envId: "填写您自己的twikoo域名",
      jsUrl: "https://cdn.staticfile.org/twikoo/1.6.42/twikoo.all.min.js",
    },
  },

运行验证

sh
pnpm docs:dev

Vercel 部署

提示

本文是在 博主 唯知笔记 文章:《使用 Twikoo 评论系统》 基础上增加了自己实践过程的一些细节,转载无需和我联系,但请注明文章来源。如果侵权之处,请联系博主进行删除,谢谢~

Twikoo 评论,需要部署前后端,包括数据库,操作略有复杂,但是不限制代码托管和服务托管,自定义程度更高。官方文档 https://twikoo.js.org/ ,非常详细,部署步骤如下:

建立数据库

MongoDB AtLas 是 MongoDB Inc 提供的 MongoDB 数据库托管服务。免费账户可以永久使用 500 MiB 的数据库,足够存储 Twikoo 评论使用。

  • 申请 MongoDB AtLas 账号

  • 创建免费 MongoDB 数据库,区域推荐选择离 Twikoo 后端(Vercel / Netlify / AWS Lambda / VPS)地理位置较近的数据中心以获得更低的数据库连接延迟。如果不清楚自己的后端在哪个云服务器和地区,可选择 AWS / Oregon (us-west-2)和香港地区,该数据中心基建成熟,故障率低,且使用 Oregon 州的清洁能源,较为环保

  • Database Access 页面点击 Add New Database User 创建数据库用户,Authentication MethodPassword,在 Password Authentication 下设置数据库用户名和密码,建议点击 Auto Generate 自动生成一个不含特殊符号的强壮密码并妥善保存。点击 Database User Privileges 下方的 Add Built In RoleSelect Role 选择 Atlas Admin,最后点击 Add User

1756629719786.png

  • Network Access 页面点击 Add IP Address 添加网络白名单。因为 Vercel / Netlify / Lambda 的出口地址不固定,因此 Access List Entry 输入 0.0.0.0/0(允许所有 IP 地址的连接)即可。如果 Twikoo 部署在自己的服务器上,这里可以填入固定 IP 地址。点击 Confirm 保存

1756630088470.png

  • Overview 页面点击 Connect,连接方式选择 Drivers,并记录数据库连接字符串,请将连接字符串中的 <username>:<password> 修改为刚刚创建的数据库 用户名:密码,复制Mongodb连接字符串并妥善保管,后面部署需要用到!然后点击 Done

示例

mongodb+srv://数据库用户名:数据库密码@cluster0.d1vvzs3.mongodb.net/?retryWrites=true&w=majority&appName=Cluster0

1756630344870.png

  • (可选)默认的连接字符串没有指定数据库名称,Twikoo 会连接到默认的名为 test 的数据库。如果需要在同一个 MongoDB 里运行其他业务或供多个 Twikoo 实例使用,建立加入数据库名称并配置对应的 ACL。 连接字符串包含了连接到 MongoDB 数据库的所有信息,一旦泄露会导致评论被任何人添加、修改、删除,并有可能获取你的 SMTP、图床 token 等信息。请妥善记录这一字符串,之后需要填入到 Twikoo 的部署平台里。

Vercel 部署

  • 申请 Vercel 账号,点击以下按钮将 Twikoo 一键部署到 Vercel Deploy

Deploy

  • 进入 Settings - Environment Variables,添加环境变量 MONGODB_URI,值为前面记录的数据库连接字符串

1756631059285.png

  • 进入 Settings - Deployment Protection,设置 Vercel AuthenticationDisabled,并 Save

1756631162813.png

  • 进入 Deployments , 然后在任意一项后面点击更多(三个点) , 然后点击 Redeploy , 最后点击下面的 Redeploy 等待部署完成,部署完成即可

  • 进入 Overview,点击 Domains 下方的链接,如果环境配置正确,可以看到 “Twikoo 云函数运行正常” 的提示,说明部署成功!

1756631491236.png

域名配置

  • 部署成功后,修改默认域名为你的子域名,需要去你的域名管理那上修改 DNS 解析。

1756631698889.png

前端配置

  • 安装 twikoo
bash
pnpm install twikoo
  • 初始化 twikoo 组件和组件插入 插槽
vue
<template>
  <div id="twikoo"></div>
</template>

<script setup lang="ts">
import { onMounted, watch } from 'vue'
import { useRoute } from 'vitepress'

const route = useRoute()

const initTwikoo = async () => {
  // 判断是否在浏览器环境中
  if (typeof window !== 'undefined') {
    const twikoo = await import('twikoo')
    twikoo.init({
      envId: 'https://twikoo.xxx.com/', // 换成你自己配置的域名
      el: '#twikoo'
    })
  }
}

// 监听路由刷新评论
watch(route, () => {
  initTwikoo()
})

onMounted(() => {
  initTwikoo()
})
</script>
vue
<script setup lang="ts">
import Twikoo from './Twikoo.vue'
</script>

<template>
  <Teek.Layout>
    <template #teek-doc-after-appreciation-before>
      <!-- 评论组件 -->
      <Twikoo />
    </template>
  </Teek.Layout>
</template>

配置邮件

  • 前后端都处理好后,界面就能正常展示了,但是我们还要处理下邮件功能。进入您的文章底部,找到评论区的设置,首次打开设置按钮后,会有设置密码框,设置一个复杂密码并记住。然后进入配置管理,选择邮件通知

  • 按照提示输入你的邮箱,邮箱授权码等即可。最后有个邮件测试,测试后,你能收到一封邮件,说明功能可用了

美化样式

  • twikoo 配置面板里的插件页签,选择代码高亮主题 coy,代码复制插件 copyButton。

  • 自定义 css

.vitepress/theme/style/comment.scss
scss
// 定义变量
:root {
    --hyde-border-radius: calc(0.25rem * 2); // 8px
    --hyde-spacing-2xl: calc(0.25rem * 2); // 8px
    --hyde-font-size-sm: 0.875rem; // 14px
    --hyde-font-size-st: 1rem; // 16px
    --hyde-spacing: 0.25rem; // 4px
    --vp-code-link-hover-color: #79bbff;
    --hyde-spacing: 0.25rem; // 4px
    --hyde-card-border-radius: 0.25rem * 4; // 16px
    --hyde-spacing-6xl: 0.25rem * 6; // 24px
    --hyde-transition-3: all 0.3s; // 0.3s
    --hyde-card-border-radius: calc(0.25rem * 2); // 8px
    --hyde-primary-color-dark: rgb(51.2, 126.4, 204);
    --hyde-primary-color: #409eff;
    --hyde-font-size-xs: 0.75rem; // 12px
}

.twikoo {
    .el-input-group__append,
    .el-input-group__prepend,
    .el-textarea__inner {
        border: 1px solid #dcdfe6;
        box-shadow: none;
    }
    .el-input-group__prepend {
        border-right: none;
    }
    .el-button--small {
        height: auto;
    }
    .el-textarea > .el-textarea__inner {
        min-height: 117px !important;
        border-radius: var(--hyde-border-radius);
        margin-top: var(--hyde-spacing-2xl);
    }
    .tk-preview-container {
        border-radius: var(--hyde-border-radius);
    }
    .tk-comments-count {
        font-size: var(--hyde-font-size-sm);
        color: var(--vp-c-text-2);
    }
    .tk-nick,
    .tk-replies .tk-nick-link {
        font-size: var(--hyde-font-size-st);
        margin-right: var(--hyde-spacing);
        color: var(--hyde-primary-color);
    }
    .tk-tag {
        margin-right: var(--hyde-spacing);
    }
    .tk-comments-container > .tk-comment {
        border: solid 1px #f3f4f6;
        border-radius: var(--hyde-card-border-radius);
        padding: var(--hyde-spacing-6xl);
        margin-top: 0;
        margin-bottom: var(--hyde-spacing-6xl);
        transition: var(--hyde-transition-3);
        &:hover {
            box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05);
        }
    }
    .tk-replies-expand > .tk-comment {
        border-top: solid 1px #f7f7f7;
        padding-top: var(--hyde-spacing-4xl);
    }
    .tk-content p {
        line-height: 1.6;
    }
    a:not(.tk-ruser):not(.tk-nick-link) {
        color: var(--hyde-primary-color-dark);
        font-weight: 500;
        text-underline-offset: 2px;
        text-decoration: underline;
        &:hover {
            color: var(--hyde-primary-color);
        }
    }
    // 代码块
    div.code-toolbar {
        border-radius: var(--hyde-border-radius) !important;
        box-shadow: var(--vp-code-block-shadow);
        :not(pre) > code[class*="language-"],
        pre[class*="language-"] {
            background: var(--vp-code-block-bg);
            border-radius: var(--hyde-border-radius);
        }
        pre[class*="language-"] {
            &::before,
            &::after {
                content: none;
            }
            & > code {
                padding: 1em;
                border-left: 4px solid var(--hyde-primary-color);
                border-radius: var(--hyde-border-radius);
            }
        }
        & > div.toolbar {
            z-index: 1;
            top: 8px;
            right: 8px;
            & > .toolbar-item > button {
                display: none;
                padding: 0 6px;
                font-size: var(--hyde-font-size-xs);
                color: black;
            }
        }
        &:hover > div.toolbar > .toolbar-item > button {
            display: block;
        }
    }
    .tk-admin-container {
        z-index: 1;
    }
}
.dark .twikoo {
    .tk-comments-container > .tk-comment {
        border-color: #454545;
        &:hover {
            box-shadow: 0 4px 12px rgba(255, 255, 255, 0.15);
        }
    }
    .tk-replies-expand > .tk-comment {
        border-color: #343434;
    }
    // 代码块
    div.code-toolbar {
        pre[class*="language-"] {
            & > code {
                filter: brightness(0.8);
            }
        }
    }
}
  • css 注入主题配置

docs\.vitepress\theme\styles\index.scss中添加配置

docs\.vitepress\theme\styles\index.scss
scss
@use "./comment.scss" as *; // 评论样式

参考文档

最近更新