Hexo_Waline独立部署


Tags: #软件  #Hexo 
Created: 
Updated:

前言

前两天将 Valine 评论更换成了 Waline 了

为什么换 Waline?

  1. 不安全:网上很多这方面的讨论了,简而言之就是有漏洞不安全
  2. 邮件通知:官方的教程是采用 LeanCloud,在 LeanCloud 上面部署个云函数,而 LeanCloud 存在睡眠策略,云函数睡眠后基本邮件通知就 G 了,需要自己登录上去激活,或者使用脚本交激活,即便如此,使用时间也有上限,到达上限还是会强制休眠 8 小时(好像是 8 小时还是 6 小时,忘了),天下没有免费的午餐🙃,一时白嫖一时爽,人家软件策略一变更就火葬场,总而言之,我折腾了有 2 天随后放弃

上次有个咨询 Obsidian2Hexo 的网友(王某)也是更换的时候才知道,23333…
为了安全和能够接受到大家的留言(邮件通知),虽然目前没啥人,为了后续的交流,决定更换
后续就找到了 Waline,本来挺好的,这两天又觉得不是很好了😅

waline 结构:

  • 客户端:也就是博客
  • 服务端:有很多选择(vercel、云函数、服务器等等)
  • 数据库:很多选择(LeanCloud、sqlite、Mysql 等等)

对于小白来说,最友好的方式坑定就是跟着教程走,可以少走坑,又白嫖人家的服务器不舒服?🤣
结果就是上面那句话天下没有免费的午餐

其实也不算是 vercel 的问题,有一点,但不多
加载博文的时候,会发现评论会加载不出来,或者请求非常慢

可能造成的原因

  1. 网上所说的 DNS 污染

    网上说是 DNS 污染,推荐有个备案的域名去重定向到 vercel 的网址
    由于没有备案的域名的,所以没有办法尝试
    但有个免费的域名,虽然没有备案,但可以进行重定向,发现效果也不是很好
    或许没有掌握到法子?,这也是我上面提的不是 vercel 的问题,是我没有条件高攀了 2333..

  2. 服务器

    这是我个人推测,可能服务器在外国导致慢
    但个人直接访问网址还是可以的,第一点的原因可能更多一些

速度慢这就非常难受了,你看着提交的圈圈转半天,犹如度日如年,这不是折磨是啥?
我是来访者提交不了我都直接走了= =
本着顾客就是上帝,要为来访者负责的精神
刚好手头有台服务器,所以打算自建,记录下折腾的过程

因为 nodejs 不熟,其实折腾了蛮久的,少说 2 天吧
废话太多,开整~

服务端

服务端就是服务器,对提交的请求进行处理的
个人中途其实也有尝试阿里云函数部署,但不知道不知道要备案域名,部署完了,但没有域名可以指向,放弃,也算踩的一个小坑,没有备案域名的小伙伴也请忽略

个人看着独立部署的文档,一开始以为很简单 2 句命令,确实是很简单,但对没有 Node. Js 这方面知识面的小白来说,没有手把手的教程,浓缩为 2 句命令,起点与终点,就是天与地的距离

Pasted image 20230412004709
按着这个运行的的话,可以打开页面(管理端),但你会发现无法请求,无法评论
具体的表现就是写评论,点击提交按钮会提示 Failed to fetch
没有数据库,自然无法存储😑

接下来跟这我按照下面步骤走就行

  1. 下载模块
  2. 设置数据库
  3. 配置环境变量

下载模块

新建个 Waline文件夹,使用 cmd 进入后,先下载模块

yarn add @waline/vercel

没有 yarn 的话,使用 npm,不过可能会比较慢

npm install @waline/vercel

再下载个 dotenv,用于后续引入环境变量

npm install dotenv

下载后文件夹结构如下:

Waline
 ├── logs
 ├── node_modules  # 存放模块
 ├── package-lock.json 
 ├── package.json 
 └── yarn.lock

设置数据库

要决定一下使用什么数据库,在这个页面找到自己使用的数据库,如果有提供文件的话就下载下来,没有的话就需要自己建一个

并且要记下页面提供的环境,后面需要用到
例如我是使用 sqlite,那么我要将文件下载下来,还要记下下面的两个必填环境变量

Pasted image 20230412010042

将下载下来的 waline.sqlite 放在 Walien 根目录下

Waline
 ├── logs
 ├── node_modules
 ├── package-lock.json
 ├── package.json
 ├── waline.sqlite
 └── yarn.lock

如果不使用任何数据库,而是使用 LeanCloud 的话,需要记住下面的环境变量
推荐使用国外版本,国内版本需要需要为应用额外绑定已备案的域名

LEAN_ID
LEAN_KEY
LEAN_MASTER_KEY

环境变量配置

在 Waline 目录下新建个 .env,这个是环境变量的配置文件
新建后文件结构如下

Waline
 ├── .env  #这个文件
 ├── logs
 ├── node_modules
 ├── package-lock.json
 ├── package.json
 ├── waline.sqlite
 └── yarn.lock

将所使用到的数据库环境变量写进去,像上面我使用 sqlite
就是填写下面两个必填项
Pasted image 20230412010821

  • SQLITE_PATH :数据库路径
  • JWT_TOKEN :随机字符串
SQLITE_PATH=D:\systemLibrary\Desktop\Waline
JWT_TOKEN=123

如果要评论通知的话,就将下面的加进去,将 SMTP_USERSMTP_PASSAUTHOR_EMAIL 改成自己的即可
注: SMTP_PASS 不是 QQ 密码,而是授权码,网上有太多教程,这里就不展开讲了

SMTP_SERVICE=QQ
SMTP_USER=739217783@qq.com
SMTP_PASS=xxxxxxxx
SMTP_SECURE=true
AUTHOR_EMAIL=739217783@qq.com

网站名字和地址的环境变量

SITE_NAME=Hexo
SITE_URL=https://linguoguang.com

完成后如下:

SQLITE_PATH=D:\systemLibrary\Desktop\Waline
JWT_TOKEN=123
SMTP_SERVICE=QQ
SMTP_USER=739217783@qq.com
SMTP_PASS=xxxx
SMTP_SECURE=true
AUTHOR_EMAIL=739217783@qq.com
IPQPS=0
AKISMET_KEY=false
SITE_NAME=Hexo
SITE_URL=https://linguoguang.com

其他以及详细说明可以参考环境变量页面
每个变量都有详细讲解

将这个 .env 保存后,在根目录下创建一个 main.js
创建后文件结构如下

Waline
 ├── .env
 ├── logs
 ├── main.js  #这个文件
 ├── node_modules
 ├── package-lock.json
 ├── package.json
 ├── waline.sqlite
 └── yarn.lock

添加下面内容,保存关闭

const dotenv = require('dotenv'); // 引入dotenv
dotenv.config(); // 调用config方法合并.env环境变量
require('@waline/vercel/vanilla.js'); // 引入并执行该文件

上面 3 行是基础
如果要修改变量,可以直接在 main.js 添加
需要添加其他环境可以根据个人需要添加,参考下面代码进行模仿(添加)
环境变量文档:环境变量页面
例如,我对邮件的通知模板进行了修改,代码如下
注:不要直接套用,不是因为流量问题,而是个人如果有变动可能图片资源会失效,可以将相关的图片保存在服务器,然后图片链接改成自己的

const dotenv = require('dotenv'); // 引入dotenv
dotenv.config(); // 调用config方法合并.env环境变量



process.env.MAIL_SUBJECT = "{{parent.nick | safe}},『{{site.name | safe}}』上的评论收到了回复";
process.env.MAIL_TEMPLATE = `<div style="background: url(https://npm.elemecdn.com/sarakale-assets@v1/Article/email/bg2.png);padding:40px 0px 20px;margin:0px;background-color:#FFCDCE;width:100%;">
        <style type="text/css">@media screen and (max-width:600px){.afterimg,.beforeimg{display:none!important}}</style>
        <div style="border-radius: 10px 10px 10px 10px;font-size:14px;color: #555555;width: 530px;margin:auto;font-family:"Century Gothic","Trebuchet MS","Hiragino Sans GB",微软雅黑,"Microsoft Yahei",Tahoma,Helvetica,Arial,"SimSun",sans-serif;margin:50px auto;max-width:100%;background: ##ffffff;">
                <img class="beforeimg" style="width:530px;height:317px;z-index:-100;pointer-events:none" src="https://npm.elemecdn.com/hexo-butterfly-envelope/lib/before.png">
                <img src="https://npm.elemecdn.com/hexo-butterfly-envelope/lib/violet.jpg" style="width:100%;overflow:hidden;pointer-events:none;margin-top: -120px;">
                <div style="width:100%;background:#f8d1ce;color:#9d2850;background-image: -moz-linear-gradient(0deg, rgb(67, 198, 184), rgb(255, 209, 244));height: 66px;background: url(https://tva2.sinaimg.cn/large/c56b8822ly1h61tb7tagcj20ii01u3yc.jpg) left top no-repeat;display: flex;justify-content: center;flex-direction: column;">
                <p style="font-size:16px;font-weight: bold;text-align:center;word-break:break-all;margin:0;">
                您在<a style="text-decoration:none;color: #9d2850;" href="{{site.url}}">『{{site.name | safe}}』</a>上的留言有新回复啦!</p>
                </div>
                <div class="formmain" style="background:#fff;width:100%;max-width:800px;margin:auto auto;overflow:hidden;margin-bottom: -155px;">
                        <div style="margin:40px auto;width:90%;"><p>Hi,{{parent.nick}},您曾在文章上发表评论:</p>
                        <div style="background: #fafafa repeating-linear-gradient(-45deg,#fff,#fff 1.125rem,transparent 1.125rem,transparent 2.25rem);box-shadow: 0 2px 5px rgba(0, 0, 0, 0.15);margin:20px 0px;padding:15px;border-radius:5px;font-size:15px;color:#555555;">{{parent.comment | safe}}</div>
                        <p><strong>{{self.nick}}</strong> 给您的回复如下:</p>
                        <div style="background: #fafafa repeating-linear-gradient(-45deg,#fff,#fff 1.125rem,transparent 1.125rem,transparent 2.25rem);box-shadow: 0 2px 5px rgba(0, 0, 0, 0.15);margin:20px 0px;padding:15px;border-radius:5px;font-size:15px;color:#555555;">{{self.comment | safe}}</div>
                        <p>您可以点击<a style="text-decoration:none; color:#cf5c83" href="{{site.postUrl}}" target="_blank"> 查看回复的完整内容 </a>,欢迎再次光临<a style="text-decoration:none; color:#cf5c83" href="{{site.url}}" target="_blank"> {{site.name}} </a>。<hr />
                        <p style="font-size:14px;color:#b7adad;text-align:center;position: relative;z-index: 99;">本邮件为系统自动发送,请勿直接回复邮件哦,可到博文内容回复。<br />https://www.zywvvd.com</p>
                        </p>
                        <img src="https://npm.elemecdn.com/hexo-butterfly-envelope/lib/line.png" style="width:100%;margin:25px auto 5px auto;display:block;pointer-events:none">
                        <p class="bottomhr" style="font-size:12px;text-align:center;color:#999">自动书记人偶竭诚为您服务!</p>
                        </div>
                </div>
                <img class="afterimg" style="width:535px;height:317px;z-index:100;margin-left: -3px;"src="https://npm.elemecdn.com/hexo-butterfly-envelope/lib/after.png">
        </div>
</div> `;
process.env.MAIL_SUBJECT_ADMIN = "{{site.name | safe}} 上有新评论了";
process.env.MAIL_TEMPLATE_ADMIN = `<div style="background: url(https://npm.elemecdn.com/sarakale-assets@v1/Article/email/bg2.png);padding:40px 0px 20px;margin:0px;background-color:#FFCDCE;width:100%;">
        <style type="text/css">@media screen and (max-width:600px){.afterimg,.beforeimg{display:none!important}}</style>
        <div style="border-radius: 10px 10px 10px 10px;font-size:14px;color: #555555;width: 530px;margin:auto;font-family:"Century Gothic","Trebuchet MS","Hiragino Sans GB",微软雅黑,"Microsoft Yahei",Tahoma,Helvetica,Arial,"SimSun",sans-serif;margin:50px auto;max-width:100%;background: ##ffffff;">
                <img class="beforeimg" style="width:530px;height:317px;pointer-events:none" src="https://npm.elemecdn.com/hexo-butterfly-envelope/lib/before.png">
                <img src="https://npm.elemecdn.com/hexo-butterfly-envelope/lib/violet.jpg" style="width:100%;overflow:hidden;pointer-events:none;margin-top: -120px;">
                <div style="width:100%;background:#f8d1ce;color:#9d2850;background-image: -moz-linear-gradient(0deg, rgb(67, 198, 184), rgb(255, 209, 244));height: 66px;background: url(https://tva2.sinaimg.cn/large/c56b8822ly1h61tb7tagcj20ii01u3yc.jpg) left top no-repeat;display: flex;justify-content: center;flex-direction: column;">
                <p style="font-size:16px;font-weight: bold;text-align:center;word-break:break-all;margin:0;">
                您在<a style="text-decoration:none;color: #9d2850;" href="{{site.url}}"target="_blank">{{site.name}}</a>上的文章有了新的评论</p>
                </div>
                <div class="formmain" style="background:#fff;width:100%;max-width:800px;margin:auto auto;overflow:hidden;margin-bottom: -155px;">
                        <div style="margin:40px auto;width:90%;"><p><strong>{{self.nick}}</strong> 回复说:</p>
                        <div style="background: #fafafa repeating-linear-gradient(-45deg,#fff,#fff 1.125rem,transparent 1.125rem,transparent 2.25rem);box-shadow: 0 2px 5px rgba(0, 0, 0, 0.15);margin:20px 0px;padding:15px;border-radius:5px;font-size:15px;color:#555555;">{{self.comment | safe}}</div>
                        <p style="text-align:center;position: relative;z-index: 99;">您可以点击<a style="text-decoration:none;color:#cf5c83" href="{{site.postUrl}}" target="_blank">查看回复的完整内容</a></p>
                        <img src="https://npm.elemecdn.com/hexo-butterfly-envelope/lib/line.png" style="width:100%;margin:25px auto 5px auto;display:block;pointer-events:none">
                        <p class="bottomhr" style="font-size:12px;text-align:center;color:#999">自动书记人偶竭诚为您服务!</p>
                        </div>
                </div>
                <img class="afterimg" style="width:535px;height:317px;z-index:100;margin-left: -3px;"src="https://npm.elemecdn.com/hexo-butterfly-envelope/lib/after.png">
        </div>
</div>`;


require('@waline/vercel/vanilla.js'); // 引入并执行该文件

打开根目录下的 package.json
修改成如下形式,修改后保存关闭
注:在 scripts 那个对象下增加一句 start: node main.js 即可

这一步个人理解是将启动的命令 npm start 变为运行 node main.js
也就是改变了入口,将 main.js 作为我们的启动入口

{
  "dependencies": {
    "@waline/vercel": "^1.28.2",
    "dotenv": "^16.0.3",
    "pm2": "^5.3.0"
  },
  "name": "waline",
  "version": "1.0.0",
  "main": "index.js",
  "scripts": {
    "start": "node main.js"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "description": ""
}

其实到这一步就可以了,使用 cmd 进入 Waline 运行 npm start 即可
之后会提供个网址,按照这个网址登录就行了,默认是 8360 端口

如果不想每次这么麻烦,可以写个批处理
在根目录下新建个txt,内容如下

@echo off
npm start

保存后,将名字修改 a.bat 即可,之后双击运行即可

部署

因为个人没有在线的服务器可以部署,所以以上(服务端)都是个人在本地进行配置
所以还需要进行内网穿透,如果是在服务器上部署的可以忽略这里的部署

内网穿透

因为是在本地运行,所以网站根本没办法请求到这个链接
所以要进行内网穿透,简单讲就是将一个外部能访问的网址(公网)重定向到你的网址上,或者说将你的应用映射到接口上,可以被外部请求

例如:https://www.123.com 是你注册的接口域名,邮件的本地应用的网址是 localhost:8036
那么内网穿透设置后,请求 https://www.123.com 就相当于请求去 localhost:8036

内网穿透篇幅太长,这里就不展开讲了(写了也快 1 小时多了)
现成的有很多方案,可以不用自己从头搭建

  • WeNAT
  • 花生壳
  • NATAPP
  • frp
  • 等等

有非常多,免费的,付费的,因人而异
感兴趣可以自己搜索下内网穿透的教程,我目前在用 NATAPP,如果要了解下我用的也可以

NATAPP 可以参考这篇 ,讲的比较详细了,我就不再赘述了

跨域请求坑

如果你的网站域名本身是 https 协议的,那么你邮件接口的域名也必须要支持 https 协议的,否则由于浏览器的同源策略,后续会遇到跨域请求的问题,导致请求到不到服务器,评论加载不出来
控制台会报信息:Mixed Content: The page at 'https://xxx' was loaded over HTTPS

所以如果自己的网站是采用 https 的话,申请的话,切记一定要购买支持 https 的域名

网上说 http 可以采用 Nginx 进行反向代理,由于个人这方面知识面不足,所以不能展开讲
如果是已购买 http 也只能自求多福😂

Note 拓展

如果你发现自己的资源无法加载出来,浏览器按 F12, 看下控制台是否有报错:Mixed Content: The page at 'https://xxx' was loaded over HTTPS。, 这种情况就是跨域请求的问题
可以按照以下方法解决

方法一:手动更改链接协议为https

方法二:
在主题配置中配置强制全局 HTTPSFluid 主题可以参考这里
其他主题(非 Fluid 主题)如果没有类似的配置开关的话,就用方法一,手动更换下协议

注:
两者设置的请提都需要域名本身支持 HTTPS!
要不设置也无效

客户端

客户端也就是 Hexo,就没有啥好说了,在各自的主题里配置

如果主题不支持的话,就需要将 Waline 的页面代码插入到你模板文件里面去,需要一定的前端能力
主题大家都用的是不同的,所以插入的位置大家也不同,这种只能自己折腾和上网查看有没有前例
插入代码如下(插入文件自己确定,每个主题布局文件都不同)

<head>
  <!-- ... -->
  <link
    rel="stylesheet"
    href="https://unpkg.com/@waline/client@v2/dist/waline.css"
  />
  <!-- ... -->
</head>
<body>
  <!-- ... -->
  <div id="waline"></div>
  <script type="module">
    import { init } from 'https://unpkg.com/@waline/client@v2/dist/waline.mjs';

    init({
      el: '#waline',
      serverURL: 'https://your-domain.vercel.app',
    });
  </script>
</body>
  • head 头部引入 Waline 样式: https://unpkg.com/@waline/client@v2/dist/waline.css
  • 下面的 init 是初始化,serverURL 填写你服务端的网址

像个人是使用 Fluid 主题,配置就很简单,打开主题配置文件 _config.fluid.yml

找到评论插件,将 type 修改成waline

# 评论插件
# Comment plugin
comments:
enable: true
# 指定的插件,需要同时设置对应插件的必要参数
# The specified plugin needs to set the necessary parameters at the same time
# Options: utterances | disqus | gitalk | valine | waline | changyan | livere | remark42 | twikoo | cusdis | giscus
# type: disqus
type: waline

找到 waline 配置项将 serverURL 修改成个人服务端的域名即可

# Waline
# 从 Valine 衍生而来,额外增加了服务端和多种功能
# Derived from Valine, with self-hosted service and new features
# See: https://waline.js.org/
waline:
  serverURL: xxxxxxxxxxxxx
  placeholder: 遗憾莫过于难忘你的背影,却找不到你来过的痕迹 ...
  path: window.location.pathname
  meta: ['nick', 'mail', 'link']
  requiredMeta: ['nick']
  avatar: "retro"
  lang: 'zh-CN'
  emoji: ['https://unpkg.com/@waline/emojis@1.1.0/weibo']
  dark: 'html[data-user-color-scheme="dark"]'
  wordLimit: 0
  pageSize: 10