# 1. Waline简介
Waline 是一款从 Valine 衍生的带后端评论系统,可以将 Waline 等价成 With backend Valine。—— Waline 官网的介绍
Waline同时具有Valine的轻量和后端管理的方便两大特性,并且提供了简单方便的Serverless部署方案,遵循轻量化、集约化设计思路的指导,支持邮件通知、Telegram通知、QQ通知及微信通知接口的接入,提供大量可自定义参数接口。
启用 Waline 即可为诸如Hexo、Hugo、Gitbook这样的静态网站提供评论与浏览量服务。
# 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版本(客户端要与服务端一致)
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
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:设置校对集
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;
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容器
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 */;
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
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
2
3
4
5
6
7
8
9
# 3.3 打开管理界面注册账号
这时用Chrome浏览器访问http://IP:8360/ui/register
地址,便能看到注册界面。
如果能够成功注册账号并登录进下图所示的管理界面,就说明Waline搭建成功了。前端的访问地址为http://IP:8360
。
常见问题:
1)如果无法打开该注册页面,说明docker容器的启动参数配置的有问题,使用如下命令查看日志排查:
$ docker logs -f --tail 20 waline
2)如果打开了该注册页面,但是无法注册用户,说明docker容器启动参数里的mysql配置有问题,比如MYSQL_HOST填的不对等问题。
# 3.4 添加反向代理并开启HTTPS
使用OneinStack搭建Nginx并配置反向代理及HTTPS,具体操作步骤此处不再赘述。
此时,我们的Waline的访问地址变为了:
管理面板:https://域名/ui/
前端界面:https://域名/
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进行“开启IMAP”和“单独应用密码”设置,然后用单独应用密码登录。
注:出于安全性考虑,你的Gmail邮箱可能配了二级验证等安全性设置,在这里用邮箱密码可能登录不上。
# 4.2.1 Gmail开启IMAP
登录Gmail——点击设置按钮(齿轮样式)——查看所有设置——转发和POP/IMAP——启用IAMP
# 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
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
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被恶意刷评论了,从发送频率来看是脚本去刷的,会不断产生新的恶意评论,手动批量删除是没有用的。
# 5.2 尝试开启Waline自带的安全机制
Waline自带了一些安全限制机制,可以在docker run的时候通过环境变量直接将其配置上去,但个人感觉用途不大。
- IPOPS:基于IP的评论发布频率限制,频率限制设置的太小就没啥用,设置的太大就会影响正常用户的使用。
- AKISMET_KEY:它是Wordpress旗下的,个人版可以免费注册使用,但根本识别不出我这种情况的垃圾评论。
- COMMENT_AUDIT:虽然将其设置上之后,审核通过后才能显示,但垃圾邮件的消息提醒还是会不断的发送。
# 5.3 Cloudfare CDN将IP放入黑名单
由于此次就一个IP在刷恶意评论,因此直接将该IP放入Cloudfare CDN的黑名单了事。
- Cloudfare CDN——Security——WAF——Custom rules——Create rule——参考如下方式填写规则(若有多个IP可采用列表)
设置了IP黑名单之后,成功的解决了此次的问题,可以看到该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/【不必填】--即将废弃
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 # 是否显示页脚版权信息
2
3
4
5
6
7
8
9
10
11
12
13
14
15
修改完配置后,执行hexo clean
、hexo s -g
重新部署即可看到效果了,使用效果如下:
至此,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)