写这篇文章之时恰逢中秋佳节之际,祝各位朋友中秋快乐!

我的博客自从2022年就已经建好,但是基本没有写很多东西在上面,搭建之初只是为了方便而使用了gitalk来作为评论系统。但这个开源项目的评论是基于github的issue来实现,虽然数据也是存储在自己的仓库并且免费。但是由于github在国内的网络环境下时好时坏,大部分情况下无法正常加载。而从个人博客评论功能的需求出发我主要归结为以下两点:

  • 加载迅速,不因为没有科学上网工具而无法使用
  • 数据安全,也即数据自己可以操控在自己的存储系统里面最好
  • 支持匿名评论,因为我不想让别人看个blog还要进行繁琐的登录

这个时候刚好看到了一个叫做Artalk的开源项目,使用go语言编写号称轻量便捷并且它还在正常更新,拓展性高,可以本地化部署,正好满足我的需求。

部署

环境:Ubuntu 22.04

正确部署姿势

artalk/artalk-go
#### **域名解析**
到你域名解析供应商处添加Artalk的域名解析记录如
```comment.example.cn```指向你的服务器地址


#### **nginx配置和安装ssl证书**

在nginx.conf里面添加如下server块:
```nginx
server {
listen 443 ssl;
server_name comment.nighterdream.cn;
ssl_certificate /etc/letsencrypt/live/comment.nighterdream.cn/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/comment.nighterdream.cn/privkey.pem; # managed by Certbot


ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers 'HIGH:!aNULL:!MD5';
ssl_prefer_server_ciphers on;

location / {
proxy_pass http://localhost:8081; # Artalk 运行的地址和端口
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;
}

}

其中证书由Cerbot生成, 至于为什么要反向代理请看下面曲折经历

  1. 安装 Certbot 和 Nginx 插件
    首先,需要安装 Certbot 和它的 Nginx 插件。如果你使用的是 Ubuntu 或其他基于 Debian 的系统,使用以下命令:
sudo apt update
sudo apt install certbot python3-certbot-nginx
  1. 运行 Certbot 自动化命令
    运行以下命令,Certbot 将自动为你的域名生成证书,并更新 Nginx 配置以启用 SSL:
sudo certbot --nginx

根据提示进行输入信息

  1. 测试 Nginx 配置
    证书生成并配置完成后,重新加载 Nginx 以应用更改:
sudo nginx -t
sudo systemctl reload nginx

Hexo配置

以butterfly主题配置为例,打来主题配置文件_config.butterfly.yml找到评论配置部分修改以下内容

artalk:
server: https://comment.example.cn # 你设置的Artalk服务端域名
site: example # 在Artalk配置中设置
visitor: false
option:

记得把评论功能打开,并且切换成Artalk

# Comments System
# --------------------------------------

comments:
# Up to two comments system, the first will be shown as default
# Choose: Disqus/Disqusjs/Livere/Gitalk/Valine/Waline/Utterances/Facebook Comments/Twikoo/Giscus/Remark42/Artalk
use: # Valine,Disqus
- Artalk
text: true # Display the comment name next to the button
# lazyload: The comment system will be load when comment element enters the browser's viewport.
# If you set it to true, the comment count will be invalid
lazyload: true
count: false # Display comment count in post's top_img
card_post_count: false # Display comment count in Home Page

Artalk配置

这个使用就可以通过https://comment.example.cn访问Artalk的后台评论管理系统了

  1. 设置Artalk后台管理员账号
    虽然能够访问了却需要账号和密码,在Artalk容器部署端执行:
docker exec -it artalk artalk admin

Artalk文档

  1. 设置可信域
    添加以下内容,实际就是设置请求头内容防止跨域问题产生
    http://comment.example.cn 防止国产浏览器无法加载,请参看国产浏览器的坑
    https://comment.example.cn

  2. 配置站点
    这里的站点要和docker run 里面的yoursite对应,同时也要和你的hexo 主题配置文件里的site对应

  3. 根据自己配置灵活进行,建议开启验证码,防止匿名评论轰炸消耗服务器资源,参考官方配置文档

总结

完成以上操作之后就可以hexo clean; hexo g; hexo d来推送博文了
在配置Artalk过程中自己也是踩了很多的坑,局域网内证书注册,还有就是国产浏览器的坑,很多问题都是一开始没有发现,实际操作中才能认识到,特别是国产浏览器无法重定向,估计又是C2C(copy to China)的锅,希望官方能够改一改。很多问题也都是在官方文档和错误日志中找到答案和解决办法,看日志的能力也是得到了一次提升。

曲折经历

局域网的坑

我的博客部署在一台阿里云的服务器上,它的容量很小,所以的构想是将Artalk部署在本地的物理主机上,然后通过frp穿透出去。可是这个想法是好的在实际操作过程中却发现了问题。 我的博客为了安全采用了https协议传输数据,但是Artalk默认使用http在我部署好了之后我发现无法正常加载博客评论,打开浏览器终端发现是由于https和http不匹配造成的。之后我仔细查阅了Artalk的官方文档里面写道:
可以开启ssl加密传输
加密传输 ssl

ssl:
enabled: true
cert_path: ''
key_path: ''
你可以配置该项,让 HTTP 升级为 HTTPS,通过 SSL 协议加密传输数据。

cert_path:SSL 证书公钥文件路径。
key_path:SSL 证书私钥文件路径。
你也可以直接反向代理 Artalk 本地服务器,然后在例如 Nginx 启用 HTTPS。

这时候就存在问题了我的Artalk是通过docker部署的而在docker 容器内安装证书显然不是一个很好的选择,我就剩下了另一个选择就是通过nginx反向代理Artalk服务器,但是这个时候就又存在了一个问题,**本地局域网内的物理机如何申请证书?**因为我是采用frp实现内网穿透的,所以申请证书基本可以宣告破产。
之后我想了一个办法,那就是把我服务器上使用certbot申请的证书给复制到我的局域网内的物理主机上,可结果确是不行,浏览器提示证书和域名不匹配,无法加载远程服务器资源,所以之后我将Artalk又使用docker部署到了我的阿里云服务器,并使用cerbot申请了证书,使用nginx将artalk本来的http反向代理成https,这似乎所有问题都得到了解决了我的博客的评论可以正常加载了,直到我发现了一个国产浏览器的坑。

国产浏览器的坑

nginx设置了将http请求重定向到https时,国产浏览器无法生效
我在博客评论系统部署好并测试好没有问题之后就可高枕无忧,专注到内容的书写上。可当我姐来我家,我让她用她手机访问我博客时却发现了问题,她使用手机的夸克浏览器没法加载评论,这个时候我没太放在心上,可能是一个概率问题。但后面我发了一篇博文到微信上,用微信自带的qq浏览器也提示评论加载错误我这个时候才意识到不是偶尔的问题,而确实存在bug,我本人一共使用三款浏览器分别是:firefox, chrome, edge测试都没有发现任何问题,这个时候我下载了一个QQ浏览器,这个时候提示跨域问题了。
这就让我很不解了我在Artalk(Artalk设置了另外的域名,博客的评论是从artalk的网址加载评论数据,所有需要跨站请求)里面设置可信域:https://www.nighterdraem.cn, https://nighterdream.cn
因为只有国产浏览器才无法加载评论所以我询问了chatgpt

为什么我的Artalk评论系统在国产浏览器中会遇到跨域问题,在edge和chrome中却能正常使用

以下是我的nginx配置
server {
listen 443 ssl;
server_name comment.nighterdream.cn;
ssl_certificate /etc/letsencrypt/live/comment.nighterdream.cn/fullchain.pem; # managed by Certbot
ssl_certificate_key /etc/letsencrypt/live/comment.nighterdream.cn/privkey.pem; # managed by Certbot


ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers 'HIGH:!aNULL:!MD5';
ssl_prefer_server_ciphers on;

location / {
proxy_pass http://localhost:8081; # Artalk 运行的地址和端口
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;
}

}
跨域问题(CORS,Cross-Origin Resource Sharing)在国产浏览器中可能会导致 Artalk 评论系统无法正常使用,而在 Edge 和 Chrome 中可以正常使用,原因可能与不同浏览器处理 CORS 的方式有关。以下是可能的原因和解决方案:

### 可能原因
1. **国产浏览器的安全策略差异**:国产浏览器(如 QQ 浏览器、360 浏览器等)有时会对跨域请求进行更加严格的处理,而国际浏览器如 Chrome 和 Edge 可能会对开发中的应用更宽容,特别是对于本地服务器或 HTTP 请求。

2. **CORS 头缺失**:你的 Nginx 配置中没有明确设置 CORS 相关的响应头,这可能导致国产浏览器拒绝跨域请求。

3. **代理转发的 Headers 问题**:Artalk 的跨域配置可能没有正确传递给浏览器。国产浏览器可能严格要求返回正确的跨域响应头。

### 解决方案
1. **在 Nginx 中添加 CORS 头**:你可以在 Nginx 的配置中添加允许跨域的响应头,确保浏览器能够正确处理跨域请求。

你可以在 `location` 块中添加如下 CORS 配置
location / {
proxy_pass http://localhost:8081;
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;

# 添加跨域响应头
add_header Access-Control-Allow-Origin *;
add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS';
add_header Access-Control-Allow-Headers 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';
add_header Access-Control-Expose-Headers 'Content-Length,Content-Range';
}

这将允许所有源对你的服务器进行请求。如果你想限制特定的源,可以将 `Access-Control-Allow-Origin` 的值替换为特定的域名。

2. **确保 Artalk 支持 CORS**:检查 Artalk 的配置文件或后端设置,确保它支持跨域请求。Artalk 可能需要配置允许的 `Origin`,确保它支持通过反向代理的跨域请求。

3. **OPTIONS 请求的处理**:有时候浏览器会发送预检请求(OPTIONS 请求)以确认服务器是否允许跨域访问。你可以在 Nginx 中为 `OPTIONS` 请求添加一个单独的处理:
if ($request_method = OPTIONS) {
add_header Access-Control-Allow-Origin *;
add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS';
add_header Access-Control-Allow-Headers 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';
return 204;
}

4. **检查浏览器控制台的错误信息**:如果问题依然存在,可以在国产浏览器中打开开发者工具,查看具体的错误信息,确认是哪个请求遇到了 CORS 问题。

通过添加这些 CORS 设置,应该可以让国产浏览器与 Edge 和 Chrome 一样正常访问你的 Artalk 评论系统。

我按照他的建议进行了更改,但之后我发现连edge和chrome都无法加载了,查看请求头:

HTTP/1.1 200 OK
Server: nginx/1.18.0 (Ubuntu)
Date: Mon, 16 Sep 2024 09:44:16 GMT
Content-Type: application/json
Content-Length: 731
Connection: keep-alive
X-Request-Id: 001151ae-c7f7-4002-945b-748a1af32112
Vary: Origin
Access-Control-Allow-Origin: https://www.nighterdream.cn
Access-Control-Allow-Origin: https://www.nighterdream.cn
Access-Control-Allow-Methods: GET, POST, OPTIONS
Access-Control-Allow-Headers: DNT,User-Agent,X-Requested-With,
If-Modified-Since,Cache-Control,Content-Type,Authorization,Range
Access-Control-Expose-Headers: Content-Length,Content-Range

问题出在了
Access-Control-Allow-Origin的值出现了两次https://www.nighterdream.cn
所以连edge和chrome也无法打开,原因是我在artalk的可信域里面进行了配置(应用层),然后在nginx里面又进行了配置(代理层),所以Access-Control-Allow-Origin
也就重复了导致edge无法打开,但神奇的是国产浏览器又能打开评论了,之后我将nginx配置中恢复了原样取消手动设置请求头。

这个时候我打开了QQ浏览器的开发者控制台发现如下报错:

Access to fetch at 'https://comment.nighterdream.cn/api/v2/conf' 
from origin 'http://nighterdream.cn' has been blocked by CORS policy:
No 'Access-Control-Allow-Origin' header is present on the requested resource.
If an opaque response serves your needs, set the request's mode to 'no-cors'
to fetch the resource with CORS disabled.

这就很奇怪了为什么是http://nighterdream.cn而不是我设置的可信域https://nighterdream.cn
然后我就在QQ浏览浏览器的导航栏输入:http://nighterdream.cn来访问我的网站,正常情况下我设置了nginx的http重定向https,浏览器应该会自动将导航栏上的地址改成https://nighterdram.cn,但是QQ浏览器没有。之后我又测试了edge,chrome浏览器发现他们都能重定向到https所以能够加载评论。
而QQ浏览器,夸克浏览器移动端,微信浏览器为代表的国产浏览器没有重定向而是继续使用http来访问,这也就造成了请求头里的Access-Control-Allow-Origin字段值和Artalk后端的https://nighterdream.cn不匹配,所以才无法加载评论,而我将Artalk的可信域里面加入http:nighterdream.cn后问题也就迎刃而解。

参考资料

Artalk文档

Artalk自托管评论系统搭建与配置

跨源资源共享(CORS)

什么是反向代理?|代理服务器介绍