使用Waline给Hexo静态博客添加评论系统

6/17/2021 Waline评论系统评论通知防恶意评论

# 1. Waline简介

Waline 是一款从 Valine 衍生的带后端评论系统,可以将 Waline 等价成 With backend Valine。—— Waline 官网的介绍

Waline同时具有Valine的轻量和后端管理的方便两大特性,并且提供了简单方便的Serverless部署方案,遵循轻量化、集约化设计思路的指导,支持邮件通知、Telegram通知、QQ通知及微信通知接口的接入,提供大量可自定义参数接口。

启用 Waline 即可为诸如Hexo、Hugo、Gitbook这样的静态网站提供评论与浏览量服务。

Waline效果

# 2. 搭建前的环境准备

以下我将采用Nginx+Docker部署的方式进行搭建,VPS系统用的是Debian 11 x86_64。VPS的购买及配置、域名解析、Docker的概念及使用...如果不会的话见我的其他博客:VPS基本部署环境的搭建与配置 (opens new window)Docker容器化及项目环境管理 (opens new window)

Waline支持的部署方式非常多,即便没有服务器也可以白嫖服务进行部署,具体参见 官方文档 (opens new window),这里就不赘述了。

# 2.1 Docker环境搭建

$ apt-get update -y && apt-get install curl -y  # 安装curl
$ curl https://get.docker.com | sh -   # 安装docker
$ sudo systemctl start docker  # 启动docker服务
$ docker version # 查看docker版本(客户端要与服务端一致)
1
2
3
4

# 2.2 Docker-MySQL环境搭建

# 2.2.1 拉取镜像创建实例容器并运行

$ docker pull mysql:5.7
$ docker run -p 3306:3306 --name mysql \
-e TZ=Asia/Shanghai \
-v /mydocker/mysql/conf:/etc/mysql/conf.d \
-v /mydocker/mysql/logs:/var/log/mysql \
-v /mydocker/mysql/data:/var/lib/mysql \
-e MYSQL_ROOT_PASSWORD=[password] \
-d mysql:5.7 --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
$ docker update mysql --restart=always
1
2
3
4
5
6
7
8
9

命令解释说明:

-p 3306:3306:将主机的3306端口映射到docker容器的3306端口。
--name mysql:运行服务名字
-e TZ=Asia/Shanghai:时区是使用了世界标准时间(UTC)。因为在中国使用,所以需要把时区改成东八区的。
-e MYSQL_ROOT_PASSWORD=[password]:初始化 root 用户的密码。
-d mysql:5.7 : 后台程序运行mysql5.7
--character-set-server=utf8mb4 :设置字符集
--collation-server=utf8mb4_unicode_ci:设置校对集
1
2
3
4
5
6
7

说明:如果是挂载已有的其他服务器数据,可能会出现用户权限问题,如果网络是通的,建议使用Navicat的数据传输功能(工具——数据传输——配置源与目标链接——选择需要传输的数据表即可),数据传输速度很快。

# 2.2.2 创建数据库及用户

在本地使用Navicat工具使用root用户连接上该数据库,使用如下四条命令创建数据库及用户。

--创建新的数据库,并设置数据库编码
$ CREATE DATABASE 你的数据库名 DEFAULT CHARSET=utf8 DEFAULT COLLATE utf8_unicode_ci;

--创建新的用户
$ CREATE USER '你的用户名'@'你的服务器IP' IDENTIFIED BY '你的密码';

--把数据库的管理权限给予刚刚创建的MySQL用户
$ GRANT ALL PRIVILEGES ON *.* TO '你的用户名'@'%' IDENTIFIED BY '你的密码' WITH GRANT OPTION;

--刷新权限,使用设置生效
$ FLUSH PRIVILEGES;
1
2
3
4
5
6
7
8
9
10
11

注:如果连接数据库时出现Access denied for user '用户名'@'某IP' (using password: YES)问题,则是第三句授权出了问题,你的本地外网IP被拦截了,那个'%'代表的是访问IP不受限制。

另注:注意设置数据库的时区,默认时区使用了世界标准时间(UTC),比国内晚8个小时,会导致评论时间显示有误。如果没设置的话可以通过以下方式修改:

$ docker exec -it mysql bash                 # 进入mysql容器内部
$ date -R                                    # 查看当前时区
$ cp /usr/share/zoneinfo/PRC /etc/localtime  # 修改为当地时区
$ exit                                       # 退出mysql容器
$ docker restart mysql                       # 重启mysql容器
1
2
3
4
5

# 3. 搭建Waline服务端

# 3.1 初始化Waline的表结构

前面我们已经创建好了MySQL数据库并使用Navicat工具连接,下面我们将执行对该数据库执行 waline.sql (opens new window) 文件初始化表结构。

/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
/*!40101 SET NAMES utf8 */;
SET NAMES utf8mb4;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;

# Dump of table wl_Comment
# ------------------------------------------------------------

CREATE TABLE `wl_Comment` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `user_id` int(11) DEFAULT NULL,
  `comment` text,
  `insertedAt` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `ip` varchar(100) DEFAULT '',
  `link` varchar(255) DEFAULT NULL,
  `mail` varchar(255) DEFAULT NULL,
  `nick` varchar(255) DEFAULT NULL,
  `pid` int(11) DEFAULT NULL,
  `rid` int(11) DEFAULT NULL,
  `status` varchar(50) NOT NULL DEFAULT '',
  `ua` text,
  `url` varchar(255) DEFAULT NULL,
  `createdAt` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
  `updatedAt` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

# Dump of table wl_Counter
# ------------------------------------------------------------

CREATE TABLE `wl_Counter` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `time` int(11) DEFAULT NULL,
  `url` varchar(255) NOT NULL DEFAULT '',
  `createdAt` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
  `updatedAt` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

# Dump of table wl_Users
# ------------------------------------------------------------

CREATE TABLE `wl_Users` (
  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
  `display_name` varchar(255) NOT NULL DEFAULT '',
  `email` varchar(255) NOT NULL DEFAULT '',
  `password` varchar(255) NOT NULL DEFAULT '',
  `type` varchar(50) NOT NULL DEFAULT '',
  `url` varchar(255) DEFAULT NULL,
  `avatar` varchar(255) DEFAULT NULL,
  `github` varchar(255) DEFAULT NULL,
  `createdAt` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
  `updatedAt` timestamp NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66

注:我是用的是Waline官方2021年6月的文件,现在的版本已经有了表结构变化,具体部署的时候参照最新的来。

# 3.2 拉取并部署Waline的Docker镜像

Step1:先使用docker search命令搜索镜像,发现有原作者的官方docker镜像lizheming/waline,使用docker pull命令拉取下来。

$ docker search waline
$ docker pull lizheming/waline:latest
1
2

Step2:使用docker run命令创建实例容器并运行,与MySQL相关的参数如下表所示:

环境变量名称 必填 默认值 备注
MYSQL_HOST 127.0.0.1 MySQL 服务的地址
MYSQL_PORT 3306 MySQL 服务的端口
MYSQL_DB MySQL 数据库库名
MYSQL_USER MySQL 数据库的用户名
MYSQL_PASSWORD MySQL 数据库的密码
MYSQL_PREFIX wl_ MySQL 数据表的表前缀
MYSQL_CHARSET utf8mb4 MySQL 数据表的字符集

我配置的启动参数如下,其余启动参数详见官方文档。

$ docker run -d --name waline -p 8360:8360 \
  -v /mydocker/waline/data:/app/data \
  -e TZ="Asia/Shanghai" \
  -e MYSQL_HOST="数据库IP" \
  -e MYSQL_DB="数据库名" \
  -e MYSQL_USER="用户名" \
  -e MYSQL_PASSWORD="密码" \
  --restart always \
  lizheming/waline:latest
1
2
3
4
5
6
7
8
9

# 3.3 打开管理界面注册账号

这时用Chrome浏览器访问http://IP:8360/ui/register地址,便能看到注册界面。

Waline注册-1

如果能够成功注册账号并登录进下图所示的管理界面,就说明Waline搭建成功了。前端的访问地址为http://IP:8360

Waline注册-2

常见问题:

1)如果无法打开该注册页面,说明docker容器的启动参数配置的有问题,使用如下命令查看日志排查:

$ docker logs -f --tail 20 waline
1

2)如果打开了该注册页面,但是无法注册用户,说明docker容器启动参数里的mysql配置有问题,比如MYSQL_HOST填的不对等问题。

# 3.4 添加反向代理并开启HTTPS

使用OneinStack搭建Nginx并配置反向代理及HTTPS,具体操作步骤此处不再赘述。

此时,我们的Waline的访问地址变为了:

管理面板:https://域名/ui/
前端界面:https://域名/
1
2

# 4. 开启评论通知

当网站有用户发布评论或者用户回复评论时,Waline 支持对博主和回复评论作者进行通知。博主通知支持多种方式,包括 QQ、微信、邮件、Telegram Bot 等,回复评论作者仅支持邮件通知。

以下仅介绍我所使用的 Gmail 通知和 Telegram bot 通知的相关配置(支持的配置项没有全用),其他配置详见:评论通知官方文档 (opens new window)。如果你不想配置评论通知可直接跳过本节。

# 4.1 Telegram Bot通知

# 4.1.1 申请Telegram bot

找 BotFather 官方机器人申请自己的 Telegram Bot,需要记录下:BotName、TOKEN、CHATID等信息。

  • Step1:在Telegram中添加BotFather这个账号,然后依次发送/start,/newbot,按照提示即可创建一个新的机器人。记下来给你生成的token。(可使用/setuserpic命令更换机器人的头像)
  • Step2:搜索刚刚创建的机器人的名字,并给它发送一条消息。(注意:需要先与机器人之间创建会话,机器人才能下发消息,否则机器人无法主动发送消息)
  • Step3:在Telegram中搜索userinfobot,并给它发送一条消息,它会返回给你chatid,将它也记下来。

注:如果还不熟悉Telegram bot的使用,可以去看下我的另一篇博客:Telegram及Telegram-bot使用指南 (opens new window)

# 4.1.2 Telegram Bot通知相关配置

Telegram 通知通过 Telegram bot 机器人实现,需要配置以下几个环境变量:

  • TG_BOT_TOKEN: Telegram 机器人用于访问 HTTP API 的 token,必填。
  • TG_CHAT_ID: 接收消息对象的 chat_id,可以是单一用户、频道、群组,必填。
  • AUTHOR_EMAIL: 博主邮箱,用来区分发布的评论是否是博主本身发布的。如果是博主发布的则不进行提醒通知。
  • SITE_NAME: 网站名称,用于在消息中显示。
  • SITE_URL: 网站地址,用于在消息中显示。

# 4.2 Gmail通知

注意这里有个坑,一开始我是用的邮箱账号和邮箱密码配的,但无法实现消息通知,查看Waline日志里却提示登录失败,可账号密码都是正确的。

Gmail登录失败的Waline日志

查阅资料后得知,需要先对Gmail进行“开启IMAP”和“单独应用密码”设置,然后用单独应用密码登录。

注:出于安全性考虑,你的Gmail邮箱可能配了二级验证等安全性设置,在这里用邮箱密码可能登录不上。

# 4.2.1 Gmail开启IMAP

登录Gmail——点击设置按钮(齿轮样式)——查看所有设置——转发和POP/IMAP——启用IAMP

IMAP设置

# 4.2.2 创建Gmail的单独应用密码

登录你的 Google账号管理 (opens new window),选择”安全性“,”登录Google“模块里有个”应用专用密码设置“,点开之后选择应用、选择设备,生成一个16位的单独应用密码。

# 4.2.3 Gmail通知相关配置

Gmail邮件通知需要配置以下环境变量:

  • SMTP_SERVICE: SMTP 邮件发送服务提供商,必填。(这里填"Gmail"即可)
  • SMTP_USER: SMTP 邮件发送服务的用户名,必填。(这里填"Gmail邮箱账号"即可)
  • SMTP_PASS: SMTP 邮件发送服务的密码,必填。(这里填“Gmail的单独应用密码”即可)
  • SITE_NAME: 网站名称,用于在消息中显示。
  • SITE_URL: 网站地址,用于在消息中显示。

# 4.3 重新创建容器以实现评论通知

Step1:先停止并删除原来的Docker容器(MySQL数据库不要删)

$ docker stop waline
$ docker rm -f waline
1
2

Step2:重新创建容器应用

$ docker run -d --name waline -p 8360:8360 \
  -v /mydocker/waline/data:/app/data \
  -e TZ="Asia/Shanghai" \
  -e MYSQL_HOST="数据库IP" \
  -e MYSQL_DB="数据库名" \
  -e MYSQL_USER="用户名" \
  -e MYSQL_PASSWORD="密码" \
  -e TG_BOT_TOKEN="Telegram-Bot的Token" \
  -e TG_CHAT_ID="Telegram-Bot的CHAT-ID" \
  -e AUTHOR_EMAIL="博主邮箱账号" \
  -e SITE_NAME="网站名称" \
  -e SITE_URL="网站地址" \
  -e SMTP_SERVICE="Gmail" \
  -e SMTP_USER="Gmail邮箱账号" \
  -e SMTP_PASS="Gmail邮箱单独应用密码" \
  --restart always \
  lizheming/waline:latest
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

这时应该就可以实现 Telegram Bot 和 Gmail 的评论通知了。

# 5. 防止恶意评论

Waline自身支持的一些安全性限制感觉开启了也作用不大。实测 Akismet 反垃圾评论就是个心理安慰,屁用都没有。由于此次的恶意评论都使用了同一个IP,没有搞代理池,因此直接使用Cloudfare CDN将该IP拉入黑名单里即可解决问题。

# 5.1 Waline被恶意刷评论

我博客里使用的Waline被恶意刷评论了,从发送频率来看是脚本去刷的,会不断产生新的恶意评论,手动批量删除是没有用的。

Waline被恶意刷评论

# 5.2 尝试开启Waline自带的安全机制

Waline自带了一些安全限制机制,可以在docker run的时候通过环境变量直接将其配置上去,但个人感觉用途不大。

  • IPOPS:基于IP的评论发布频率限制,频率限制设置的太小就没啥用,设置的太大就会影响正常用户的使用。
  • AKISMET_KEY:它是Wordpress旗下的,个人版可以免费注册使用,但根本识别不出我这种情况的垃圾评论。
  • COMMENT_AUDIT:虽然将其设置上之后,审核通过后才能显示,但垃圾邮件的消息提醒还是会不断的发送。

Waline自带的安全配置

# 5.3 Cloudfare CDN将IP放入黑名单

由于此次就一个IP在刷恶意评论,因此直接将该IP放入Cloudfare CDN的黑名单了事。

  • Cloudfare CDN——Security——WAF——Custom rules——Create rule——参考如下方式填写规则(若有多个IP可采用列表)

Cloudfare-CDN配置IP拦截规则

设置了IP黑名单之后,成功的解决了此次的问题,可以看到该IP还是在源源不断的进行请求,只不过现在都被拦截掉了。

Cloudfare-CDN将IP放入黑名单

# 6. 引入Waline客户端

# 6.1 Waline前端配置

接下来就是往项目里引入Waline的前端了,具体情况具体分析,配置参数详见官方文档 Waline前端配置 (opens new window),摘录部分配置如下:

- serverURL:Waline 的服务端地址。【必填】
- el:Waline 的初始化挂载器。必须是一个有效的 CSS 选择器 或 HTMLELement 对象。【不必填】
- path:当前文章页路径,用于区分不同的文章页,以保证正确读取该文章页下的评论列表。默认值:window.location.pathname【不必填】
- lang:多语言支持,默认值: zh-CN (可选值:'zh'、'zh-CN'、'zh-TW'、'en'、'en-US'、'jp'、'jp-JP')【不必填】
- visitor:文章访问量统计。默认值: false【不必填】
- emoji:表情设置。默认值: ['https://cdn.jsdelivr.net/gh/walinejs/emojis/weibo']【不必填】
- dark:暗黑模式适配,设置为auto会根据设备暗黑模式自适应【不必填】
- meta:评论者相关属性。默认值: ['nick', 'mail', 'link']【不必填】
- requiredMeta:设置评论者属性必填项。默认值:[](即匿名)【不必填】
- login:登录模式状态,默认值:enable('enable': 启用登录、'disable': 禁用登录,用户只能填写信息评论、'force': 强制登录,用户必须注册并登录才可发布评论)【不必填】
- avatar:Gravatar头像展示方式。默认值:'mp'【不必填】
- wordLimit:评论字数限制,填入单个数字时为最大字数限制。默认值:0(即不限制)【不必填】
- pageSize:评论列表分页,每页条数。默认值:10【不必填】
- avatarCDN:设置Gravatar头像CDN地址。默认值: https://sdn.geekzu.org/avatar/【不必填】
- avatarForce:每次访问是否强制拉取最新的评论列表头像。默认值:false【不必填】
- uploadImage:自定义图片上传方法,方便更好的存储图片,方法执行时会将图片对象传入。【不必填】
- highlight:代码高亮显示。默认值:true【不必填】
- mathTagSupport:是否注入核外样式以兼容 <math> 显示,默认值:false【不必填】
- copyright:是否显示页脚版权信息。默认值true【不必填】
- placeholder:评论框占位提示符。默认值:'欢迎评论'【不必填】--即将废弃
- emojiCDN:设置表情包 CDN。默认值:https://img.t.sinajs.cn/t4/appstyle/expression/ext/normal/【不必填】--即将废弃
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

# 6.2 将Waline整合到kratos-rebirth主题

kratos-rebirth主题是一款二次元的Hexo主题,详见我的另一篇博客:搭建Hexo静态博客并使用Git部署到VPS (opens new window)

作者已经将Waline整合进去了,我们只需要修改该主题下_config.yml文件里的相关配置即可,下面是我的配置仅供参考:

# Waline [Waline](https://waline.js.org) 评论相关
## el 和 path 会在页面自动生成,不必加入
waline:
  serverURL: https://域名/    # 后端URL(必填)
  visitor: true   # 文章访问量统计
  lang: zh-CN     # 语言,默认zh-CN
  dark: auto      # 黑暗模式适配
  login: enable   # 登录模式状态,默认值enable 
  wordLimit: 0    # 评论字数限制,0为不限制,默认值为0
  pageSize: 10    # 评论列表分页,数字为条数,默认值10
  highlight: true # 代码高亮,默认true
  meta: ['nick', 'mail'] # 评论者相关属性,默认['nick', 'mail', 'link']
  requiredMeta: [] #设置评论者属性必填项,默认[](即匿名)
  placeholder: '随便说点什么喵~o(=•ェ•=)m \n没有登录也是完全没问题的哦~' # 评论框占位提示符,默认'欢迎评论'
  copyright: false # 是否显示页脚版权信息
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

修改完配置后,执行hexo cleanhexo s -g重新部署即可看到效果了,使用效果如下:

将Waline整合到kratos-rebirth主题

至此,Waline的搭建及整合已经完成啦。可以去测试一下代码块、图片上传、表情、评论嵌套、评论通知等功能是否可以正常使用,并检查后台管理功能。

# 7. 参考资料

[1] Waline快速上手 from Waline官方手册 (opens new window)

[2] Waline介绍 from Waline官方手册 (opens new window)

[3] Waline前端配置 from Waline官方手册 (opens new window)

[4] 一款基于 Valine 衍生的简洁、安全的评论系统 from Github (opens new window)

[5] 从Disqus迁移到Waline from 糖菓·部落 (opens new window)

[6] Kratos-Rebirth食用说明 from 糖菓·部落 (opens new window)

[7] Waline 评论系统部署日志 from cc的部落格 (opens new window)

[8] Hexo Next 主题使用 Waline 评论系统 from Clay的技术博客 (opens new window)

[9] docker中的MySQL修改时区 from itpub (opens new window)

[10] Gmail SMTP问题解决汇总 from CSDN (opens new window)

[11] Gmail使用应用专用密码登录 from Google官方帮助 (opens new window)

[12] Cloudflare拉黑多个IP的方式(支持批量录入)from 柴郡猫 (opens new window)

Last Updated: 10/6/2024, 5:51:58 PM