阅读视图

发现新文章,点击刷新页面。

图片为啥用 Base64 格式进行传输

在互联网的世界里,图片传输是再平常不过的事情了,而 Base64 格式常常出现在这一过程中。那为啥图片要用 Base64 格式来传输呢?这背后有不少门道。本文将介绍 Base64 格式的应用场景和优点,以及一些应用场景下的缺点。

Base64 是什么

Base64 是种用 64 个可打印字符来表示二进制数据的编码方法。这 64 个字符含大小写字母各 26 个,还有 10 个数字以及两个符号。

例如,当我们看到一串像 SGVsbG8gV29ybGQh 这样的字符,这就是 Base64 编码后的结果,其实代表了 Hello World!

易于文本传输

在很多网络传输场景中,尤其是早期的网络应用,传输通道主要被设计为传输文本数据。

因为文本数据格式相对简单、统一,而且不容易出现乱码等问题。

而图片是二进制的数据,直接传输二进制数据可能会因为不同系统、不同软件对二进制数据的处理方式不同而出现问题。

Base64 把图片的二进制数据转换成了文本形式。这样一来,通过电子邮件、网页表单等主要以文本传输为主的渠道时,图片就可以顺利跟着文本一起传输了。

比如,在发送带有图片附件的电子邮件,邮件系统会把图片转换成 Base64 格式,然后和邮件的正文一起发送。

接收方收到邮件后,邮件客户端再把 Base64 格式的数据转换回图片,这样我们就能看到图片。

兼容性好

不同的操作系统和不同的软件应用对数据处理方式可能存在差异。Base64 编码后的文本数据在各种平台都能被正确识别和处理。

例如,一个在 Windows 系统上生成的 Base64 编码的图片数据,在 Linux 服务器上也能轻松解码并还原成图片,不用担心因为平台不同而出现数据损坏或者无法读取的情况。

几乎所有的编程语言都有内置的库或者函数来处理 Base64 编码和解码。这使得开发人员在开发涉及图片传输的应用程序时,能够很方便使用 Base64 格式。

比如,在一个基于 Python 的 Web 应用,开发人员可以使用库轻松地将图片文件读取并编码为 Base64 格式,然后通过网络发送给服务器或客户端。

方便在网页中嵌入图片

在网页设计中,如果一个网页中有大量的小图标或小图片,每次加载这些图片都需要发送一个 HTTP 请求。

这不仅会增加服务器的负担,还会影响网页加载速度。

而将这些小图片转换为 Base64 格式后,可以直接将 Base64 编码的数据嵌入到 HTML 或 CSS 文件中。

这样浏览器在加载 HTML 或 CSS 文件的时候,就可以直接读取到图片数据,而不需要单独发送 HTTP 请求去获取图片,从而提高了网页的加载效率。

嵌入 Base64 格式的图片还可以简化网页的结构。不需要在网页文件目录中单独存放这些小图片文件,减少了文件管理复杂性。

对于一些简单的网页应用或前端框架,这种方式非常实用。

安全性的考虑

虽然 Base64 编码不能算是真正的加密方法,但它在一定程度上可起到隐藏信息的作用。

因为对于不了解 Base64 编码的人来说,看到一串 Base64 编码的数据可能不知道它代表的是图片内容。

在一些对安全性要求不是特别高的场景下,可作为一种简单的保护措施。

比如,在一些内部文档分享系统中,把图片转换 Base64 格式传输,可防止非授权用户轻易地获取到原始图片文件。

在某些情况下,直接传输二进制图片文件可能会带来安全风险,如图片文件可能被恶意篡改,包含恶意代码。

将图片转换为 Base64 格式后,这些恶意代码在 Base64 编码文本环境中很难被执行,从而降低安全风险。

缺点

不过,Base64 传输图片也有其缺点。比如,Base64 编码后数据量比原始的二进制图片数据要大,大概会增加百分之三十三左右的大小。

所以在传输大图片或者对带宽要求很高的场景,可能需要权衡下是否使用 Base64 格式。

本博出现图碎问题说明

近期本博访问时出现了图碎问题,经排查系 CDN 回源失败导致的。有小伙伴可能会说,保证成功就可以修复了,其实没有那么简单。本文简单描述下存储节点数据流,顺便科普一下如何清理单站数据缓存。

数据流向

通过下图可以看出,图片文件保存在主机上,通过转换处理为 WebP 格式文件,经由 CDN 回源并实现访问加速:

问题分析

登录 CDN 管理后台查看其日志,发现出现超时记录。

超时原因一般两种,一种是因线路问题导致回源超时,一种是因主机没有及时返回数据造成。

本地图片经由 WebP 中间件处理,再回源给 CDN 做反代,经查是 WebP 服务突然宕机导致 CDN 未收到响应数据导致超时。

除超时问题外,因无返回数据导致 CDN 响应 404,而服务器设置 404 默认跳转至主站首页,这就导致好多小伙伴频繁刷新页面依然不显示图片。

解决方案

目前已关闭 CDN,流量直接回源至源主机,缺点就是会影响访问的速度。带调试维护后会重新挂上 CDN。

WebP 图片转换是为了减少图片体积,进而减轻带宽压力「轻量级服务器有流量的限制」因此不能暂停使用,已修改其参数,尽量保障响应的成功率。

如之前有访问记录,会留下 404 跳转缓存,需要清理相关数据。

有小伙伴分享了两种清理缓存的方法,需要的小伙伴可以参考操作。

清理缓存

首先进入到浏览器的开发者工具,一般浏览器点击F12即可,进入更多设置,勾选 Disable cache while DevTools is open 项:

或者切换到网络标签页,勾选禁用缓存,刷新页面即可「注意保持开发者工具一直处于开启的状态」

Hugo 渲染超时问题的解决笔记

hehe 童鞋选择将所有的站点托管到杜老师这「是收费的」这样就可以专心维护网站的内容,也不用费心思在运维上。在做站点迁移时遇到了 Hugo 框架的一个报错,原因是使用 Hugo 搭建相册网站需要遍历大量图片,而在生成站点文件时出现了超时问题,本文记录解决方法。

报错信息

1
2
3
ERROR render of "page" failed: "/home/runner/work/photo/photo/themes/gallery/layouts/_default/single.html:3:5": execute of template failed: template: _default/single.html:3:5: executing "main" at <partial "gallery.html" .>: error calling partial: partial "gallery.html" timed out after 30s. This is most likely due to infinite recursion. If this is just a slow template, you can try to increase the 'timeout' config setting.
Total in 60412 ms
Error: error building site: render: failed to render pages: render of "page" failed: "/home/runner/work/photo/photo/themes/gallery/layouts/_default/single.html:3:5": execute of template failed: template: _default/single.html:3:5: executing "main" at <partial "gallery.html" .>: error calling partial: partial "gallery.html" timed out after 30s. This is most likely due to infinite recursion. If this is just a slow template, you can try to increase the 'timeout' config setting.

注意:杜老师是通过 GitHub Actions 来部署,逻辑是先准备 Hugo 的运行环境,再根据站点的数据渲染站点文件。在生成站点文件时出现如上错误信息。

解决思路

从错误信息看,Hugo 网站在渲染页面时出现了问题,具体是 gallery.html 这个 partial 文件在执行时超时了,并且怀疑是由于无限递归导致的。

首先检查 gallery.html 中代码。无限递归问题可能是 gallery.html 中调用了自身,或者在调用其它 partial 时形成了循环。仔细检查文件,确保没有递归调用自己或其它可能导致循环的部分。

其次检查数据结构。如果 gallery.html 中依赖某些数据结构,可能是数据结构中存在循环引用。例如,某个对象或者列表在渲染时不断递归调用。

再次增加超时时间。如果确认不是无限递归问题,而是模板渲染确实很慢,可以尝试增加超时时间。在 Hugo 的配置文件中,增加 timeout 配置项,如 timeout = '60000'

然后优化模板性能。如果模板渲染确实很慢,可能是模板的代码过于复杂。可以尝试优化模板代码,减少不必要循环和复杂逻辑。

接着调试模板。使用 Hugo 的调试工具来逐步检查模板的执行过程。可通过在模板中添加日志输出来帮助调试。

再者检查依赖插件。如果网站使用第三方插件或依赖,可能是插件导致了问题。尝试禁用插件,看看能否解决问题。

最后检查 Hugo 的版本。确保使用的 Hugo 版本是最新的。旧版本可能存在已知的 bug,而新版本可能已修复了这些问题。

宝塔面板-V免签支付系统搭建教程:个人开发者收款解决方案(含2开源码)

V免签支付系统介绍

V免签(PHP) 是基于 Thinkphp5.1 + mysql 实现的一套免签支付程序,主要包含以下特色:

  1. 收款即时到账,无需进入第三方账户,收款更安全
  2. 提供示例代码简单接入
  3. 超简单 Api 使用,提供统一 Api 实现收款回调
  4. 免费、开源,无后门风险
  5. 支持监听店员收款信息,可使用支付宝微信小号/模拟器挂机,方便 iOS 用户
  6. 免 root,免 xp 框架,不修改支付宝/微信客户端,防封更安全

V免签官方源码:https://github.com/szvone/vmqphp

V免签安卓监控端:https://github.com/szvone/VmqApk

演示环境基于 宝塔面板 搭建,使用 nginx1.18、php7.4、mysql5.6 已实测该环境正常搭建可用

  • V免签的运行环境为PHP版本 >=5.6。

宝塔面板-V免签支付系统搭建教程
宝塔面板-V免签支付系统搭建教程

宝塔面板部署V免签支付系统教程

  1. 下载V免签压缩包,上传至服务器并解压

  2. 关闭防跨站攻击,设置运行目录为 public 并保存

宝塔面板-网站目录-运行目录
宝塔面板-网站目录-运行目录

  1. 设置伪静态为thinkphp并保存

宝塔面板-伪静态设置
宝塔面板-伪静态设置

  1. 设置默认文档,将index.html放在第一行并保存(这里改完顺序,点击添加就是保存)

宝塔面板-默认文档设置
宝塔面板-默认文档设置

  1. 打开网站路径/config/database.php ,设置好你的 mysql 账号密码并保存

V免签支付系统数据库设置
V免签支付系统数据库设置

  1. 导入数据库文件 vmq.sql 到服务器里

数据库导入V免签数据文件
数据库导入V免签数据文件

  1. 至此网站搭建完毕,请访问后自行修改配置信息!默认后台账号和密码均为 admin

V免签支付系统演示图

前台演示图

V免签支付系统前台演示图
V免签支付系统前台演示图

后台演示图

V免签支付系统后台演示
V免签支付系统后台演示

V免签支付系统后台演示-系统设置
V免签支付系统后台演示-系统设置

V免签支付系统后台演示-监控端设置
V免签支付系统后台演示-监控端设置

V免签监控端设置

V 免签监控端:该软件是基于 V 免签开发一款免 root 和框架 Android 收款监听软件,功能为监听支付宝和微信收款消息与服务端进行交互,若匹配当前时间段服务端有同金额订单将会把收到的金额消息进行回调!达到监听通知栏收款消息回调完成支付业务。该版本主要修复了原版监控的支付宝和微信不回调的 BUG,优化代码写法。删除沉余代码加快启动速度,增加电池白名单权限,使软件在电池优化时不会被杀掉!增加 Log 监听回调面板与店员监听。V免签现已更新 PC 端监控。

下载地址

付费图片
付费图片
限时优惠
宝塔面板-V免签支付系统搭建教程:个人开发者收款解决方案(含2开源码)
为尊重作者劳动成果,此处内容已隐藏,请购买查看内容
10
限时特惠
输入邮箱即可查询订单,跳转支付则为未查询到订单(邮箱只用于订单使用,不会发送内容到邮箱,虚拟产品售出不退!!!)
已有0人解锁查看
输入邮箱即可查询订单,跳转支付则为未查询到订单(邮箱只用于订单使用,不会发送内容到邮箱,虚拟产品售出不退!!!)
付费阅读
已售 0
隐藏内容

V免签Android监控端设置

使用Android手机安装APK,点击扫码配置 - 扫描V免签监控端设置的二维码即可配置完成

V免签二开源码

运行环境 Nginx1.1.5 以上 PHP5.6-7.3 Mysql5.6以上

  1. 网站目录->运行目录 设置为public并保存
  2. 伪静态 设置为thinkphp并保存
  3. 打开网站目录 config/database.php ,设置好您的mysql账号密码
  4. 导入数据库文件(位于根目录)pay.sql到您的数据库
  5. 至此网站搭建完毕,请访问/houtai后自行修改配置信息!默认后台账号admin和密码123456
  6. 后台登录入口在route/route.php,找到’houtai’修改即可
  7. 在后台里设置首页跳转地址,不设置跳转到默认地址
  8. 配置邮箱信息和支付宝商户号
  9. 使用免挂或者软件监控,使用免挂需要配置回调监控
  10. 建议把当前站点的网站防火墙关了,以防被拦截

下载地址:包含源码与监控挂机软件

付费图片
付费图片
限时优惠
宝塔面板-V免签支付系统搭建教程:个人开发者收款解决方案(含2开源码)
为尊重作者劳动成果,此处内容已隐藏,请购买查看内容
10
限时特惠
输入邮箱即可查询订单,跳转支付则为未查询到订单(邮箱只用于订单使用,不会发送内容到邮箱,虚拟产品售出不退!!!)
已有0人解锁查看
输入邮箱即可查询订单,跳转支付则为未查询到订单(邮箱只用于订单使用,不会发送内容到邮箱,虚拟产品售出不退!!!)
付费阅读
已售 0
隐藏内容

V免签WordPress插件

V免签WordPress插件

  • ✅关闭订单(2024年11月4日)

  • ✅收款返回文章页面,并显示隐藏内容(2023年11月4日)

  • ✅界面上面的文字可以自定义(2023年11月4日)

  • ✅金额可以在文章中自定义设置,如果不设置则显示默认金额(2023年11月7日)

  • ✅订单显示在后台(2023年11月7日)

  • ✅支付金额可以自动填入(2023年11月9日)@格子老师

  • ✅3款主题切换

V免签代部署服务

有源码不会装?懒癌发作,手不听使唤?瞌睡上头思想无法集中?昨晚酒还没醒?

如果您有以上疑难杂症,点这里就对了,发挥你的钞能力,一键解君愁!

服务内容:

  • 您无需准备以上所需源码,提出要求就好!
  • 带安装对接以上支付接口!
  • 您只需提供服务器信息、域名信息、收款二维码即可!

v免签 代安装搭建服务

Artalk 评论工具登录功能使用及反馈收集

Artalk 默认只需填写昵称和邮箱即可发表评论,无需验证邮箱。但有时候,我们希望用户能够使用社交账号登录,以减少用户填写信息的时间,或者提高用户信息的真实性,故此杜老师决定开启社交登录来实现这一目的。

写在最前

作为 Artalk 的内测用户,杜老师第一时间启用了社交登录功能。

近期也会收到一部分小伙伴反馈,说看到登录按键后不太习惯。

这里说明一下启用邮箱密码登录功能后仍然可跳过邮箱验证,登录弹窗底部显示跳过按钮,点击后评论框顶部恢复为显示原有的昵称、邮箱、网址。

另外已经向 Artalk 作者反馈相关建议,期待后期升级更多功能。

同时希望小伙伴们积极提供建议,这边都会第一时间反馈给 Artalk 作者,以满足大家的需求。

本站后期也会对接各大社交平台,目前仅支持用邮箱登录。

食用教程

在启用邮箱密码登录后,评论框顶部的昵称邮箱输入框将隐藏,发送按钮将显示为登录按钮。当用户点击登录按钮后,会弹出一个登录框,用户可输入邮箱和密码登录,登录成功即可发表评论:

用户可以通过邮箱注册账号,将向用户邮箱发送一封带有验证码的邮件。验证码有效期为 10 分钟,验证码发送频率限制 1 分钟一次:

登录后如果检测到相同邮箱下有多个不同用户名的账号,将会弹出账号合并工具,用户可选择保留其中一个用户名,该邮箱下的所有评论等数据合并到保留账号下,而原有的账号将被删除,评论显示的用户名将会变更为保留用户名:

用户发表的评论将展示「邮箱已被验证」标识:

支持同时启用多种登录方式,用户可以选择任意一种方式登录:

如果只启用了唯一一种登录,如 GitHub 登录,将直接弹出 GitHub 授权登录页面:

同款说说页面部署代码分享

在一帮小伙伴的帮助下,杜老师终于完成了对说说页面的美化。对此颇有感概,不会前端是真不行,但就是学不会。该代码匹配 Volantis,可自适应夜间模式,感兴趣的可以尝试部署,有问题就不要问了,杜老师也不会~

特性

  1. 统计用户所发说说条数;

  2. 显示用户头像;

  3. 显示用户昵称;

  4. 显示平台的用户名;

  5. 支持大图显示;

  6. 可一键至说说广场进行评论。

效果

正常的浏览效果如下图:

夜间模式的浏览效果如下图:

代码

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
<link href="https://npm.onmicrosoft.cn/penndu@13.0.0/memos/css/style.css" rel="stylesheet" type="text/css">
<link href="https://npm.onmicrosoft.cn/penndu@13.0.0/memos/css/highlight.github.min.css" rel="stylesheet" type="text/css">
{% p center logo large, 点图片可放大! %}
<section id="main" class="container">
<div class="total">Total <span id="total">0</span> Memos 🎉</div>
<div id="memos" class="memos">
</div>
</section>
<script type="text/javascript">
var memos = {
host: 'https://s.dusays.com/',
limit: '10',
creatorId: '1',
domId: '#memos',
username: 'penn',
name: 'Teacher Du',
}
</script>
<script type="text/javascript" src="https://npm.onmicrosoft.cn/penndu@13.0.0/memos/js/lazyload.min.js?v=17.8.3"></script>
<script type="text/javascript" src="https://npm.onmicrosoft.cn/penndu@13.0.0/memos/js/marked.min.js?v=11.1.1"></script>
<script type="text/javascript" src="https://npm.onmicrosoft.cn/penndu@13.0.0/memos/js/view-image.min.js?v=2.0.2"></script>
<script type="text/javascript" src="https://npm.onmicrosoft.cn/penndu@13.0.0/memos/js/moment.min.js?v=2.30.1"></script>
<script type="text/javascript" src="https://npm.onmicrosoft.cn/penndu@13.0.0/memos/js/moment.twitter.js"></script>
<script type="text/javascript" src="https://npm.onmicrosoft.cn/penndu@13.0.0/memos/js/highlight.min.js?v=11.9.0"></script>
<script type="text/javascript" src="https://npm.onmicrosoft.cn/penndu@13.0.0/memos/js/main.js"></script>
<script>hljs.highlightAll();</script>

注意:如果不是 Volantis 主题需删除{% p center logo large, 点图片可放大! %}所在行。

使用

请根据需求修改对应的内容:

参数说明
host域名
limit每页显示条数
creatorId用户的 ID
domId显示位置
username广场的用户名
name昵称

说说广场资源转存至缤纷云

杜老师最近太忙了,平时也是撒手掌柜,很少管理旗下平台,除非遇到问题才会第一时间解决。恰好昨天下午得空看了一下说说广场,没想到超过了百人。图片加载速度好慢,就想着托管到其它平台!

什么是 S3

S3 存储是亚马逊推出的一种对象存储服务。提供了一个高度可扩展、可靠且安全的数据存储解决方案,用于存储和管理各种类型的数据对象,例如文件、图像、视频、文档。

使用了 S3 存储,用户可以通过 API 或与 S3 兼容的工具来上传、下载、检索、管理数据对象。S3 还支持数据版本控制、生命周期管理、数据备份和恢复等功能。

Bitiful 缤纷云

缤纷云的界面是非常简洁的,而且还挺好看,概述页面可以看到资源的使用量:

缤纷云每月会赠送 50G 的存储容量,CDN 流量 10G,API 请求 10 万次。具体费用可见官方文档:

整合说说

下面说说整合过程。首先注册登录到缤纷云,切换到对象存储 AccessKey 页面,点击右侧的添加 Key,根据流程填写对应内容即可:

进入到 Memos 后台,点击设置——存储——创建,参考下图输入相关内容「杜老师做了些调整,如果效果不太理想,可以在评论区留言询问」

使用体验

有一说一,加载速度还是非常快的,毕竟是专业的存储加 CDN。不过并发请求貌似有些问题,每次批量加载都会出现很多请求失败问题。不过还好不影响前端的调用:

杜老师的网站访问速度快吗

闲着没事分析了一下博客的留言,在四万多条留言里,其中有超过一百条说杜老师博客访问速度喜人,想了解下如何做的。今天为小伙伴们分享一下杜老师说的架构,以及优化建议~

数据分布

当您访问杜老师说,正在阅读一篇图文搭配教程,并准备留言时。您正在访问如下四个资源库:

资源解释

网站源码。杜老师使用 Hexo 静态框架,这意味着该网站的所有页面都是预先生成的静态 HTML 文件,而不是动态生成的。访问该网站时,直接获取这些静态网页资源,而不需要再查询数据库。这种做法可以极大减少响应延迟,从而提高网站的加载速度和性能:

图片外链。大量图片托管与去不图床同节点服务器中,方便管理同时,通过自建 CDN 节点加速了访问速度,同时避免与源码站同服务器导致抢占带宽。之所以与去不图床外链地址不同,是因为加入了 WebP 自动转换中间件,节约流量同时,提升加载速度,等同变相增加线路带宽:

评论系统。采用 Artalk 评论系统 Docker 部署方式,其使用 Go 语言构建后端,快速处理数据同时,还使用异步处理的方式,加速评论提交过程。同时采用 Redis 预缓存,Artalk 启动后直接将数据缓存至内存,无需再查询数据库,可以极大减少响应延迟:

开源镜像。全站的 JS 及部分 CSS 资源均引用开源镜像站,感谢 Zkeq 童靴提供公益 CDN 加速平台,既稳定又高速。同时号召小伙伴们不要滥用公益资源,细水长流才能长长久久,境内可用的公益资源越来越少了,希望该平台可长久运营:

优化建议

  1. 主机选择。境外主机的平均带宽比境内的主机高,但境外主机延迟都不低,且数据中心的距离越远,则丢包率越高。故在不考虑带宽情况下,尽量选择境内主机,唯一的限制就是备案了,这是一个硬性门槛,各位站长酌情考量;

  2. 程序选择。静态的肯定比动态的框架快,但有些小伙伴偏爱 WordPress/Typecho 这类的框架,可以安装静态生成插件,进而减少数据库的查询次数,变相减少响应延迟。还要注意的是,不要安装太多插件,因为每次加载页面都会遍历所有插件,插件越多遍历时间越久;

  3. 服务优化。经调查小伙伴们用的云主机普遍配置较低,建议选择 Nginx 作引擎,可以的话推荐使用编译安装最新版本,这个杜老师做过测试的,编译的更稳定且效率高。MySQL 最好 5.7 版本,8.0+适用分布式,性能提升是通过牺牲配置实现的,主机 6G 以下的无法发挥 8.0+版本的性能优势。PHP 肯定是版本越高越好,但需要程序支持才可以。主机内存充足的情况下可以通过 Redis/Memcached 缓存减少数据库查询次数「优先选 Redis」

  4. 站外调用。条件允许的情况下,尽可能的调用站外资源,如 JS/CSS,减少服务器请求数量的同时,还可以避免与网站同服务器导致抢占带宽。墙裂推荐杜老师的去不图床,各大动态博客框架都有对应插件,方便上传管理,自建 CDN 保障稳定及速度。头一次在文章里挂广告推自己的图床,还有一点脸红~

文章推荐

优化云主机的性能确实是一个重要的考虑因素,尤其是在托管大量图片和资源时。很多小伙伴喜欢用某塔面板,很久前杜老师写了一篇《云主机的极致优化》感兴趣的可以看下。虽然文章比较久远,但依旧有参考价值。

只有榨干云主机的性能,才能将性能最大化。关于安装所需的软件和服务,确实需要注意不要过度配置。每个额外的服务或应用程序都可能增加服务器的负担并可能导致性能下降。因此,仔细评估每个应用程序的必要性和其对系统资源影响是很重要的。

比如去不图床安装了 WAF,则每次访问时,先通过 WAF 过滤,才会进行请求处理,经测试会产生 100 毫秒左右的延迟。这是一个值得注意的点,尤其是对于高流量的网站或对性能要求较高的应用。虽然 WAF 可提供安全保护,但这种延迟可能对用户体验产生影响。

如果您感觉杜老师说访问速度不快,那就当杜老师上面的都没说~

友情链接的那些事

首先打个欠条,之前答应写一篇 OpenWrt 教程,奈何杜老师突然因工作安排出差,身边没有实验设备,故只要推迟更新了。这篇文章主要聊一下杜老师对友情链接的看法,其中一些策略可能会影响到后期友链运营!

先聊成绩

本博客创建于 2019 年 7 月 10 日,截止该文章发布时,已存在的友链 166 条,其中全站链接 27 条,首页链接 13 条,余下皆为内页链接。

而这 166 条链接,除了继承菜鸟博客那不超过十条友链之外,其余都是被动链接「由他站主动发起的友链申请」

当然其中还有一些友链,是友站建立好后未声明,后期回访时主动发现的,这类站点杜老师会及时上链,保障互动~

友链鼎盛时期,则达到了 207 条,部分站点的友链因无故断链、无法访问等情况而下链。

回顾前文

友链较多,维护起来也很麻烦。

杜老师会定期检查每个友链对应站点可访问性,及本站的友链是否存在,是否更换展示位置等等。

虽说有脚本工具的帮助,但因为博客框架及主题的多样性,很多站点仍需手动检测,这样就占用了杜老师很多时间和精力。

为此杜老师曾编写一篇友链规则文章《关于友情链接的一些事》里面详细描述了杜老师对友链的要求。

遇到问题

杜老师可以很自信的说,没有几个人按照该规则申请链接!

一上来就丢链接的仍然很多,不过比较友善的是都提前做好了杜老师说链接。

不过突然关站、故障博客比比皆是,杜老师每每遇到都会发邮件通知,并提供相关的技术支持,有些博主因上学等一些原因无法及时处理,导致站点长时间的不可访问,搞的杜老师只要做下链处理。

这里很多小伙伴会有所疑问,为什么一遇到不可访问,就立即下链呢?简单为大家介绍下某度引擎索引机制。

杜老师说权重尚可,每天都会吸引数千蜘蛛爬取数据,而遇到无法访问资源时,蜘蛛会降低杜老师说的权重,且对无法访问资源的 URL 做降权甚至是 K 站处理。所以说立即下链是保护站点一种方式。

当然大家找不到自己的链接,也不需要担心,在友链申请页面说明情况就好了,杜老师看到后,也会第一时间恢复上链。

一些想法

不知道有多少的小伙伴做过来源分析,会发现绝大多数的访问流量,都来自于其他博主。大众访客一般都会通过社交平台获取所需要的数据,我们这类博客只有同为博客圈的站长才会乐此不疲。

而互访就是最有效活跃博客的方式了。杜老师添加很多的友链,会定期采集各站的最新文章,尽可能的第一时间送上热评,在活跃气氛的同时,也在其它站点留下本站一丝身影。这也是为什么经常有小伙伴会说:怎么哪里都有杜老师呢?

但是久而久之,杜老师发现很多站点的博主互动性差「从不回访」有些站点久不更新。所以杜老师决定后期会调整友链策略,达到硬性的要求后再考虑做友链。同时屏蔽部分互动性差站点资源采集,这样可以有更多的精力仔细拜读大佬们的文章,以留下更多的热评。

之后建站时间低于一年的请不要主动申请链接,杜老师不清楚您建站是一时兴起,还是长远打算。

一个月及以上未更新的博客也请不要主动申请链接,且已友链的可能会随时下链,杜老师不清楚您是没有时间还是跑路。

第一次来本站的小伙伴也请高抬贵手不要主动申请链接,本站不是您宣传的平台,请不要降低了杜老师互访的热情,谢谢!

杜老师说方向调整

最近一直在水文章,偶尔还会托更。除了最近比较忙碌之外,更多的是不知道该更新点啥。和小伙伴聊了一下,决定调整一下杜老师的主题方向,也希望大家可以提一些建议!

语音部分

需要手动点击播放:

文字部分

今天,这个博文就以语音的形式去发布。然后,会将这个语音转换成文字的形式,方便喜欢看文字的小伙伴去浏览阅读。懒得看字,您可通过听语音的形式。

杜老师今天为大家分享内容,主要是想说下,杜老师说调整了一下主题的方向。原因比较简单:实在不知道该写点什么好了。

大家应该知道,杜老师说每三天会更新一次。会给大家伙分享一些技术方面的内容,有的时候会根据一些小伙伴的兴趣和建议,分享一些跟杜老师生活相关事情。

但是最近,一直在拖更且水文,很多小伙伴已经开始抱怨了。当然有一部分原因,是因为杜老师还是比较懒的,拖延症吧!

今天这个文章本来想打字说明的,但是懒得打字,打算录音,然后通过一些工具将音频转换成文字的形式跟小伙伴们进行分享。并且在此之前,也没有说先写文稿,然后再去录制,所以说会有很多的废话或者是口头语之类,这个也希望大家理解吧。

我们的话题说回来,说下方向。之前也给各位小伙伴介绍过,杜老师说是个人的技术博客,主要就是为我的学员去分享技术文章,让他们在上课的过程中,不需要把过多的精力放在记录笔记上。这样他们上课可以认真听课,下课可以在我的博客上获得笔记。

后期我已经不做培训讲师的这个工作,转向了公司的另外一个讲师,算是。职责上发生了一些变化。所以说就导致了并不需要将我自己的博客推向我的学员,这个平台就单纯的变成一个技术、资源,还有就是生活类分享的一个平台。

未来打算做一些简单的调整。因为分享一些,比如说运维方向的一些知识,很多小伙伴们可能不是特别的感兴趣。甚至是不需要,很多小伙伴们来了之后都是表示不明觉厉,他们遇到的问题更多是喜欢直接在评论区下面留言,然后获得直接帮助。

这种方式是很高效。所以说感觉没有必要去分享这类资源。当然以后有些更好的技术或者是服务的话,也会给各位小伙伴们进行这种教程上分享,主要还是想着改成这种,比如说一些有趣的工具,或是生活类的。

所以说未来主题的方向,会逐渐面向生活类,面向有趣工具,或者是一些实用性的东西来分享。会发现很多小伙伴,都是跟杜老师一样,是博主是站长,他们希望通过这一类的资源,尽可能的去丰盈自己的博客,然后带来更多流量。

使得自己博客的功能更加的健全,所以未来可能更加注重这个方向。但是有一点就是杜老师作为一个单纯的运维工程师,并不会开发代码也不会前端。

所以大家可以看到,杜老师说是非常的简洁。并没有一些酷炫的效果,只不过在功能方面,相对来说够用。也是要感谢之前有很多小伙伴对杜老师的帮助,在这里呢,就不一指名道谢了。

最后想说一下关于未来主题方向,这个也是杜老师刚刚想到的,跟其他的小伙伴也聊过,然后他们也给杜老师提供了一些建议。

当然这些还是比较片面,也希望能看到此文章一些小伙伴,给杜老师提供更多建议,这个平台的受众是访客。希望能迎合着访客的兴趣口味去经营杜老师说。

后期还是会继续保持着每三天一更的频次,尽可能的不要再出现水文了。实在懒得打字。那我就发语音。

实际上发语音比打字要轻松的多,毕竟杜老师做这方面的工作多年了吧,所以很多话都是在嘴边,不需要过脑直接就可以说出来的。

并不需要太多文稿,可以跟大家聊半天,只不过有些小伙伴应该也听出来,杜老师的口音还是比较重的,尤其是平翘舌不分。

表达的时候就会出现这种特别的情绪所在,导致大家可能听着有些别扭,这个我慢慢去调整,慢慢纠正,但是做这个行业比较久,回想一下,杜老师已经当老师十年之久,所以说不太容易改。

除了资源还有生活分享之外。未来还会推出一些公益性的活动,大家在这块如果有什么需求的话,也可在评论区留言,我看到一些比较合理的需求,也会加入到托管的项目,但是大家请不要太过于期待。

我们还是需要有一定的成本保障,目前的去不图床啊,它本身是一个公益,奈何后期有大量的恶意用户,包括受到过一些攻击造成了巨大的运营成本。

所以没办法最终改成了收费,很多小伙伴也找我细聊。有些小伙伴注意到,我们博客圈里还是有一些就是年纪比较轻,对于他们来说,可能一个月的零花钱也没有多少,但是更多的还是一些成年人,对于他们来说,这都不到一包烟的价格,所以他们还是建议我提升去不图床的价格。

但是思前想后还是没有合理定价标准,所以目前还是保持现状。目前这个阶段,杜老师的工资收入可以很好的支撑住去不图床成本。

后期在不超过一定阈值的情况下,杜老师就算是亏本也会持续运营,不能支撑住的时候,会提前跟各位小伙伴们说的,绝对不会突然跑路,请小伙伴放心。

好了,前前后后叭叭了差不多十分钟了,我们今天聊到这里,后期大家如果对这种语音形式感兴趣的话,也请留言告诉给杜老师。拜拜!

杜老师说旗下服务调整回源策略

经常光顾本站的小伙伴都很清楚,杜老师使用家中服务器对外提供服务。因家用宽带会封禁 80 等端口,借助 CDN 的端口回源功能,可使用户通过域名直接访问杜老师说旗下服务,但经常会遇到回源问题。点击进入本文听杜老师细聊!

回源问题

首先我们使用去不图床举例,说明下之前的网络连接拓扑。

内网的服务器是树莓派,映射端口分别为 80 和 443,通过软路由转换为可用端口,再使用 CDN 端口回源反代加速。

优点是网络节点少,效率较高。缺点是家用带宽会变动地址,需要经常调整 CDN 的回源地址。

之前杜老师通过 DDNS,加 DNSPod 付费服务「TTL 最低值」解决回源地址变动问题。

但是会有一段时间无法访问,原因还是出现在回源地址的解析上面。

新地址获得后,需要等待一段时间,才会同步到 DDNS。而 CDN 本地解析缓存时间较长,导致无法及时获取到新地址,就造成了回源失败。

内网穿透

为了加快地址变更后的回源生效速度,杜老师决定改为使用内网穿透的方式解决这一问题。

内网穿透是种网络技术,它允许局域网内的设备通过互联网与外部网络通信。这种技术通常用于家庭、办公室或其它内部网络环境,其中设备的 IP 地址是私有的,无法直接与公共互联网通信。

内网穿透的基本原理是通过在公共互联网上创建一个代理服务器,该服务器充当内部网络与外部网络之间的中介。当内部网络中的设备需与外部网络通信时,它会将数据发到代理服务器,然后由代理服务器将数据转发到目标设备。同样,当外部设备需与内部设备通信时,代理服务器会将数据发送到内部设备。

内网穿透的主要应用场景包括:远程访问、远程办公、游戏服务器及私有云服务等。

工具选择

在众多内网穿透工具中,杜老师选择 frp。

frp 是一个专注于内网穿透的高性能的反向代理应用,支持 TCP/UDP/HTTP/HTTPS 等多种协议,且支持 P2P 通信。可以将内网服务以安全、便捷的方式通过具有公网 IP 节点的中转暴露到公网。

工具特点

  1. 客户端服务端通信支持 TCP/QUIC/KCP 以及 Websocket 多种协议;

  2. 采用 TCP 连接流复用,在单个连接间承载更多请求,节省连接建立时间,降低请求延迟;

  3. 代理组间负载均衡;

  4. 端口复用,多个服务通过同一个服务端端口暴露;

  5. 支持 P2P 的通信形式,流量不经过服务器中转,充分利用带宽资源;

  6. 多个原生支持的客户端插件,便于独立使用 frp 客户端完成某些工作;

  7. 高度扩展的服务端插件系统,易于结合自身需求进行功能扩展;

  8. 服务端和客户端 UI 页面。

服务部署

从官网页面下载软件包,解压其中的 frps 及 frps.ini 文件,并上传至服务端/opt/目录「可上传至任意目录,但影响到下面服务配置路径」编辑 frps.ini 文件并添加 token 项「等号右侧的值可自定义,与客户端相同」

1
2
3
[common]
bind_port = 7000
token = dusays.com

使用 systemd 控制 frps 的运行状态及配置开机自启,运行命令 vim /etc/systemd/system/frps.service 并添加下面代码,即可通过 systemctl start frps 启动 frp,使用命令 systemctl enable frps 配置 frps 开机自启:

1
2
3
4
5
6
7
8
9
10
11
12
13
[Unit]
# 服务名称,可自定义
Description = frp server
After = network.target syslog.target
Wants = network.target

[Service]
Type = simple
# 启动frps的命令,需修改为您的frps的安装路径
ExecStart = /opt/frps -c /opt/frps.ini

[Install]
WantedBy = multi-user.target

客户部署

从官网页面下载软件包,解压其中的 frpc 及 frpc.ini 文件,并上传至客户端/opt/目录「可上传至任意目录,但影响到下面进程守护管理器的运行路径」编辑 frpc.ini 文件并添加以下内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
[common]
server_addr = 123.123.123.123
server_port = 7000
token = dusays.com

[web]
type = tcp
local_ip = 127.0.0.1
local_port = 80
remote_port = 8780

[web2]
type = tcp
local_ip = 127.0.0.1
local_port = 443
remote_port = 8443

杜老师使用的宝塔面板,安装了进程守护管理器插件,按照如下的配置即可运行客户端:

来自杜老师的求助信息

眼看着博客的周年庆就快过去了,杜老师一直心想着大改框架,但是苦于找不到一款好程序,在此发布求助信息,希望小伙伴们可以帮忙推荐一些程序,满足杜老师的框架需求。

目前现状

目前 Hexo 的插件加 Volantis 附加功能可以满足杜老师说呈现需求,现期正在静候 Volantis 新版本更新,短期内不会有较大变动。不过有个比较大的问题,就是页面生成时间太长,平均每次部署都需要十分钟:

手中资源

目前杜老师具有 WordPress 两款付费主题,分别是知更鸟和大前端「知更鸟见下图」

具有 Typecho 一款付费主题,是 handsome「handsome 见下图」

具有 Halo 一款付费主题,是 PandaPro「PandaPro 见下图」

还有一些其它资源,在这里就不一一说明了「大前端见下图」

选型问题

WordPress 是杜老师之前用过的框架,其臃肿性被杜老师鄙夷,所以打算不再使用这款框架。

Typecho 是目前观望一款框架,程序轻量、主题完善、插件健全,如果实在没得选可能用该款。

Halo 是杜老师十分看好的一款框架,但其无法自定义 URL,加上数据的保存形式暂不做选择。

除以上几款外,其它程序暂未发现心仪主题,但考虑 Hexo 部署时间太长,不得已也要取舍了!

框架需求

  1. 首先支持高定制 URL,即可以设置每篇文章的访问地址,为的是使现有文章访问地址不变「必选」

  2. 高度兼容 Markdown 的语法,可以更加方便导入 Hexo 的文章,当然不支持没关系,大不了逐一复制也可以;

  3. 如支持数据库,希望可选数据库支持 MySQL,可以直接修改数据,不要那种 blob 类型的;

  4. 如是静态框架,希望可以技术成熟,满足上述要求同时还能快速部署。如是动态框架,希望可以是轻量级。以上均不考虑付费问题!

下一代静态博客框架 Valaxy

杜老师一直在找 Hexo 替代框架,因为杜老师说博客文章量比较多,站点页面生成速度太慢,经晓雨童靴的推荐,了解到 Valaxy 框架。本文介绍 Valaxy 的特点,以及部署方式,感兴趣的小伙伴可以尝试下!

框架介绍

Valaxy 的目标是成为新一代静态博客框架与生成器。提供更好热更新与用户加载体验、更强大更便捷自定义开发可能性。支持配置、文章的热更新,而不像 Hexo 一样重新加载页面。

它与 Hexo 相比开发体验和速度上都更胜一筹,且与 VitePress/VuePress 相比拥有更多针对博客的集成功能,譬如文章列表钩子、自动路由、组件注册、可覆盖的布局与主题等。

Valaxy 基于 Vite 提供热更新与打包功能,基于 Vue 实现视图等客户端的功能。因此 Valaxy 兼容并可自由使用 Vite 与 Vue 生态所有插件。

Valaxy 已经默认集成 Open Graph 的 SEO 优化。需要注意的是,对于许多搜索引擎来说,它们可能只青睐 SSG 构建模式。

部署过程

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
67
68
penn@penn-PC:~/Desktop$ sudo npm i -g pnpm
请输入密码:
验证成功

added 1 package in 13s

1 package is looking for funding
run `npm fund` for details
penn@penn-PC:~/Desktop$ npm init valaxy
Need to install the following packages:
create-valaxy@0.14.30
Ok to proceed? (y)

🌌 Valaxy v0.14.30

Project name: … valaxy-blog
📁 /home/penn/Desktop/valaxy-blog

Scaffolding project in valaxy-blog ...
Done.

✔ Install and start it now? … yes
✔ Choose the agent › pnpm
Downloading registry.npmjs.org/typescript/4.8.4: 11.9 MB/11.9 MB, done
Packages: +435
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Packages are hard linked from the content-addressable store to the virtual store.
Content-addressable store is at: /home/penn/.local/share/pnpm/store/v3
Virtual store is at: node_modules/.pnpm
node_modules/.pnpm/vue-demi@0.14.5_vue@3.3.4/node_modules/vue-demi: Running postinstall script, done in 119ms
Progress: resolved 457, reused 0, downloaded 435, added 435, done
node_modules/.pnpm/esbuild@0.17.19/node_modules/esbuild: Running postinstall script, done in 73ms

dependencies:
+ valaxy 0.14.30
+ valaxy-theme-yun 0.14.30

devDependencies:
+ typescript 4.8.4 (5.1.3 is available)

 WARN  Issues with peer dependencies found
.
├─┬ valaxy 0.14.30
│ └─┬ vite-ssg 0.22.2
│ └── ✕ unmet peer critters@^0.0.16: found 0.0.17 in valaxy
└─┬ valaxy-theme-yun 0.14.30
└─┬ valaxy-addon-waline 0.1.0
└── ✕ unmet peer valaxy@latest: found 0.14.30

Done in 1m 34.2s

> valaxy-blog@0.14.30 dev /home/penn/Desktop/valaxy-blog
> valaxy

ℹ Resolve valaxyConfig from /home/penn/Desktop/valaxy-blog/valaxy.config.ts 03:31:05
ℹ Resolve siteConfig from /home/penn/Desktop/valaxy-blog/site.config.ts 03:31:05
ℹ Resolve valaxy.config.ts from theme(yun) 03:31:05
ℹ Resolve addons: 03:31:06

🌌 Valaxy v0.14.30

🪐 theme > yun
📁 /home/penn/Desktop/valaxy-blog

Preview > http://localhost:4859/
Network > http://192.168.36.141:4859/

shortcuts > restart | open | edit

注意:官方推荐使用 pnpm 来部署,所以杜老师第一步安装了 pnpm。另外在 Choose the agent 一步,需要选 pnpm。完成 Valaxy 的部署后会自动运行,默认端口号 4859。

博客更新

如需发布文章,进入到博客根目录的 pages/posts,新建.md 文件就行了,内容结构如下:

1
2
3
4
5
6
7
8
9
10
11
---
title: Title
hide: true
excerpt_type: text
---

这是摘要

<!-- more -->

这是正文

参数作用详见下表:

参数作用阈值
title文章标题暂无
hide临时隐藏某篇文章当设置为 true 或 all 时,文章仍然会被渲染,可以直接访问链接进行查看。但不会被显示在展示的文章卡片与归档中;当设置为 index 时,将只在首页隐藏归档中仍然展示。
excerpt_type预览列表摘要渲染类型md 展示原始 Markdown;html 以 HTML 的形式展示;text 以纯文本的形式展示。

从 Hexo 迁移

Hexo 博客目录与 Valaxy 博客目录对应的关系如下,将相关的内容复制至对应文件夹即可:

用途HexoValaxy
文章source/_postspages/posts
页面sourcepages
静态资源sourcepublic

托管部署

  1. GitHub Pages: 在创建模版项目时,已内置文件 .github/workflows/gh-pages.yml 以实现 GitHub Actions 的自动部署工作流。

  2. Netlify: 已内置 netlify.toml。

  3. Vercel: 将 Framework Preset 设置为 Other,并更改 Build and Output Settings,将 Output Directory 设置为 dist 后点击 Deploy。

  4. Cloudflare Pages: 点击创建应用程序——连接到 Git,然后选择点击开始设置,将构建输出目录设置为 dist 后添加一个环境变量。变量名称设置为 NODE_VERSION,阈值为 16.0,最后点击保存并部署就行了。

使用体验

杜老师将已发布的 590 篇文章迁移到 Valaxy,仅需 20 秒即可生成站点页面文件,而通过 Hexo 则需要 8 分钟「大概是因为杜老师说使用了太多插件」

不过毕竟是新型的框架,目前主题及插件比较少,并不足以满足杜老师的使用需求,想折腾的小伙伴可以尝试下,杜老师也在坐等着更多模板。

说说广场代码分享

首先感谢下林木木童鞋,参考他的代码才有此篇教程,效果可以参考本博说说广场。杜老师不擅长前端,如有更好样式,欢迎在评论区提出建议。本教程样式不兼容所有博客模板,如有错位等问题的出现,可在评论区中留言!

准备工作

此篇教程兼容各类博客框架,不管用的是 Hexo/Hugo/Typecho/WordPress 都可直接使用。

若无服务器可以不用搭建 Memos,借助现有平台「如杜老师的 https://s.dusays.com」注册账户即可。

广场代码

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
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
<script>
if (typeof Lately === 'undefined') {
const script = document.createElement('script');
script.src = 'https://jsd.onmicrosoft.cn/gh/Tokinx/Lately/lately.min.js';
script.onload = () => {
Lately.init({ target: '.bbs-date' });
};
document.head.appendChild(script);
} else {
Lately.init({ target: '.bbs-date' });
}
const urls = [
{home:"https://s.dusays.com/",host:"https://s.dusays.com/",apiV1:'v1/',creatorId:"1",comment:'',imgsrc:"https://cravatar.cn/avatar/28b57baa4e8f13fe4292ccb2de267e30"},
{home:"https://s.dusays.com/",host:"https://s.dusays.com/",apiV1:'v1/',creatorId:"70",comment:'',imgsrc:"https://bu.dusays.com/2023/07/13/64b00b0a2586c.png"}
]
var bbDom = document.querySelector('#bbs');
var load = '<div id="load" onclick="nextFetch()" ><button class="load-btn button-load">加载更多</button></div>'
var loading = '<div class="loader"><svg class="circular" viewBox="25 25 50 50"><circle class="path" cx="50" cy="50" r="20" fill="none" stroke-width="2" stroke-miterlimit="10"/></svg></div>'
var bbsDatas = [],bbsData = {},nextDatas = [],nextData = {},limit = 2
var page = 1,offset = 0,nextLength = 0,nextDom='',bbUrlNow = '',imgsrcNow = '',hostNow = '',creIdNow = '',commentNow = '',twiEnvNow='',artEnvNow='',artSiteNow=''
bbDom.innerHTML = loading
allUrls()
function allUrls(){
var myHtml = ''
for(var i=0;i < urls.length;i++){
myHtml += '<div class="bbs-urls bbs-url" onclick="urlsNow(this)" data-hostid="'+urls[i].host+"u/"+urls[i].creatorId+'" data-host="'+urls[i].host+'" data-apiV1="'+urls[i].apiV1+'" data-creatorId="'+urls[i].creatorId+'" data-imgsrc="'+urls[i].imgsrc+'" data-comment="'+urls[i].comment+'" data-home="'+urls[i].home+'" data-twienv="'+urls[i].twiEnv+'" data-artenv="'+urls[i].artEnv+'" data-artsite="'+urls[i].artSite+'" data-index="'+i+'"><img src="'+urls[i].imgsrc+'" alt=""></div>'
}
myHtml += '<div class="bbs-urls urls-button" onclick="urlsNow(this)" data-type="random"><svg t="1665928089691" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2562" width="32" height="32"><path d="M913.2 672l98.8 57.1c5.3 3.1 5.3 10.8 0 13.9l-43.4 25L710.4 924c-2.7 1.5-6-0.4-6-3.5V772c0-2.2-1.8-4-4-4H544c-70.4 0-134.4-28.8-180.8-75.2-11.1-11.1-21.2-23.2-30.1-36.1-6.4-9.2-20-9.1-26.4 0.1C260.5 723.9 183.1 768 96 768h-48c-26.5 0-48-21.5-48-48s21.5-48 48-48h48c42.5 0 82.6-16.7 112.9-47.1 30.4-30.4 47.1-70.5 47.1-112.9s-16.7-82.6-47.1-112.9C178.6 368.7 138.4 352 96 352h-48c-26.5 0-48-21.5-48-48s21.5-48 48-48h48c70.4 0 134.4 28.8 180.8 75.2 11.1 11.1 21.2 23.2 30.1 36.1 6.4 9.2 20 9.1 26.4-0.1 46.3-67 123.6-111.1 210.8-111.1H700.4c2.2 0 4-1.8 4-4V103.4c0-3.1 3.3-5 6-3.5l258.2 156 43.4 25.1c5.3 3.1 5.3 10.8 0 13.9L913.2 352 710.4 476c-2.7 1.5-6-0.4-6-3.5V356c0-2.2-1.8-4-4-4H544c-42.5 0-82.6 16.7-112.9 47.1-30.4 30.4-47.1 70.5-47.1 112.9 0 42.5 16.7 82.6 47.1 112.9C461.4 655.3 501.5 672 544 672H700.4c2.2 0 4-1.8 4-4V551.4c0-3.1 3.3-5 6-3.5L913.2 672z" p-id="2563" fill="#f5f5f5"></path></svg></div>'
myHtml += '<div class="bbs-urls urls-button"><a href="https://s.dusays.com/"><svg t="1665929410343" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="6308" width="32" height="32"><path d="M906.212134 565.732986 565.732986 565.732986 565.732986 906.212134C565.732986 926.013685 541.666486 959.972 511.97312 959.972 482.297674 959.972 458.213254 926.013685 458.213254 906.212134L458.213254 565.732986 117.734106 565.732986C97.950475 565.732986 63.97424 541.666486 63.97424 511.97312 63.97424 482.279754 97.950475 458.213254 117.734106 458.213254L458.213254 458.213254 458.213254 117.734106C458.213254 97.950475 482.297674 63.97424 511.97312 63.97424 541.666486 63.97424 565.732986 97.950475 565.732986 117.734106L565.732986 458.213254 906.212134 458.213254C925.995765 458.213254 959.972 482.279754 959.972 511.97312 959.972 541.666486 925.995765 565.732986 906.212134 565.732986Z" p-id="6309" fill="#f5f5f5"></path></svg></a></div>'
myHtml = '<div id="bbs-urls">'+myHtml+'</div>'
bbDom.insertAdjacentHTML('beforebegin', myHtml);
}
function nextFetch(){
document.querySelector("button.button-load").textContent= '加载中……';
updateHTMl(nextDatas)
if(nextLength < 10){
document.querySelector("button.button-load").remove()
return
}
getNextList()
};
function urlsNow(e){
var domUrls = document.querySelectorAll('#bbs-urls .bbs-urls')
if(e.classList.contains('url-now')){
domUrls[e.getAttribute("data-index")].classList.remove("url-now")
fetchBBser()
}else{
domUrls.forEach(function(value,index){ domUrls[index].classList.remove("url-now")})
var btn = document.querySelector('button.button-load')
if(btn){btn.remove()}
page = 1,offset = 0
bbDom.innerHTML = loading
var type = e.getAttribute("data-type")
if(type == 'random'){
var num = Math.round(Math.random() * (urls.length-1))
hostNow = urls[num].host
creIdNow = urls[num].creatorId
imgsrcNow = urls[num].imgsrc
commentNow = urls[num].comment
twiEnvNow = urls[num].twiEnv
artEnvNow = urls[num].artEnv
artSiteNow = urls[num].artSite
homeNow = urls[num].home
apiV1Now = urls[num].apiV1
domUrls[num].classList.add("url-now")
}else{
domUrls[e.getAttribute("data-index")].classList.add("url-now")
hostNow = e.getAttribute("data-host")
creIdNow = e.getAttribute("data-creatorId")
imgsrcNow = e.getAttribute("data-imgsrc")
commentNow = e.getAttribute("data-comment")
twiEnvNow = e.getAttribute("data-twienv")
artEnvNow = e.getAttribute("data-artenv")
artSiteNow = e.getAttribute("data-artsite")
homeNow = e.getAttribute("data-home")
apiV1Now = e.getAttribute("data-apiV1")
}
bbUrlNow = hostNow+"api/"+apiV1Now+"memo?creatorId="+creIdNow+"&rowStatus=NORMAL&limit=10"
fetch(bbUrlNow).then(res => res.json()).then( resdata =>{
var arrData = resdata || ''
if(resdata.data){
arrData = resdata.data
}
bbDom.innerHTML = ''
bbsDatas.length = 0
for(var j=0;j < arrData.length;j++){
var resValue = arrData[j]
bbsData = {
memoId: resValue.id,
updatedTs: resValue.updatedTs,
creatorId:resValue.creatorId,
creator: resValue.creatorName || resValue.creator.nickname || resValue.creator.name,
imgsrc: imgsrcNow,
content: resValue.content,
resourceList: resValue.resourceList,
url:hostNow,
twiEnv:twiEnvNow,
artEnv:artEnvNow,
artSite:artSiteNow,
home:homeNow,
comment: commentNow
}
bbsDatas.push(bbsData)
}
updateHTMl(bbsDatas)
bbDom.insertAdjacentHTML('afterend', load);
var nowLength = bbsData.length
if(nowLength < 10){
document.querySelector("button.button-load").remove()
return
}
page++
offset = 10*(page-1)
getNextList()
});
}
}
function getNextList(){
var bbUrl = bbUrlNow+"&offset="+offset;
fetch(bbUrl).then(res => res.json()).then( resdata =>{
var arrData = resdata || ''
if(resdata.data){
arrData = resdata.data
}
nextDom = arrData
nextLength = nextDom.length
page++
offset = 10*(page-1)
if(nextLength < 1){
document.querySelector("button.button-load").remove()
return
}
nextDatas.length = 0
for(var j=0;j < nextDom.length;j++){
var resValue = nextDom[j]
nextData = {
updatedTs: resValue.updatedTs,
creatorId:resValue.creatorId,
creator: resValue.creatorName || resValue.creator.nickname || resValue.creator.name,
imgsrc: imgsrcNow,
content: resValue.content,
resourceList: resValue.resourceList,
url:hostNow,
twiEnv:twiEnvNow,
artEnv:artEnvNow,
artSite:artSiteNow,
comment:commentNow,
memoId: resValue.id,
home:homeNow,
}
nextDatas.push(nextData)
}
})
}
const withTimeout = (millis, promise) => {
const timeout = new Promise((resolve, reject) =>
setTimeout( () => reject(`Timed out after ms.`),millis));
return Promise.race([
promise,
timeout
]);
};
const fetchBBser = async () => {
const results = await Promise.allSettled(urls.map(
url => withTimeout(2000,
fetch(url.host+"api/"+url.apiV1+"memo?creatorId="+url.creatorId+"&rowStatus=NORMAL&limit="+limit).then(response => response.json()).then(resdata => {
var qsLive = ".bbs-urls.bbs-url[data-hostid='"+url.host+"u/"+url.creatorId+"']"
document.querySelector(qsLive).classList.add("liveon");
var arrData = resdata || ''
if(resdata.data){
arrData = resdata.data
}
return arrData
})
)
)).then(results=> {
bbDom.innerHTML = ''
for(var i=0;i < results.length;i++){
var status = results[i].status
if(status == "fulfilled"){
var resultsRes = results[i].value
for(var j=0;j < resultsRes.length;j++){
var resValue = resultsRes[j]
var dateNow = new Date()
var dateDiff = dateNow.getTime() - (resValue.updatedTs * 1000);
var dayDiff = Math.floor(dateDiff / (24 * 3600 * 1000));
if(dayDiff < 10 ){
bbsData = {
memoId: resValue.id,
updatedTs: resValue.updatedTs,
creatorId:resValue.creatorId,
creator: resValue.creatorName || resValue.creator.nickname || resValue.creator.name,
imgsrc: urls[i].imgsrc,
content: resValue.content,
resourceList: resValue.resourceList,
home:urls[i].home,
url:urls[i].host,
comment:urls[i].comment,
twiEnv:urls[i].twiEnv || '',
artEnv:urls[i].artEnv || '',
artSite:urls[i].artSite || ''
}
bbsDatas.push(bbsData)
}
}
}
}
bbsDatas.sort(compare("updatedTs"));
updateHTMl(bbsDatas)
})
}
fetchBBser()
function compare(p){
return function(m,n){
var a = m[p];
var b = n[p];
return b - a;
}
}
function uniqueFunc(arr){
const res = new Map();
return arr.filter((item) => !res.has(item.creator) && res.set(item.creator, 1));
}
function updateHTMl(data){
var result="",resultAll="";
const TAG_REG = /#([^\s#]+)/;
const IMG_REG = /\!\[(.*?)\]\((.*?)\)/g;
BILIBILI_REG = /<a.*?href="https:\/\/www\.bilibili\.com\/video\/((av[\d]{1,10})|(BV([\w]{10})))\/?".*?>.*<\/a>/g;
NETEASE_MUSIC_REG = /<a.*?href="https:\/\/music\.163\.com\/.*id=([0-9]+)".*?>.*<\/a>/g;
QQMUSIC_REG = /<a.*?href="https\:\/\/y\.qq\.com\/.*(\/[0-9a-zA-Z]+)(\.html)?".*?>.*?<\/a>/g;
QQVIDEO_REG = /<a.*?href="https:\/\/v\.qq\.com\/.*\/([a-z|A-Z|0-9]+)\.html".*?>.*<\/a>/g;
YOUKU_REG = /<a.*?href="https:\/\/v\.youku\.com\/.*\/id_([a-z|A-Z|0-9|==]+)\.html".*?>.*<\/a>/g;
YOUTUBE_REG = /<a.*?href="https:\/\/www\.youtube\.com\/watch\?v\=([a-z|A-Z|0-9]{11})\".*?>.*<\/a>/g;
marked.setOptions({
breaks: true,
smartypants: false,
langPrefix: 'language-'
});
const renderer = new marked.Renderer();
const linkRenderer = renderer.link;
renderer.link = (href, title, text) => {
const localLink = href.startsWith(`${location.protocol}//${location.hostname}`);
const html = linkRenderer.call(renderer, href, title, text);
return localLink ? html : html.replace(/^<a /, `<a target="_blank" rel="noreferrer noopener nofollow" `);
};
marked.use({ renderer });
for(var i=0;i < data.length;i++){
var memos = data[i].url
var memoId = data[i].memoId
var memoUrl = memos + "m/" + memoId
var comment = data[i].comment
var twiEnv = data[i].twiEnv
var artEnv = data[i].artEnv
var artSite = data[i].artSite
var bbContREG = data[i].content
.replace(TAG_REG, "<span class='tag-span'>#$1</span> ")
.replace(IMG_REG, '')
bbContREG = marked.parse(bbContREG)
.replace(BILIBILI_REG, "<div class='video-wrapper'><iframe src='//www.bilibili.com/blackboard/html5mobileplayer.html?bvid=$1&as_wide=1&high_quality=1&danmaku=0' scrolling='no' border='0' frameborder='no' framespacing='0' allowfullscreen='true'></iframe></div>")
.replace(NETEASE_MUSIC_REG, "<meting-js auto='https://music.163.com/#/song?id=$1'></meting-js>")
.replace(QQMUSIC_REG, "<meting-js auto='https://y.qq.com/n/yqq/song$1.html'></meting-js>")
.replace(QQVIDEO_REG, "<div class='video-wrapper'><iframe src='//v.qq.com/iframe/player.html?vid=$1' allowFullScreen='true' frameborder='no'></iframe></div>")
.replace(YOUKU_REG, "<div class='video-wrapper'><iframe src='https://player.youku.com/embed/$1' frameborder=0 'allowfullscreen'></iframe></div>")
.replace(YOUTUBE_REG, "<div class='video-wrapper'><iframe src='https://www.youtube.com/embed/$1' title='YouTube video player' frameborder='0' allow='accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture' allowfullscreen title='YouTube Video'></iframe></div>")
var IMG_ARR = data[i].content.match(IMG_REG) || '',IMG_ARR_Grid='';
if(IMG_ARR){
var IMG_ARR_Length = IMG_ARR.length,IMG_ARR_Url = '';
if(IMG_ARR_Length !== 1){var IMG_ARR_Grid = " grid grid-"+IMG_ARR_Length}
IMG_ARR.forEach(item => {
let imgSrc = item.replace(/!\[.*?\]\((.*?)\)/g,'$1')
IMG_ARR_Url += '<figure class="gallery-thumbnail"><img class="img thumbnail-image" loading="lazy" decoding="async" src="'+imgSrc+'"/></figure>'
});
bbContREG += '<div class="resimg'+IMG_ARR_Grid+'">'+IMG_ARR_Url+'</div>';
}
var tagArr = data[i].content.match(TAG_REG);
var bbContTag = '';
if (tagArr) {
bbContTag = String(tagArr[0]).replace(/[#]/g, '');
} else {
bbContTag = '动态';
};
if(data[i].resourceList && data[i].resourceList.length > 0){
var resourceList = data[i].resourceList;
var imgUrl='',resUrl='',resImgLength = 0;
for(var j=0;j < resourceList.length;j++){
var restype = resourceList[j].type.slice(0,5);
var resexlink = resourceList[j].externalLink
var resLink = '',fileId=''
if(resexlink){
resLink = resexlink
}else{
fileId = resourceList[j].publicId || resourceList[j].filename
resLink = memos+'o/r/'+resourceList[j].id+'/'+fileId
}
if(restype == 'image'){
imgUrl += '<figure class="gallery-thumbnail"><img class="img thumbnail-image" src="'+resLink+'"/></figure>'
resImgLength = resImgLength + 1
}
if(restype !== 'image'){
resUrl += '<a target="_blank" rel="noreferrer" href="'+resLink+'">'+resourceList[j].filename+'</a>'
}
}
if(imgUrl){
var resImgGrid = ""
if(resImgLength !== 1){var resImgGrid = " grid grid-"+resImgLength}
bbContREG += '<div class="resimg'+resImgGrid+'">'+imgUrl+'</div>'
}
if(resUrl){
bbContREG += '<div class="resour">'+resUrl+'</div>'
}
}
var EnvNow = ''
if(twiEnv && twiEnv != "undefined"){
EnvNow = twiEnv.replace(/https\:\/\/.*\.(.*)\..*/,'$1')
}
if(artEnv && artEnv != "undefined"){
EnvNow = artEnv.replace(/https\:\/\/.*\.(.*)\..*/,'$1')
}
result += '<li class="'+EnvNow+'memo-'+memoId+'"><div class="bbs-avatar"><a href="'+data[i].home+'" target="_blank" rel="noopener noreferrer"><img src="'+data[i].imgsrc+'" alt=""></a><a href="'+memoUrl+'" target="_blank" rel="noopener noreferrer" class="bbs-creator">'+data[i].creator+'</a><span class="bbs-dot">·</span><span class="bbs-date">'+new Date(data[i].updatedTs * 1000).toLocaleString()+'</span>'
var comSVG = '<span class="bbs-coment-svg"><svg class="icon" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" width="20" height="24"><path d="M816 808H672c-4.8 0-8 1.6-11.2 4.8l-80 80c-36.8 36.8-97.6 36.8-136 0l-80-80c-3.2-3.2-6.4-4.8-11.2-4.8h-144c-70.4 0-128-57.6-128-128V232c0-70.4 57.6-128 128-128h608c70.4 0 128 57.6 128 128v448C944 750.4 886.4 808 816 808zm0-64c35.2 0 64-28.8 64-64V232c0-35.2-28.8-64-64-64H208c-35.2 0-64 28.8-64 64v448c0 35.2 28.8 64 64 64h144c20.8 0 41.6 8 56 24l80 80c12.8 12.8 32 12.8 44.8 0l80-80c14.4-14.4 35.2-24 56-24H816zM320 408c27.2 0 48 20.8 48 48v32c0 27.2-20.8 48-48 48s-48-20.8-48-48v-32c0-27.2 20.8-48 48-48zm192 0c27.2 0 48 20.8 48 48v32c0 27.2-20.8 48-48 48s-48-20.8-48-48v-32c0-27.2 20.8-48 48-48zm192 0c27.2 0 48 20.8 48 48v32c0 27.2-20.8 48-48 48s-48-20.8-48-48v-32c0-27.2 20.8-48 48-48z" /></svg></span>'
var outSVG = '<span class="bbs-coment-svg"><svg class="icon" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" width="20" height="20"><path d="M864 640a32 32 0 0 1 64 0v224.096A63.936 63.936 0 0 1 864.096 928H159.904A63.936 63.936 0 0 1 96 864.096V159.904C96 124.608 124.64 96 159.904 96H384a32 32 0 0 1 0 64H192.064A31.904 31.904 0 0 0 160 192.064v639.872A31.904 31.904 0 0 0 192.064 864h639.872A31.904 31.904 0 0 0 864 831.936V640zm-485.184 52.48a31.84 31.84 0 0 1-45.12-.128 31.808 31.808 0 0 1-.128-45.12L815.04 166.048l-176.128.736a31.392 31.392 0 0 1-31.584-31.744 32.32 32.32 0 0 1 31.84-32l255.232-1.056a31.36 31.36 0 0 1 31.584 31.584L924.928 388.8a32.32 32.32 0 0 1-32 31.84 31.392 31.392 0 0 1-31.712-31.584l.736-179.392L378.816 692.48z"/></svg></span>'
if(comment == '1'){
if(twiEnv && twiEnv != 'undefined'){
result += '<a data-id="'+memoId+'" data-twienv="'+twiEnv+'" data-path="'+memoUrl+'" onclick="loadTwikoo(this)" onmouseenter="insertTwikoo(this)" href="javascript:void(0)" rel="noopener noreferrer">'+comSVG+'</a></div><div class="bbs-content"><div class="bbs-text">'+bbContREG+'</div><div class="item-comment twikoo-'+memoId+' d-none"><div id="'+EnvNow+'twikoo-'+memoId+'"></div></div></div></li>'
}else if(artEnv && artEnv != 'undefined'){
result += '<a data-id="'+memoId+'" data-artenv="'+artEnv+'" data-artsite="'+artSite+'" data-path="'+memoUrl+'" onclick="loadArtalk(this)" href="javascript:void(0)" rel="noopener noreferrer">'+comSVG+'</a></div><div class="bbs-content"><div class="bbs-text">'+bbContREG+'</div><div class="item-comment '+EnvNow+'artalk-'+memoId+' d-none"></div></div></li>'
}else{
result += '<a href="'+memoUrl+'" target="_blank" rel="noopener noreferrer">'+outSVG+'</a></div><div class="bbs-content"><div class="bbs-text">'+bbContREG+'</div></div></li>'
}
}else{
result += '</div><div class="bbs-content"><div class="bbs-text">'+bbContREG+'</div></div></li>'
}
}
var bbBefore = "<section class='bbs-timeline'><ul class='list'>"
var bbAfter = "</ul></section>"
resultAll = bbBefore + result + bbAfter
bbDom.insertAdjacentHTML('beforeend', resultAll);
var btn = document.querySelector('button.button-load')
if(btn){
btn.textContent= '加载更多';
}
window.ViewImage && ViewImage.init('.bbs-content img')
window.Lately && Lately.init({ target: '.bbs-date' });
}
</script>

注意:如需增加站点,可增加 const urls 字段,注意格式。

样式代码

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
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
<style>
#bbs{padding: 2rem 0;}
#bbs-urls{margin-top: 2rem;}
.bbs-urls{display:inline-block;background: #4a4b50;border-radius:10%;margin:0 .6rem 0 0;padding:4px;width:3.4rem;height:3.4rem;cursor: pointer;vertical-align: text-bottom;}
.bbs-urls img{border-radius:50%;width:100%;height:100%;}
.bbs-urls.url-now{background:#42b983;transition: 0.6s;}
.urls-button svg.icon{padding:10px;width:100%;height: 100%;}
.bbs-timeline ul {margin:0;padding: 0;}
.bbs-timeline ul li{list-style-type:none;position:relative;}
.bbs-timeline{max-width:1200px;margin:0 auto;}
.bbs-avatar{position: relative;}
.bbs-avatar img{width:24px;height:24px;border-radius:50%;margin-right:1rem;}
div.bbs-avatar > img {
display: inline-block;
margin: 0 10px 0 0;
}
.bbs-creator,.bbs-date,.bbs-dot{position:relative;top:-5px;}
.bbs-dot{font-weight: 800;margin:0 .5rem;}
.bbs-content {margin-bottom: 3rem;}
.bbs-text,.resour{background: var(--color-block);border-radius: 8px;font-size: 1em;padding:10px 14px;position: relative;}
.resour{font-size: 0.9rem;margin-top: 2px;padding: 5px 14px;}
.bbs-text{overflow:hidden;max-height:90vh;}
.bbs-text blockquote{font-family: KaiTi,STKaiti,STFangsong;margin:0 0 0 1rem;padding:.25rem 2rem;position: relative;border-left:0 none;}
.bbs-text blockquote::before{line-height: 2rem;content: "“";font-family: Georgia, serif;font-size: 28px;font-weight: bold;position: absolute;left: 10px;top:5px;}
.bbs-text p{margin:0;}
.bbs-text pre p{display: inline-block;}
.bbs-text pre p:empty{display: none;}
.tag-span{color: #42b983;}
#load button.load-btn{width:100%;padding:8px 0;background: var(--color-block);}
#bb-footer{letter-spacing:8px;margin:5rem auto 1rem;text-align:center;}
.dark .bbs-text,.dark .resour{background:#4a4b50;}
.dark .bbs-text p{color:#fafafa;}
.loader {position: relative;margin:3rem auto;width: 100px;}
.loader::before {content: '';display: block;padding-top: 100%;}
.circular {animation: rotate 2s linear infinite;height: 100%;transform-origin: center center;width: 100%;position: absolute;top: 0;bottom: 0;left: 0;right: 0;margin: auto;}
.path {stroke-dasharray: 1, 200;stroke-dashoffset: 0;animation: dash 1.5s ease-in-out infinite, color 6s ease-in-out infinite;stroke-linecap: round;}
@keyframes rotate {100% {transform: rotate(360deg);}}
@keyframes dash {
0% {stroke-dasharray: 1, 200;stroke-dashoffset: 0;}
50% {stroke-dasharray: 89, 200;stroke-dashoffset: -35px;}
100% {stroke-dasharray: 89, 200;stroke-dashoffset: -124px;}
}
@keyframes color {
100%,0% {stroke: #d62d20;}40% {stroke: #0057e7;}66% {stroke: #008744;}80%,90% {stroke: #ffa700;}
}
.bbs-content p > img{cursor:pointer;border:1px solid #3b3d42;}
.bbs-content p:has(img.img){display: inline-block;}
.bbs-text p > img {display: block;}
.bbs-text p > img:first-child:nth-last-child(n+2),.bbs-text p > img:first-child:nth-last-child(n+2) ~ img {display: inline-block;}
.bbs-content p > img.square{height:180px;width:180px;object-fit:cover;}
.resimg.grid{
display: grid;
grid-template-columns: repeat(3,1fr);
grid-template-rows:auto;
gap: 4px;
width: calc(100%* 2 / 3);
box-sizing: border-box;
margin: 4px 0 0;
}
.resimg.grid-2{
grid-template-columns: repeat(2, 1fr);
width: 80%;
}
.resimg.grid-4{
grid-template-columns: repeat(2, 1fr);
width: calc(80% * 2 / 3);
}
.resimg.grid figure.gallery-thumbnail {
position: relative;
width: 100%;
height: 0;
padding-top: 100%;
cursor: zoom-in;
}
.resimg figure{
text-align: left;
max-height:50%;
}
.resimg figure img{
max-height:50vh;
}
.resimg.grid figure, figcaption {
margin: 0 !important;
}
.resimg.grid figure.gallery-thumbnail > img.thumbnail-image {
position: absolute;
left: 0;
top: 0;
display: block;
width: 100%;
height: 100%;
object-fit: cover;
object-position: 50% 50%;
}
.video-wrapper{position:relative;padding-bottom:55%;width:100%;height:0}
.video-wrapper iframe{position:absolute;height:100%;width:100%;}
</style>

注意:上面的样式杜老师做了微调,效果可见本站说说广场,如不满意也可自行调整。

展示代码

1
2
3
4
<div id="bbs"></div>
<script type="text/javascript" src="https://jsd.onmicrosoft.cn/npm/marked@4.3.0/marked.min.js"></script>
<script type="text/javascript" src="https://jsd.onmicrosoft.cn/gh/Tokinx/ViewImage/view-image.min.js"></script>
<script type="text/javascript" src="https://jsd.onmicrosoft.cn/gh/Tokinx/Lately/lately.min.js"></script>

注意:根据自身需求修改对应代码,如有任何问题,可随时在评论区中留言!

AI 写作对博主影响

当今数字时代,AI 写作已经成为越来越受欢迎的一种方式。AI 写作技术已非常成熟,许多人选择使用 AI 写作工具来帮助他们快速创建高质量内容。但是,这种技术对于博主来说究竟有什么影响呢?

提高写作效率

使用 AI 写作工具可以帮助博主在更短的时间内创作出更多的内容。这种工具可以帮助博主快速生成文章的结构和主题,也可以提供一些提示和建议来帮助博主更好地组织、表达想法。

这样,博主就可以更快地完成写作任务,有更多的时间来处理其它重要的事情。

带来新的创意

AI 写作工具通常会提供一些新颖的想法和主题,这些想法可能会激发博主的灵感,帮助他们创作出更有价值的内容。

此外,AI 写作工具也可识别出一些已有的文章中的主题和想法,并在此基础提出一些新的见解和建议。

提高内容质量

对于大多数的博主来说,质量是非常重要的。AI 写作工具可以帮助博主优化他们的文章,使它们更加的清晰、流畅、易读。

这些工具可以提供一些语法和拼写方面的帮助,还可以识别出文章中重复或冗余内容。

降低写作成本

使用 AI 写作工具可帮助博主降低写作成本。这种工具可以帮助博主快速创建大量内容,减少了雇佣写手或编辑需求。

此外,使用 AI 写作工具还可以减轻博主的工作量,使之能够专注于其它的任务。

结论

总之,AI 写作工具对博主来说可以带来很多好处。

它们可以提高写作效率、带来新的创意、提高内容质量,还能降低写作成本。

然而,博主也需注意,AI 写作工具只是一种辅助的工具,它们不能代替博主自己思考和创造力。

因此,博主应该在使用 AI 写作工具同时,保持自己独特性和思考方式。

写在最后

小伙伴们都知道杜老师经营起了知乎,为了快速提升积分,杜老师使用了 ChatGPT 回答问题。

其中也学习到很多知识及写作的技巧,可以说是在回复中提升。

进而也思考了 AI 写作对于博主的影响。

此文是在 AI 写作工具辅助下完成,不得不说有了 AI 的帮助,思路更加清晰,描述更加准确。

但需注意的是,不能过于依赖 AI 来进行创作,还是要表达出博主独特性和思考方式,做一个有态度的博客才会有受众。

最后为 FlowUs 做个广告,已集成 AI 辅助工具,可以实现写作、总结、摘要、解释功能!

使用 Memos 搭建时光机教程

首先感谢下林木木童鞋,参考他的代码才有此篇教程。时光机的效果可以参考本博说说广场,不过时光机只会展示个人的说说,如需 Memos 的搭建教程,或是广场搭建教程,可以静等之后教程!

写在前面

此篇教程兼容各类博客框架,不管用的是 Hexo/Hugo/Typecho/WordPress 都可直接使用。

若无服务器可以不用搭建 Memos,借助现有平台「如杜老师的 https://s.dusays.com」注册账户即可。

条数统计

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<div class="container">
<p>共发表了 <span id="memosCount">0</span> 条 Memos 说说!</p>
</div>
<script>
function getTotal() {
var totalUrl = "https://s.dusays.com/api/v1/memo/stats?creatorId=1";
fetch(totalUrl).then(res => res.json()).then(resdata => {
if (resdata) {
var memosCount = document.getElementById('total');
memosCount.innerHTML = resdata.length;
}
}).catch(err => {
});
};
window.onload = getTotal();
</script>

注意:上面代码的 https://s.dusays.com/api/v1/memo/stats?creatorId=1 一句,s.dusays.com 替换成自己 Memos 的域名,结尾的 1 改为用户的 ID。

前端展示

1
2
3
4
5
6
7
8
9
10
11
12
13
<div id="bber"></div>
<script>
var bbMemos = {
memos : 'https://s.dusays.com/',
limit : '10',
creatorId:'1' ,
domId: '#bber',
}
</script>
<script src="https://npm.onmicrosoft.cn/penndu@4.0.9/memos.js"></script>
<script src="https://npm.onmicrosoft.cn/marked/marked.min.js"></script>
<script src="https://jsd.onmicrosoft.cn/gh/Tokinx/ViewImage/view-image.min.js"></script>
<script src="https://jsd.onmicrosoft.cn/gh/Tokinx/Lately/lately.min.js"></script>

注意:上面代码的 bber 可自定义,不要与整站 div 重名;s.dusays.com 替换成自己 Memos 的域名;limit 为展示数量限制,creatorId 对应用户 ID,domId 需与 div id 相同。

补充说明

如果不知道自己的 ID 是多少,可以直接留言问杜老师。或者发表一条说说,然后点击 这里,点击您的用户名称,所进入页面的网址末尾处的数字,就是 ID 了:

小推一波说说广场

细心的小伙伴应该发现,杜老师调整了说说页面,更换了说说的托管平台,由 Artitalk 调整为 Memos,相比 Artitalk 部署时会泄露 Token,Memos 更加安全且高效,欢迎注册体验!

页面展示

点击导航栏的 说说 即可进入广场。杜老师的前端能力有限,内容展示比较简陋,欢迎小伙伴提供建议及代码:

也可直接访问 说说平台 浏览整合后的内容页面:

注册使用

点击进入 页面 可以注册用户,也可登录账号:

登录后即可管理配置并发布说说:

使用规则

  1. 严禁发布不良内容;

  2. 不得发布带有超链接及有广告嫌疑的内容;

  3. 杜老师有权在不通知的情况下删除任何触犯以上条例的内容;

  4. 最终解释权归杜老师说所有。

扩展应用

如使用 Chrome 内核的浏览器,可以通过安装 扩展 实现快速发布:

如使用安卓系统的手机,可以通过安装 软件 实现快速发布:

讨论如何通过移动设备更新博客

今天农历正月初二,刚由一个城市,转到了另一个城市,趁着手边恰好有电脑的机会,更新此文,并希望看到的小伙伴可一同讨论!

写在前面

细心的小伙伴可能发现,平时杜老师发布的博文,都会在更新日零点 52 分刷新,那是因为博文已在前一日准备好,GitHub Actions 的计划任务零点 52 分触发自动部署更新博客内容。

今天已经快结束了,博文仍未更新,是因为之前的几天,杜老师身边一直没电脑,所以只好通过移动设备回复评论,但没条件更新博文,故写此文,讨论一下如何通过移动设备更新博客。

智能手机

现在一提手机,没人能想到不智能款式,不过杜老师写下此文时,奶奶刚好在旁边通过老年机听收音机「部分老年机具备FM功能」为了严谨,此段落强调是智能手机。

之前做过一些统计,发现杜老师接触 Hexo 博主,大多都是学生。除了休息日回家用电脑更新,绝大多数时间都是通过手机更新博客。

杜老师使用的工具是 Termux,这是一个终端的模拟器,可使用 Shell 命令,并能通过安装软件添加功能,如 Git。

杜老师会拉取文章仓库到手机中,然后在手机上更新站点内容,再提交至仓库完成更新。一般使用该种方法,都是少量更新需求,如友链等。

平板电脑

为了方便数据跨设备及平台传输,杜老师使用的安卓平板,使用博客维护工具为 AidLux,AidLux 是一个构建在 ARM 硬件上,基于创新性跨 Android+Linux 融合系统环境的智能物联网应用开发和部署平台。

借助 AidLux 不仅可以实现更好的终端操作体验,且通过内置的插件中心,还可安装 Visual Studio Code 等程序,更新博客更加方便!一般使用该种方法,是需要博文更新时,但手边无可用电脑设备。

写在最后

以上是杜老师如何通过移动设备更新博客,因为平时使用移送设备较少「虽然杜老师是一枚狂热的数码爱好者,但手机确实占用了杜老师不少精力和时间,所以在繁忙的工作和学习时,几乎不使用移动设备接收和处理信息」所以了解到的工具较少,希望经常使用移动设备更新博客的小伙伴可以多提建议、参与讨论!

另外杜老师说全年无休,每三天会更新内容,并会满足一些小伙伴的需求,提供宣传及图文教程类博文,欢迎关注!

WordPress 文件及权限

曾答应了小熊童鞋发布一篇关于 WP 目录权限的教程,本篇就已 Linux 系统加某塔面板为例,讲解 WordPress 各文件作用,及对应权限和设置方法!

文件列表

基于官方最新 6.1.1 版本安装包,内含文件如下:

名称作用
wp-admin存放后台面板相关文件,因文件比较多,这里不做详细介绍
wp-content存放用户上传文件,如模板插件及媒体文件
wp-includes存放 WP 相关库文件,为模板插件提供运行库
index.php核心索引文件 ,也是博客输出文件,里面的代码很简单,定义一个垂直变量,引用同目录下的 wp-blog-header.php 文件
license.txtGPL许可证文件
readme.html安装导言
wp-activate.php用户激活文件,用户注册之后就会发一封邮件给用户,激活账户
wp-blog-header.php加载环境和模板的
wp-comments-post.php添加评论把它添加到数据库的文件「个别主题提供评论提交入口,可删除该文件减少垃圾评论」
wp-config-sample.php官方给出的链接数据库示例文件,如果 wp-config.php 文件丢失了,通过这个文件进行修改也可以的
wp-cron.php执行定时任务文件,允许判断任务是不是到时间完成
wp-links-opml.php生成一个 opml 格式的链接列表
wp-load.php加载 wp-config.php 文件且设置公共变量,及加载 WP 的程序和类库
wp-login.php注册用户登录页面
wp-mail.php邮件操作页面
wp-settings.php运行前的例行程序,包括代码安装是否正确,使用辅助函数,应用用户插件,执行初始化计时器等等
wp-signup.php定义新用户的账号
wp-trackback.php处理 trackback 的请求「别人在博客外引用博文,如果对方开启这个功能,这个文件就会通知我们,他的博客引用了我们的文章」
xmlrpc.php远程发布功能,这个功能允许用别的工具通过远程来发布文章

权限设置

  1. 最简单的:将目录及文件的权限都设置为 755,所有者 www,应用到子目录。即所有者拥有读写执行权限,所有组即其它用户可以读取执行。

  2. 最安全的:将目录及文件的所有者设置为 www,文件权限设置为 600「即所有者仅拥有读权限」目录权限设置为 700,该种方法可一定意义上防止其它程序篡改网站源码。

一个面向 WordPress 博客的优化建议

随着新春将至,很多博主由日常的繁忙转向清闲,开始折腾起了博客。发现不少的小伙伴换了博客程序,一些小伙伴开始为博客调优,今天分享一些关于 WordPress 博客的优化建议!

写在前面

了解杜老师说的小伙伴比较清楚,杜老师说一直使用 Hexo 这款轻量级博客框架,且一直在用 Volantis 主题。

但杜老师对 WordPress 还算是比较了解的,因为杜老师说的前身是菜鸟博客,用的就是 WordPress 搭建的。

菜鸟博客文章量近 1600 篇,文章评论 12W 多。且安装了论坛插件「即 bbPress」注册用户量 13000,发帖及回复量约 22W。

在此数据量级,为了保证运营成本,最好的方式就是做优化!所以说杜老师的优化经验还是比较丰富的~

程序评价

每十个博客就有一个使用 WordPress,这是 WordPress 的宣传文案,但不是乱说的,有实际的数据统计。

毕竟 WordPress 的安装简单,使用方便,庞大的主题库和插件库可满足任何人对网站的任何需求。

但不管 WordPress 如何升级,都无法避免一个大问题:臃肿!

不支持源码上臃肿,运行时也有很多臃肿的机制,且因为主题及插件调用问题,对数据库的优化不够好,很多小伙伴都反馈数据库缓存命中率较低。

所以 WordPress 的使用者会感到博客越来越慢,最终只能通过升级服务器的配置维持运营。

以上评价仅为杜老师的个人使用体验,如有不同见解欢迎评论交流!

优化方法

  1. 静态文件:大多博客都会借助图片或特效让页面变得好看,但这些文件会占用大量带宽,影响页面打开速度。所以可以将这类的文件通过引用站外链接「如 CDN」方式调用,减少带宽占用,进而加快页面打开速度;

  2. 程序源码:WordPress 使用 PHP 语言,在博客页面切换时,会产出大量且重复的 PHP 执行,可借助 OPcache 缓存执行结果,加速执行过程,进而加快页面打开速度;

  3. 数据查询:WordPress 在运行时会大量产生数据库的交互操作,且 WordPress 本身缓存机制较弱,导致数据无法及时返回拖慢页面打开速度。我们可以增加缓存「如 Memcached」并可使用插件生成静态页面,进而减少数据库的查询次数,加快页面打开速度;

  4. 博客插件:WordPress 在做站点展示前,会扫描所有的插件,并对开启状态的插件调用其数据库中的配置项,而扫描和调用过程则会拖慢页面打开速度。所以尽量减少插件使用,未启用的插件可备份后删除,轻量级的插件功能尽量通过修改程序源码实现「如邮件通知等」

写在最后

杜老师自认为理论丰富但动手能力弱,所以暂不提供远程优化相关技术支持,不过可以留言讨论,共同来寻找更好的优化方式!

如果您有自己的服务器,服务器中仅运行一个 WordPress 博客,且博客中并无优化插件,可以尝试使用杜老师主推 OpenLiteSpeed 和 LiteSpeed Cache 插件。

杜老师说的 2022 年度总结

最近看到很多小伙伴都在写年度总结,就连十年之约论坛也开启了文章收集,杜老师也趁着机会水篇文章,文笔有限,小伙伴们随便看看即可!

博客年度事件

2022 年 11 月 26 日

杜老师说站点接入林林小盆友提供 Umami 访问分析服务,如因此导致访问中出现问题,欢迎随时反馈。

2022 年 11 月 24 日

因 Volantis 版本升级的原因,本站下线 Pjax 无刷新页面加载效果;

2022 年 10 月 04 日

本博客全面本地化,欢迎小伙伴们来测试稳定性;

2022 年 10 月 02 日

经多方测试 Meilisearch 的标题检索异常,正式修复前先切换至 Algolia;

2022 年 09 月 04 日

为测试 GitHub Actions 配置,临时托管至 CloudBase;

2022 年 09 月 02 日

因 Algolia 最近节点位于香港,大陆访问速度较慢,且有 API 调用数限制,现换成 Meilisearch;

2022 年 08 月 30 日

因 content.json 过大,严重影响访客搜索体验,现换成 Algolia 服务;

2022 年 08 月 28 日

下架 8 月 28 日后穿越文,新增定时发布功能;

2022 年 08 月 08 日

调整友情链接位置,由右侧调整到页脚。

2022 年 08 月 02 日

后端换到了 Netlify,页面生成加部署时间缩短 34%;

2022 年 07 月 10 日

博客三周年了,纪念一下!

2022 年 07 月 08 日

后端换到了 Vercel,前端使用阿里云 CDN 缓存加速;

2022 年 06 月 20 日

在星辰童鞋帮助下,自建了不蒜子统计平台,已经部署在本博客,待测试稳定后,会提供公益性统计服务;

2022 年 06 月 18 日

为了减少流量成本,本站关闭了页面预加载功能,经测试影响不明显,不会降低访客体验;

2022 年 05 月 24 日

随着更新日志增多,大量时间线内容拉长了留言页面,为了给小伙伴们更好的浏览体验,现将部分内容折叠;

2022 年 05 月 20 日

在柚子童靴帮助下,杜老师说进一步提升了贴图上传速度,图片不经过服务器,直接通过 API 上传至图床;

2022 年 04 月 24 日

今日有小伙伴反馈贴图上传速度较慢,因为贴图数据要先传到服务器上,再通过 API 传到图床,而服务器的下行带宽只有 1M。目前已将后端托管在家中的 NAS 上,上下行百兆带宽可提升上传速率;

2022 年 04 月 20 日

在柚子童靴疯狂邀请下,杜老师说更换了 Artalk 评论系统。在此也感谢柚子童靴和评论系统作者 QWQAQ 的大力帮助,完成无损切换;

2022 年 04 月 16 日

新增右键菜单,为访客提供更加便捷的操作方式,如需恢复原有菜单,可以按住CTRL时右键;

2022 年 04 月 14 日

新增暗黑模式,为夜间浏览带来更好的体验,保护视力,从我做起;

2022 年 04 月 04 日

因图床托管平台被查封,目前图片数据存放于杜老师说所在服务器,为了做好数据隔离,杜老师说将于近期进行服务器的迁移,可能会出现短时间无法访问,请大家耐心等待片刻后刷新即可;

2022 年 03 月 28 日

杜老师上线朋友圈页面,方便第一时间送上沙发,同时期待大家回访;

2022 年 02 月 10 日

杜老师说取消苹果教程分类,其下所有文章转至智慧生活,添加视频分享分类;

2022 年 02 月 08 日

杜老师说监控服务器替换为更加精确的 Freshping,可提供以小时为单位的监控数据;

图床年度事件

2022 年 10 月 06 日

图床近期调整运营策略,下线除 5G 容量外其它的套餐,已购买的套餐仍然生效。

2022 年 10 月 02 日

部分托管图片遭受流量攻击,产生大量费用,为减少图床的运营成本,会对异常流量图片进行删除处理,删除前会邮件通知,并至少保留 24 小时;

2022 年 08 月 30 日

去不图床首页新增背景图片,采集自某应的每日壁纸,如影响加载速度请大家及时反馈;

2022 年 08 月 28 日

近期服务器频繁遭受到恶意攻击,为保障服务器安全,开启很多安全策略,如有影响大家使用,请理解并留言反馈;

2022 年 08 月 22 日

去不图床开通 QQ 第三方登录模块,允许用户使用 QQ 接入及登录;

2022 年 08 月 20 日

已将图床整站转移至国内服务器,更高配置更大带宽保障用户使用体验;

2022 年 08 月 18 日

已通过 ICP 备案,图床官网接入多吉云 CDN 国内节点加速;

2022 年 08 月 16 日

去不图床开通 GitHub 第三方登录模块,允许用户使用 GitHub 接入及登录;

2022 年 08 月 10 日

去不图床全站添加访问统计,显示页面展示次数,以及访问人数;

2022 年 08 月 08 日

计划 8 月 20 日凌晨 2 点切换存储策略,时间预计一个小时,期间无法上传图片;

2022 年 07 月 30 日

去不图床计划于 8 月 1 日正式启用新付费模式;

2022 年 07 月 24 日

去不图床已将程序升级至商业版本,同时调整付费模式,付费账号改为付费容量;

2022 年 07 月 12 日

部分小伙伴反馈图床打开的速度较慢,经排查出了网络问题外,可能是服务器内存不足导致,已做内存升级,并调整了网站环境配置;

2022 年 07 月 08 日

因 PHP 扩展故障,导致图片的缩略图生成出现问题「不会影响外链」近期修复故障并重新生成缩略图,预计生成时间持续一周;

2022 年 05 月 24 日

近期发现部分访客上传大量违禁图片,已收到存储节点服务商警告邮件,决定关闭访客上传功能,接入实时图片审核服务;

2022 年 05 月 12 日

为提升图片的上传效率,已将并发数改为 3;

2022 年 05 月 04 日

部分用户反馈批量上传时输出的图片外链地址顺序错乱,已将该问题提交给图床程序作者,临时将上传并发数改为 1 避免该问题再现;

2022 年 05 月 02 日

为了保证国外用户可以正常使用,已将国外的节点临时切换到腾讯云 CDN;

2022 年 04 月 26 日

已有用户反馈国外节点逐步恢复,杜老师联系了节点客服,目前还未收到明确答复;

2022 年 04 月 24 日

新版图床正式启用,支持多图上传、拖拽上传、粘贴上传、复制图片、复制链接、一键复制链接及强大的图片管理功能;

2022 年 04 月 06 日

为了满足更多小伙伴的使用需求,去不图床将于近期进行新版本的内测,点击 这里 查看内测详情;

2022 年 04 月 04 日

因图床托管平台被查封,已将图片数据迁移至杜老师说所在服务器,为了做好数据隔离,杜老师说将于近期进行服务器的迁移,可能会出现短时间无法访问,请大家耐心等待片刻后刷新即可;

2022 年 02 月 28 日

开通境外加速节点,境外走 Cloudflare 节点加速;

2022 年 02 月 02 日

图床提卡系统已完成第一次价格调整;

博客站点数据

截至 2022 年 12 月 29 日 20 点 45 分,杜老师说文章量为 538 篇,已运行时间为 1268 天,总字数约为 312.7 千字,访客数为 53499 人「2022 年 6 月 22 日至今」访问量为 202126 次「同上」。

博客留言量为 19383 条,访问量最多的文章《小米云摄像头无法对接群晖存储解决方法》访问量为 12919 次,评论数最多的页面「关于」评论数为 2928 条。

图床站点数据

除了杜老师说,旗下还有去不图床,2019 年 10 月 28 日创建至今,已稳定运行了 1158 天,已托管图片约为 174.5 千张,相册数量 241 个,用户数量约为 10.9 千人,存储占用量约为 65.85GB。

相比博客,图床运营成本较大,除存储空间外,最大的费用支出就是流量了,目前收入虽然抵不上运营的成本,但仍在杜老师可接受支出范围内,所以不用担心跑路问题!

聊聊杜老师吧

杜老师目前在一家公司担任技术讲师,主要研究方向为 Linux 国产操作系统,平时的工作内容大致为编写课件、课程交付。因为工作任务比较零散、随机,所以有较多的时间可以维护博客、解答小伙伴的问题,所以经常免费提供技术支持。

不过目前行业竞争激烈,杜老师也需要不断学习强化自身,所以未来可能回复时间较集中在晚上,着急的话也可选择付费技术支持。

关于未来展望

在关于里有介绍过,杜老师说主题为技术类分享博客,主要是运维类技术文章分享。

但细心的小伙伴应该发现了,2022 年发布的文章大多都偏了这个主题,原因是杜老师肚子中的墨水所剩无几。

所以会在 2023 年着重提升自身技术水平,以此遍写出更详细更实用的教程!

除此之外,杜老师还发现很多的小伙伴对于技术文章的态度较统一:不明觉厉。

更多关注点放在了生活日志,加上访问统计分析结果,所以 2023 年的主题为:日常生活、智能家居、建站技术。

随着已经逐渐稳定,政策已经放宽,杜老师决定没事多出去走走,分享一些杜老师眼中的世界。

杜老师还是数码爱好者,经常会买一些奇奇怪怪的小物件,也会分享给小伙伴,共同来体验科技的新奇。

还要感谢陪伴杜老师说成长的小伙伴,名字就不一一提了,谨献上杜老师由衷感谢!

如果有建议和意见可以随时留言,杜老师会参考小伙伴们意愿调整博客运营。

最后祝愿各位小伙伴在新的一年,心想事成、身体健康、阖家欢乐、财源滚滚!

杜老师建站史

小伙伴还记得第一次接触建站是什么时候的事情吗?还记得一共搭建过多少个网站吗?哪些网站依旧印象深刻?今天来聊一聊杜老师建站史!

接触网络

第一次接触计算机还是在小学时,具体的年龄忘记了,只记得那会还是 DOS 系统,相比那时候的红色警戒,杜老师更喜欢扫雷,接触第一款操作系统还是 Windows 95。

时隔几年,家里买了台兼容机,运行了 Windows 98,当时因为硬件原因,运行极不稳定,但不妨碍刷大菠萝,那会还没有修改器,凭能力一遍又一遍刷图还是很有趣的。

杜老师第一次接触互联网还是通过调制解调器,那会一小时三块钱,而且会占用电话的线路「上网期间电话无法接听」因为费用和线路的关系,都是在网络的海洋中蘸点水,然后断开网络干搓~

到了初中家里办了宽带,别看只有两兆,可是打开了杜老师的世界观。那会很少会玩游戏,而是在网上浏览各类的资源,偶尔再聊聊天~

第一个站

好像是初二的时候,在日常浏览网站时,看到了一条免费内容托管的广告,顺着链接进入,就来到了名为 AnyP 的平台。

AnyP 为免费用户提供了 100M 存储空间,赠送 anyp.cn 后缀的二级域名。付费可以获得更多空间,并且支持绑定顶级域名。

在零几年的时候网络安全意识比较弱,页面支持各类代码,可以借助模块实现各种效果。

那会最大的乐趣就是在页面中集成新功能,然后接受隔壁小伙伴的膜拜以及请教「目前该平台已停止运营」

腾讯空间

随着内容不断增加,免费的 100M 容量已经不够用了,又没条件付费「那会还没手机,不像现在支付那么便捷」就转战 QQ 空间。

与现今的 QQ 空间不一样,最开始的空间自定义功能非常墙,借助 JS 代码可以打造各类的效果,当时身边小伙伴的空间都是非主流的主题。

杜老师生活在辽宁,当地比较流行的主题风格叫残血。杜老师在官方属于技术运营主力之一,来空间的访客大多都是寻求帮助,也有不少定制模板的小伙伴~

当年空间访问量达到了 50 万,也有付费的小伙伴,当时付费就是 Q 币,再者就是各种会员「不知各位看几年前的日志时,有没有想要掐死自己的冲动,杜老师舍不得掐死自己,就申请了空间注销」

班级网站

因为 QQ 空间对代码没有限制,久而久之就爆出了严重安全问题,腾讯平台开始限制代码使用,功能需要通过内置模块实现,效果等则需要办理黄钻才可。

在升入高中后,因高中强制性住校,家人为了方便给杜老师办了张银行卡,借此杜老师买了第一个虚拟主机,仅支持 ASP 网页语言。

借助开源平台搭建了班级的主页,据说是整个学校史上第一个班级网站,因为噱头较大,再加上新鲜感,除本班同学外,隔壁班的也跑来贡献 IP。

值得骄傲的是,杜老师还凭此获得学校颁发的计算机类比赛一等奖「空间当时买一赠一,就是两年,两年到期后并没有续费,整站数据随之消失」

世外桃源

在班级站运营期间,杜老师逐渐熟悉 BBS 平台,也在众多站长的帮助下,找到很多免费资源,于是就有了综合型论坛「世外桃源」

当时论坛程序是 Discuz,运行在一个国内的免费空间「08 年前国内的空间无需备案」认识了很多行业的大牛,在他们加入后,论坛会员达到了 10W。

那会不懂如何盈利,只是单纯想着人多热闹,而且作为站长,十分有成就感。不过也有一些问题,杜老师的同学知道该论坛后,都想凭借关系获得版主一职,不过论坛规则所限,不能满足他们要求,因此被孤立了好一阵子。

08 年后国内开始要求备案后接入,免费空间没有任何警示直接跑路,论坛全部数据丢失,杜老师的心态直接崩了,弃网备战高考。

工作室站

进入大学后在学者的怂恿下,迷迷糊糊创立了工作室,主要为学校周边的经营场所提供网站搭建、网络维护服务,就搭建了一个演示站点。

在众多开源程序中,杜老师选择了 emlog。忘记是什么原因了,但确实因为 emlog 让杜老师对 PHP 充满兴趣,并为 emlog 贡献了不少代码。

那会还没用 Git,写完代码后发给创始人那多,然后坐等审核、整合、上线,可惜的是 emlog 从 5.2.1 版本后,那多记忆逐渐淡出论坛,也不参与后期开发,元老团队成员逐渐转向其它程序,emlog 落没了~

大学毕业,工作室交给了学弟学妹管理,站点也没带走「毕业后两年的一天,再次访问工作室网站发现无法打开了」

菜鸟博客

大学毕业后从事了培训行业,光荣变成一枚讲师。因自身的授课风格需要学院配合,对埋头记笔记的学员甚无奈,所以和大学时学长及众伙伴创建:菜鸟团队技术博客「后更名为菜鸟博客」

杜老师的能力不多说了,垃圾一枚。

开发频道:老魏,国家计算机研究中心的技术总监,擅长各类编程语言。

网络频道:悦悦,华为华中地区项目经理,精通思科、华三网络设备调试。

数据频道:婧婧,北京理工大学当届校花,擅长数据分析、数据处理,那一条腿比杜老师的生命线还长。

还有些伙伴就不介绍了。因博客使用 WP 程序搭建,用过的小伙伴应该知道它多臃肿,数据量访问量上来之后,一般服务器扛不住。为了平衡运营成本,杜老师提供了很多付费内容、服务,可惜后期因为「分赃不均」导致团队解散,菜鸟博客因此关站。

杜老师说

就你们面前的这个破站,还需要杜老师多介绍吗?

水到这可以了,要什么自行车。

Volantis 主题新版渲染图

Hexo 有非常多好看的主题模板,一些博客圈的小伙伴喜欢经常换主题,杜老师也非常喜欢折腾,但文章量一旦上来,更换主题的成本非常大,很多主题自带的短代码都要调整,下面聊聊杜老师说建博以来用的唯一一款主题。

简单聊聊

Volantis 是一个功能丰富、高度模块化的博客主题。得益于其强大的模块化特性,可轻松搭建一个极简风格的博客,也可以仿照官网搭建一个多人协作的、含文档模块的大体量综合型博客。

建博之初,杜老师就在三款主题中纠结,分别是 Next/Volantis/Butterfly,不过 Next 是单栏,Butterfly 太过于花俏「没有任何贬低含义,只是杜老师喜欢简洁风」

当时这款主题叫 Material X,主题自带的功能模块可以让博文更好呈现,且维护者更新频繁。这些因素都使得杜老师建博以来一直没有更换其它主题。

之前主题原作者离开过一段时间,后期都是由其他小伙伴负责更新,杜老师也贡献一些代码。如今原作者回归了,带来了一些新想法,下面是新版本的渲染图,大家可以提前欣赏一下,顺便提提意见!

新版渲染

关于友情链接的一些事

友情链接,也称网站交换链接、互惠链接、互换链接、联盟链接。是具有一定资源互补优势的网站之间简单合作形式,即分别在自己的网站上放置对方网站的 Logo 图片或文字的网站名称,并设置对方网站的链接,使用户可以从合作网站中发现自己的网站,达到互相推广目的,因此常作为一种网站推广的基本手段。

关于友链

导语引自某度百科。在杜老师看来,友链并非推广手段,而是博主间维系互动的纽带。

通过友情链接,我们可以很方便的找到小伙伴的博客,在感兴趣的文章内留下我们脚印,博主间的互访,也是我们更新与维护博客的动力!

杜老师从未主动申请过友情链接,但收到的友情链接邀请从未拒绝。

即便如此,杜老师也希望各位小伙伴在申请友链时,遵循如下规则。

友善友链

  1. 请不要忘记友链是友情链接。相比友链更希望我们能拥有友情,所以希望不要一上来就丢个链接。经常会遇到这样的情况,有时杜老师好奇这些都是谁,各群问了一圈都不认识,拜访时才知道对方不知从何处寻到了杜老师的博客地址。建议多在对方站内评论留言,熟悉之后自然会加友链,且评论的链接地址还会带动反链,有助于增加搜索引擎的收录;

  2. 请不要设置站标防盗用。自从 jsD 被封后,有些小伙伴将图片数据托管在个人空间中,因怕数据盗用,设置了防盗链。身为云计算安全运维工程师,杜老师很理解这种操作,但给站标也设置防盗链,是不希望他人的平台显示你的友链吗?如果心疼流量,可以贴图到评论区,去不图床愿意托管小伙伴的站标;

  3. 关站或故障请及时通知。友链页面除申请留言外,更多的是「杜老师我的友链怎么没有了」在此郑重声明,杜老师说绝对不会恶意下链。平台后端会监控友链网站的状态,当故障时间超过六小时,则提醒杜老师下链。而下链前,杜老师会通过 QQ 群、邮箱等一切手段与博主联系,希望能协助其尽快修复。如遇此种情况,留言提醒下杜老师即可;

  4. 本博客仅做同级别链接。顾名思义,您把杜老师说放在首页,这边就会做全站链;您把杜老师说放在内页,这边就会做内页链。目前 handsome 主题的首页链接、及部分主题的随机首页链接,同样会放在本站的全站链中,待数量过多时,杜老师会考虑放入内页,届时会有留言告知;

  5. 本博客支持付费单向链。杜老师深知免费才是成本最高的选择,故目前运行的平台均为大厂付费产品。为了维持博客运营,支持付费单向全站链接,目前的价格是 18 元每月「按每月份 31 天计算」支持支付宝及微信支付,需要的话留言即可。另如需要调整付费链接展示顺序,可选竞价服务,相同竞价者按时间顺序排列;

  6. 下链或换站请及时通知。遇到过一些骗链的「互链没两天就偷偷下链」还有一些想从头开始的,新站并未同步原来友链数据。还有一些不知道因什么原因,就直接下链了。因遇到较多次,杜老师都想弄个黑名单,然后在 GitHub 公开,防止小伙伴们中招,目前想法依在,想出现在榜首的可以联系杜老师!

友链福利

  1. 献上 IP 及评论。杜老师说通过友链文章采集,可以获得友链博客更新数据,当发现有新文章发布后,杜老师都会在每天固定时间送上 IP 及评论。因采集平台的限制,部分博客的 RSS 无法直接识别「也有部分博客没有提供 RSS 或禁用该项服务」杜老师也会定期去拜访;

  2. 提供技术支持。杜老师是通过技术支持养活这个博客以及旗下站点,不过友链博客的一些小问题,都可免费协助处理。且杜老师认识了很多热心的大佬,互帮互助解决很多问题,有问题别害羞,随时留言,会有大佬协助解决。

写在最后

聊一些与此文无关的事。杜老师说主题相对单一,都是围绕技术类的内容。

之前有小伙伴提到「这里好热闹啊,但是就看不懂」还因为杜老师拜访部分小伙伴时,其文章的专业性也使杜老师不知如何留言,只能弱弱的说「过来学习一下」

简单说下近况。徘徊在居家隔离与出差之间,昨天出差、今天上课、明天回京。所以一直未能腾出时间更新内容,导致博文写了一半定时任务就发布了出去,被误认为水文~

就写这么多吧,文笔不好,高考作文都是造句拼的,小伙伴们凑合看吧!

使用 MeiliSearch 实现 Volantis 主题博客搜索「保姆教程」

感谢柚子童鞋在杜老师的疯狂怂恿下为 Volantis 主题整合了 MeiliSearch 搜索引擎,并花费大量心思编写了相关教程,反正杜老师照着柚子童鞋的教程没做出来,不过在柚子童鞋的耐心帮助下最后还是成功实现了,这里记录下部署过程中可能遇到的坑。

写在前面

习惯水文的杜老师花了很长时间才下决心写下此文,教程太长没耐心看,看了又不愿意自行搭建,搭建了又遇到了更多的问题……

正文开始前先卖下队友,点击 这里 访问柚子童鞋写的教程。

历史背景

杜老师的博客再水,也将近 300 万字,检索文件 content.json 大小 1.42MB「还是调整后的,原有的超过 4M」

当有小伙伴使用搜索功能时,需完整加载 content.json 文件才可显示搜索结果,不仅影响体验还会产生较大流量。

之后换成了 Algolia 服务,但其最近节点位于香港,大陆访问速度较慢,且有 API 调用数限制。

在百度上疯狂谷歌之后,发现一款可自建的开源搜索引擎,就是 MeiliSearch 了。

杜老师第一时间推给了柚子童鞋,对方回复能搞!

再次感谢柚子童鞋,很快写好了教程并推送调用代码至 Volantis 主题库中。

服务搭建

杜老师是忠实的容器党,能用 Docker 的绝不考虑其它部署方法,以下是官方的部署命令,其中 MASTER_KEY 自定义,版本号 v0.28 可换成 latest

1
2
3
4
5
6
docker run -it --rm \
-p 7700:7700 \
-e MEILI_MASTER_KEY='MASTER_KEY' \
-v $(pwd)/meili_data:/meili_data \
getmeili/meilisearch \
meilisearch --env="development"

如果想用某塔 Docker 管理器部署,配置如图。但墙裂建议使用命令行部署,杜老师尝试用 Docker 管理器部署几次失败,最后定位问题属于玄学:

获取密钥

部署完成后通过 IP:7700,如能看到下图页面说明部署成功:

这页面好看吧,然而没啥卵用!官方建议使用 Postman 调试 MeiliSearch,并提供了调试文件,点击 这里 跳转至 Postman 页面,复制官方调试文件链接 https://docs.meilisearch.com/postman/meilisearch-collection.json 到 Link 标签项,导入即可:

将上文的 MASTER_KEY 填入 Token 框中:

切换至 Variables,将 url 处替换为 MeiliSearch 的域名,indexUID 建议使用 hexo,记得点击右上方 Save:

展开 MeiliSearch 进入 Key Management-Get keys,点击右侧 Send 即可获取 searchKey:

如若长期使用,建议使用生产模式部署,停用上面的实例后,使用下面命令重新部署:

1
2
3
4
5
6
docker run -d --restart=always \
-p 7700:7700 \
-e MEILI_MASTER_KEY='MASTER_KEY' \
-v $(pwd)/meili_data:/meili_data \
getmeili/meilisearch \
meilisearch --env="production" --no-analytics

调试使用

为保证每篇文章拥有一个唯一值,推荐用 hexo-uuid 插件,进入到博客目录后使用如下命令按照:

1
npm install hexo-uuid

安装完后,需要 blog/_config.yml 配置文件为如下内容:

1
2
3
4
5
6
7
8
jsonContent: 
meta: false
pages: false
posts:
title: true
path: true
text: true
uuid: true

使用如下命令完成检索文件推送:

1
2
3
4
curl -X POST 'https://yoursdomain.com/indexes/hexo/documents/?primaryKey=uuid' \
-H "Authorization: Bearer MASTER_KEY" \
-H "Content-Type: application/json" \
--data-binary '@public/content.json'

参考下面代码修改主题配置文件即可:

1
2
3
4
5
6
7
8
search:
enable: true
service: meilisearch # hexo, algolia, meilisearch
meilisearch:
placeholder: 'Search...'
searchKey: 'searchKey'
indexName: 'hexo'
hostUrl: 'https://m.dusays.com'

注意事项

杜老师在推送检索文件时遇到了全量推送问题,表现为搜索时出现大量重复结果,杜老师选择了最简单粗暴的解决方法,上传前调用删除接口清空数据库:

1
curl -X DELETE 'https://m.dusays.com/indexes/hexo' -H "Authorization: Bearer MASTER_KEY"

最后分享下杜老师的 GitHub Actions 配置文件:

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
name: CI
on:
push:
branches: [ "main" ]
workflow_dispatch:
schedule:
- cron: '30 16 * * *'
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- uses: actions/setup-node@v1
with:
node-version: '16.17'
- name: npm
run: |
npm i -g hexo-cli
npm i
- name: hexo
run: |
hexo g --silent
gulp
curl -X DELETE 'https://m.dusays.com/indexes/hexo' -H "Authorization: Bearer ${{secrets.MEILISEARCH_KEY}}"
curl -X POST 'https://m.dusays.com/indexes/hexo/documents/?primaryKey=uuid' -H "Authorization: Bearer ${{secrets.MEILISEARCH_KEY}}" -H "Content-Type: application/json" --data-binary '@public/content.json'
- name: Deploy
uses: peaceiris/actions-gh-pages@v3
with:
deploy_key: ${{ secrets.ACTIONS_DEPLOY_KEY }}
external_repository: penndu/my-website
publish_branch: master
publish_dir: ./public

通过 GitHub Actions 实现 Hexo 定时发布

经常会有小伙伴说杜老师总发穿越文,确实这种发布方式会让新伙伴一脸懵,且对搜索引擎不大友好。本文讲解如何通过 GitHub Actions 变相实现 Hexo 定时发布功能!

隐藏功能

其实 Hexo 根配置文件有个隐藏功能,通过调整 future 值可以实现是否显示当前时间点之后的文章。

为什么说隐藏功能,因为杜老师曾问了一圈,没一个知道的!

默认 future: true 时发布所有文章,改为 future: false 则隐藏当前时间点之后的文章。

需要注意的是,这里的隐藏指不生成该文章页面,而不是主页不显示。且到了文章的时间点后还需手动生成页面文件才可显示。

定时发布

这里借助 GitHub Actions 的计划任务功能实现,workflow 配置文件中加入如下代码即可:

1
2
schedule:
- cron: '30 16 * * *'

提示一下,GitHub Actions 和国内有时间差,杜老师设置每天 16 点 30 分部署后,实际部署时间为第二天 0 点 52 分,完整参考代码如下:

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
name: CI
on:
push:
branches: [ "main" ]
workflow_dispatch:
schedule:
- cron: '30 16 * * *'
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- uses: actions/setup-node@v1
with:
node-version: '16.17'
- name: npm
run: |
npm i -g hexo-cli
npm i
- name: hexo
run: |
hexo g --silent
gulp
- name: Deploy
uses: peaceiris/actions-gh-pages@v3
with:
deploy_key: ${{ secrets.ACTIONS_DEPLOY_KEY }}
external_repository: penndu/my-website
publish_branch: master
publish_dir: ./public

通过 GitHub Actions 将 Hexo 部署至良心云 CloudBase

部分主题如 Volantis 对 node 有版本要求,而 Web 应用托管无法指定 node 的版本,且直接推送 public 文件部署还会因为网络问题导致无法及时触发,本文讲解如何通过 GitHub Actions 解决该问题。

准备工作

首先登录良心云 CloudBase,获取 Web 应用托管对应环境 ID,记录一下等会要用:

进入访问管理——访问密钥,进入到 API 密钥管理,获取 SecretId 以及 SecretKey:

登录 GitHub 并进入博客的源码库,切换到 Settings-Secrets-Actions,分别添加红框变量,如 ENVID/SECRETID/SECRETKEY:

最后切换到 Actions-New workflow-set up a workflow yourself:

数据走向

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
name: CI
on:
push:
branches: [ "main" ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- uses: actions/setup-node@v1
with:
node-version: '16.17'
- name: npm
run: |
npm i -g hexo-cli
npm i
- name: hexo
run: hexo g --silent
- name: Deploy to Tencent CloudBase
uses: TencentCloudBase/cloudbase-action@v2.0.1
with:
secretId: ${{secrets.secretId}}
secretKey: ${{secrets.secretKey}}
envId: ${{secrets.envId}}

注意:以上为杜老师所用代码,替换原有内容,或根据现有内容做修改即可。

文件限制

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
{
"envId": "{{secrets.envId}}",
"version": "2.0",
"framework": {
"name": "gh-actions-test",
"plugins": {
"func": {
"use": "@cloudbase/framework-plugin-website",
"inputs": {
"outputPath": "public",
"ignore": [
".git",
".github",
"cloudbaserc.json"
]
}
}
}
}
}

注意:TencentCloudBase/cloudbase-action@v1 传输的文件不能超过一千,所以这里选择了 TencentCloudBase/cloudbase-action@v2.0.1,该版本执行需要在博客源码根目录中创建文件 cloudbaserc.json 并加入上面代码。

写在最后

  1. 以上方法适用于将博客所有源码托管至 GitHub 上,如只托管 public 目录内文件则需修改配置;

  2. 如 public 目录内的文件不超过 1000,可选择使用 TencentCloudBase/cloudbase-action@v1,该版本不需要在博客源码根目录中创建文件 cloudbaserc.json

  3. 默认强制全量推送策略,会删除 CloudBase 中原有的文件,使用该教程前请先做好数据备份;

  4. 偶尔会出现推送失败的提示,但实际测试已完成推送,无视即可。

Lsky Pro 企业版手动升级、优化教程

部分 Lsky Pro 企业版用户自行修改源码,如使用在线版本升级会覆盖已修改的文件。本文介绍如何使用手动升级,及图床程序的优化操作。

升级

使用管理账号登录图床后台,点击进入系统——系统设置——系统升级,下载新版本补丁包文件。合并补丁包文件至 Lsky Pro 程序源码后,在服务器终端执行如下命令应用更新:

1
composer update

上述命令执行完后,进入到数据库管理,执行如下语句升级版本,需要注意的是,其中的 V 1.1.1 根据升级版本修改:

1
UPDATE `configs` SET `value` = 'V 1.1.1' WHERE `configs`.`name` = 'app_version';

由于版本升级可能加入一些新的功能,需要修改数据库表,使用如下命令进行数据填充:

1
php artisan migrate --seed

版本升级后因文件改变可能导致网站报 500 错误,执行下面命令清理优化缓存即可:

1
php artisan optimize:clear

优化

项目部署到生产环境时,请确保您正在优化 Composer 的类自动加载器映射,以便 Composer 可以快速找到为给定类加载的正确文件:

1
composer install --optimize-autoloader --no-dev

下面命令会将 Laravel 的所有配置文件合并到一个缓存文件中,这大大减少了框架在加载配置值时必须访问文件系统的次数:

1
php artisan config:cache

下面命令将所有路由注册减少到缓存文件的单个方法调用中,从而在注册数百条路由时提高路由注册的性能:

1
php artisan route:cache

下面命令预编译所有 Blade 视图,因此它们不会按需编译,从而提高返回视图的每个请求的性能:

1
php artisan view:cache

有没有兴趣来抢个沙发

杜老师说建站至今,已经运营 1194 天,水文 514 篇。很多小伙伴把评论区当成聊天区,杜老师也会一一的回复并且回访,不过还有 62 篇文章还没有小伙伴临幸,已经整理出来,欢迎来抢沙发!

写在前面

这一天杜老师还在公司摸鱼,突然灵光一闪想清一波零评论的文章,好不容易有水文的机会必然不能错过!

杜老师使用 Artalk 评论系统,后端托管在 MySQL,导出 comments 表数据,筛选 page_key 项,这样即可将零评论文章整理出来「说的非常简单,做的时候还是蛮麻烦的」

文章列表

本想做成文章标题,但想想还是弄成盲盒比较好。友情提示,部分文章内有美女,欢迎前往留下您的脚印:

编号地址
1https://dusays.com/177/
2https://dusays.com/188/
3https://dusays.com/206/
4https://dusays.com/207/
5https://dusays.com/210/
6https://dusays.com/211/
7https://dusays.com/212/
8https://dusays.com/215/
9https://dusays.com/219/
10https://dusays.com/222/
11https://dusays.com/224/
12https://dusays.com/232/
13https://dusays.com/237/
14https://dusays.com/240/
15https://dusays.com/244/
16https://dusays.com/245/
17https://dusays.com/247/
18https://dusays.com/248/
19https://dusays.com/249/
20https://dusays.com/251/
21https://dusays.com/252/
22https://dusays.com/253/
23https://dusays.com/254/
24https://dusays.com/255/
25https://dusays.com/256/
26https://dusays.com/257/
27https://dusays.com/259/
28https://dusays.com/265/
29https://dusays.com/269/
30https://dusays.com/271/
31https://dusays.com/274/
32https://dusays.com/277/
33https://dusays.com/284/
34https://dusays.com/286/
35https://dusays.com/287/
36https://dusays.com/288/
37https://dusays.com/297/
38https://dusays.com/298/
39https://dusays.com/300/
40https://dusays.com/305/
41https://dusays.com/306/
42https://dusays.com/307/
43https://dusays.com/308/
44https://dusays.com/309/
45https://dusays.com/320/
46https://dusays.com/324/
47https://dusays.com/326/
48https://dusays.com/327/
49https://dusays.com/335/
50https://dusays.com/337/
51https://dusays.com/338/
52https://dusays.com/341/
53https://dusays.com/345/
54https://dusays.com/347/
55https://dusays.com/348/
56https://dusays.com/349/
57https://dusays.com/355/
58https://dusays.com/359/
59https://dusays.com/360/
60https://dusays.com/363/
61https://dusays.com/364/
62https://dusays.com/366/

杜老师说网站更新图解

想知道杜老师每次发布新文章时,网站的更新流程吗?耗时半天设计的流程图,展现杜老师卓越的艺术细菌!点进来看看吧~

更新图解

看懂的小伙伴记得评论:

流程详情

  1. 首先判断更新的是主题还是文章,如果是文章则直接上传至 GitLab;

  2. 如果是主题则通过 Webhook 触发服务器生成本地时间点标识文件并上传至 GitLab;

  3. GitLab 文件更新会触发 gitlab-runner 开始自动化构建;

  4. 进入指定目录「文章或是主题」开始同步最新代码;

  5. 如果是主题则执行清理数据缓存;

  6. 生成网站页面代码;

  7. 压缩网站页面代码;

  8. 网站源码上传至 GitHub;

  9. 触发 Vercel 获取源码后生成站点;

  10. 通过套路云 CDN 加速展示。

参与设备

自动构建所用到的设备是套路云的 ECS,配置为 1H2G。构建速度还算可以,但部署比较慢,最大瓶颈是 1M 的小水管!

代码托管在自家 NAS。配置不多说了,毕竟 GitLab 存储代码和触发事件都不需要太多资源。

写在最后

估计很多小伙伴看完杜老师的图解后,都会忍不住说一句:其实不用这么麻烦!

确实这道工序有些复杂。

有些小伙伴曾好奇杜老师是做什么的。杜老师是一枚不称职的云计算运维工程师,为什么说不称职呢?因为目前在 CEC 做云计算运维讲师,而且一做就是七年。

习惯大型集群架构的杜老师喜欢套用多种服务实现一个功能,让每一层独立处理自己的事。虽然效率不高,但和做人是一样的,最重要就是开心嘛!

坚持更新博客的动力是什么

博客圈子不断有新人的加入,也不断有老人退出。几乎每个月杜老师都会检查一下友情链接,看看哪些网站测掉了杜老师说的链接。而在这过程中,总会发现一些网站长久没有更新,还有一些网站,已然无法访问~

强迫症者

经常有小伙伴说文章的时间错了,为什么杜老师一直在更新穿越文「提前发布」

其实杜老师就是个强迫症加拖延症的患者,曾在《留言》中声称每三天更新一篇,不做到会浑身难受。

但有时候真的不知道该写什么好,有的时候又研究出有意思的技术,加上一些小伙伴的需求,总会突然更新多篇,而 Hexo 并没有定时发布的功能,所以杜老师就按照排期,一并发了出来,这就是各位小伙伴看到的穿越文!

不知道有多少的小伙伴和杜老师一样,通过强迫症迫使自己去更新博客,如果恰巧和杜老师一样,欢迎留言让杜老师知道,不是一个人在战斗!

习惯记录

朋友圈里不少的小伙伴,喜欢研究一些新奇的小玩意,有时候还会找到我交流。

在研究的过程中难免会遇到一些问题,每次解决之后,都会留下一篇笔记文章。

还有的小伙伴,会经常记录自己的生活。杜老师站在读者的角度,更加了解这些小伙伴的生活!

杜老师就非常喜欢记录,但自己的文笔不好,所以不会经常记录生活,加上本博主题就是技术分享,所以在本博中很少可以看到杜老师的生活分享,以后也许会有,敬请期待!

希望盈利

杜老师的友链圈中,还有一类博友,他们喜欢收集一些资源,然后付费分享。

或者提供一些收费服务,亦或站中加入大量广告。

首先杜老师要说明一点,本人不反感任何盈利性行为,毕竟建站本身就需要成本的。有些人可能不赞同,毕竟现在免费资源遍地都是。但大家都需要知道,维护时的精力和时间也算是成本,所以只要合理合法,大家应该都会支持。

杜老师目前的收费项目只有图床,实在是没办法,运营成本太大!而目前的付费收入远远不够支出,不过好在没有人再传违禁图片了,图片审核的成本降低了,而且每天不用提心吊胆担心链接被封,也知足了!

喜欢互动

常来杜老师博客的小伙伴都知道,在本博的每条评论,杜老师都会用心去回复,并且都会回访、留言。

杜老师很喜欢十年之约的一句话:一个人的寂寞,一群人的狂欢。

在社交平台如此繁多的时代,只有互访才能让博客不寂寞。

也喜欢杜老师说的博文,可以给小伙伴带来更多话题,让更多小伙伴加入互动,实现一群人的狂欢。

向 CODING 推送代码出现 Permission denied 的解决方法

杜老师说博客托管在腾讯云的 Webify,最近因 GitHub 的 Webhook 推送问题导致无法触发部署,故转移到了 CODING。在推送代码时出现 Permission denied 的问题,本文记录解决方法。

部署公钥

在推送代码前,我们需要将服务器的公钥部署到 CODING 上:

还可以添加到个人账户设置中 SSH 公钥一项。两者的区别是,前者只对指定项目有效,后者针对该用户的所有项目有效:

解决方法

部署公钥后使用 ssh -T git@e.coding.net 命令测试,会提示 Permission denied (publickey)。

如果是 Linux 系统,使用命令 vim /etc/ssh/ssh_config 在文件末尾加入以下代码:

1
2
3
Host *.coding.net
HostkeyAlgorithms +ssh-rsa
PubkeyAcceptedAlgorithms +ssh-rsa

如果是 Windows 系统,需先找到 Git 的安装目录,如 C:\Program Files\Git,则编辑配置文件 C:\Program Files\Git\etc\ssh\ssh_config 加入以下代码:

1
2
3
Host *.coding.net
HostkeyAlgorithms +ssh-rsa
PubkeyAcceptedAlgorithms +ssh-rsa

编辑完成后再试下 ssh -T git@e.coding.net,就不会提示 Permission denied (publickey),可正常推送代码了。

修改 GitLab 默认地址及端口

为了方便更新文章,杜老师使用 Docker 搭建 GitLab 做文章管理,后期迁移到群晖上,并做了外网的映射。迁移后需要修改 GitLab 的域名及端口,那么就分享下修改方法。

地址修改

查询绑定地址或 IP 的命令为:

1
grep ^external_url /etc/gitlab/gitlab.rb

如需修改绑定地址,则编辑文件/etc/gitlab/gitlab.rb:

1
external_url http://gitlab.dusays.com;

端口修改

如需修改修改端口,则编辑文件/etc/gitlab/gitlab.rb:

1
nginx['listen_port'] = 8080

记得取消注释。最后提醒任何配置修改完后,需要重跑一下配置:

1
gitlab-ctl reconfigure

如何将 Hexo 部署到 OSS

鉴于最近 GitHub 从中国大陆访问网速较慢,而且现在国内阿里云 OSS 支持将静态网站部署在上面,而且访问速度尚可。今天杜老师为大家介绍一款插件,可以将 Hexo 部署到 OSS。

准备工作

已搭建 Hexo 博客,如果还未搭建,可以参考《杜老师说同款博客搭建》一文。同时需拥有阿里云账号,注意部署静态网站需要实名认证,且域名需备案:

插件安装

1
npm i -S hexo-deployer-oss-aliyun

注意:在 Hexo 博客目录下执行上面的命令。

插件配置

1
2
3
4
5
6
deploy:
type: aliyunoss
region: Endpoint
bucket: Bucket
accessKeyId: AccessKey ID
accessKeySecret: AccessKey Secret

注意:在 Hexo 配置文件 _config.yml 中添加上面配置,并按实际情况修改,如有任何问题,可在评论区中留言。

写在最后

改好之后记得保存,保存好之后执行 hexo d,一般没问题的话就可以将 Hexo 生成的静态文件上传到 OSS 中。默认将文件上传到阿里云 OSS Bucket 根目录下,如需要部署到其它目录,在 deploy 下添加 remotePath 选项进行指定。

另外在创建阿里云 OSS Bucket 时,应将存储权限设置为公共读。

通过 Webify 部署 Hexo

Vercel 虽是免费的,但因为其服务器在国外,常会遇到访问不稳定的问题。最近良心云推出了个人站点扶持计划,不少已备案的小伙伴转到了国内托管,今天就分享下通过 Webify 部署 Hexo。

服务介绍

CloudBase Webify 为您的 Web 应用提供一站式托管服务,支持包括态网静站、动态 Web 服务等各种类型的 Web 应用,提供默认域名、可自定义域名、安全证书、CDN 加速等,提升 Web 应用的性能和安全性,此外提供基于 Git 的工作流、自动部署流程、加速开发部署流程,提供极佳体验。

可将博客/论坛/官网等任意形式的个人站点部署到 Webify,即可以申请获得扶持代金券,即实现零成本网站托管。

在线部署

进入良心云 Web 应用托管页面,点击页面中的新建应用:

在右侧从模板创建中找到 Hexo:

选择源码托管平台,并设置托管仓库名,然后点下一步:

在框架预设中,选择 Hexo 项,然后点击部署应用:

服务开始部署应用,待页面提示发布成功后,即可正常访问博客:

服务会免费送一个访问地址,不过该支持较长不容易记忆,可以自行添加域名,且支持 SSL:

通过 Vercel 部署 Hexo「主题」

如果不喜欢 Hexo 自带的默认主题,想换一个心仪的主题如何操作呢?今天就以杜老师用的这款 Volantis 作为演示,说一下如何更换 Hexo 主题。

写在前面

通过前两篇的教程,大家应该发现除了发布文章时固定的文章格式代码外,并没有其它的命令。参考杜老师的教程,可以实现仅用鼠标点击,就能创建一个博客。

本文较之前的教程相比,需要借助 GitHub 官方的 Desktop 工具才可实现无代码操作。如果了解 Git 的相关命令,也可直接通过命令操作。本站不提供 GitHub Desktop 下载地址,请自行搜索并下载安装,如需帮助可以在页面下留言。

操作步骤

安装好 GitHub Desktop 并打开后,首先需要登录账号,就可在工具中看到博客的部署源码所在仓库了,选择其并点击下方的 Clone:

点击 Clone 后,工具会提示仓库的地址,以及本地存放路径,根据需求可以修改本地存放路径:

通过浏览器访问心仪模板的页面,点击 Code 后选择 Download ZIP 下载模板文件:

返回 GitHub Desktop 点击 Repository,选择 Show in Explorer 即可打开博客的部署源码所在文件夹:

找到刚刚下好的模板压缩包,将里面的文件解压到 themes 目录:

记得修改下目录的名称,将其改为模板名称,下图中是未修改的演示:

返回到 GitHub Desktop,在图示的位置输入任意字符,点击 Commit to master 即可将模板文件上传至 GitHub:

通过 GitHub 访问博客的部署源码页面,点击进入到_config.yml 文件:

点击右侧的笔,即可进入修改模式:

将文件中设置项 theme 后的值改为主题的名称,最后点击 Commit changes 就行了。Vercel 会自动部署,待部署完成后即可看到博客换了新的主题:

通过 Vercel 部署 Hexo「发表」

我们在上文中讲解了如何部署 Hexo,本文主要说明如何通过 GitHub 在线更新博客的内容。当然,如果您熟悉 Git 相关操作,也可以 clone 到本地编辑并提交。

在线更新

登录自己的 GitHub 账号,在 Repositories 列表中找到存放源码的仓库:

进入保存博文的目录 source/_posts:

点击 Add file 添加一个新文件:

填写文件名称:

按照下图格式添加内容模板,并添加自己的内容:

编辑好内容后,点击 Commit new file 提交并自动部署:

博文模板

1
2
3
4
5
6
7
8
9
10
11
12
13
14
---
title: 标题
tags:
- 标签
categories:
- 分类
date: 2021-10-01 00:00:00
---

> 导语

<!-- more -->

正文

注意:可以添加多个标签、分类,按照上面格式,每行一个。导语一行可以省略。

通过 Vercel 部署 Hexo「部署」

也许您也想拥有一套自己的博客,方便面试的时候想展示自我,或者想记录自己的生活,但是一直没找到合适的平台;也许有一些自己的小玩意想部署到服务器,但是服务器又有点小贵,打工人又舍不得买,那么 Vercel 平台可能是您不错的选择,不用花钱,访问速度不错,域名也有!本文的主要目的是帮助想拥有自己的博客的小伙伴,提供一套完整博客搭建方案,那么现在就开干吧!

前言

以 Vercel 和 Hexo 作为关键词去搜索,会搜到一大堆教程,而且每一篇都非常详细。就会小伙伴会问了:杜老师为什么要重复的造轮子呢?

说实话我也不想这么做,奈何再详细的教程,还是会有些小伙伴不会操作,一个劲追问为什么。既然如此,贴心的杜老师就把每一步骤都截图在下面,并且尽量减少代码出现,让需要的小伙伴仅通过鼠标点击就可以完成 Hexo 部署。

介绍

Vercel 提供一个云平台,可优化整个项目开发和部署体验,它有强大的功能值得去探索,个人使用是免费的,提供域名访问,使用方便快捷:

Hexo 是一个基于 Node.js 的静态博客网站生成工具,命令操作简单,直接开箱使用,支持丰富主题,支持高度自定义化,主要用 Markdown 语法:

部署

首先使用 GitHub 用户登录 Vercel,如果没有 GitHub 可注册一个,这里就不再叙述了。如果不会操作,可在下面评论留言,杜老师会第一时间协助注册:

因为杜老师之前部署过一个站点,所以该页面会有所不同。不过都能看到右上方的新建项目:

支持从 GitHub 导入项目,但本次我们主题是通过 Vercel 全新部署 Hexo 博客,所以我们选右侧的查看所有模板:

在刷新的页面下方,即可看到 Hexo 项,点击开始部署:

我们首先将部署的代码,保存在 GitHub:

设置在 GitHub 仓库名称,点击创建,Vercel 会自动在 GitHub 中创建对应仓库,并将相关的代码存储在其中:

这里不做过多解释,问就是要收费,直接跳过即可:

接着 Vercel 开始全自动部署博客,稍等一会即可:

部署完成之后,页面会自动跳转并跳出烟花,杜老师手慢了没有截到,点击去仪表盘即可查看部署结果:

仪表盘中,我们能看到 Vercel 为我们提供的免费二级域名,使用该域名即可访问刚搭建好的博客:

结尾

杜老师不喜欢读长文更不喜欢写长文,所以完整搭建流程,会分为四个章节来更新,本篇仅讲述如何部署 Hexo,下一篇将更新如何更新文章,再一篇会更新如何安装插件,最后一篇更新如何使用模板。

杜老师会根据小伙伴的需求,考虑更新进阶教程,不过最终目标就是使用最少的代码完成 Hexo 的搭建和后期更新。有任何的问题及建议请在评论区留言,杜老师会尽快回复!

给公益图床提供者的一些小建议

最近发现一些小伙伴开始搭建起公益图床。去不图床已经运营近两年了,期间经历过很多事,也给杜老师提供了很多运营经验,在这里同小伙伴们分享一下,让公益更长久!

隐藏地址

总有些人对公益有一些误解,认为公益可能是好心的,但办的不一定就是好事。所以有些人发现公益图床后,可能会进行一些破坏性操作,比如直接攻击图床的服务器。

建议运营图床的小伙伴,尽可能在图床所在服务器前添加 CDN 等服务,隐藏服务器的真实地址,防止恶意用户攻击。

因去不图床的域名没有备案,且考虑到流量成本,所以杜老师选择了 Cloudflare 作为前置 CDN。

部分图床程序开启 CDN 后可能无法正常运行,可以开启 Cloudflare 的开发模式,这样请求端可与服务端直接通信,不再通过 CDN 的缓存,保障服务同时又隐藏了服务器的真实地址。

异地存储

建议异地存储主要是有两个原因。一是如果选择本地存储,随着存储图片量的增大,存储成本也会随之增大,后期升级及转移都非常麻烦。

二是相比图床源码所在的服务器,存储服务器的运行维护更少,也更不容易出问题。所以当图床服务器出问题时,存储服务器还可以持续提供服务,仅会影响上传,但不影响调用已上传的图片。

经过多个云服务商的对比后,杜老师最终选择又拍云存储及 CDN,对比条件非常简单,在可正常提供服务的情况下,费用最低。

有些小伙伴可能会提到云存储及 CDN 的性能,对于存储来说无非就是上传数据,而调用数据时,则是 CDN 在发挥作用。对于静态图片文件来说,对这些的要求都非常小。

图片审核

不管服务器在国内还是国外,只要通过大陆网络访问,就必然要合法合规。

我们无法把控用户上传哪些图片,但是我们可以把控图片的合法合规性。人为审核也好,通过 API 调动云服务进行审核也罢,总之要保障上传图片的合法合规。

如果资金充足,可以使用云服务商提供图片审核服务,比如腾讯云 COS 配合数据万象,当出现违规图片时,数据万象会自动将 COS 中的图片设置成禁止访问的权限。

如果资金不足,可以使用免费的 API,国内国外有很多免费的图片审核网站,可以提供一定免费额度。当然,随着上传量的增大,转为收费是不可避免的。

不要放弃

随着图片数量增多,外链图片访问量的增大,存储成本、流量成本也会越来越大,很多小伙伴都是因为承受不住而选择放弃。

在这里建议这些小伙伴,要么不做,要做就请坚持,毕竟用户上传的图片可能此刻正在网络的一个小角落被调用,一个放弃很有可能导致用户整站无法正常访问,且无法再找回图片数据。

搭建好图床后,除了宣传之外,还有两件事需要做。

第一件事就是平衡成本。公益不代表零成本,图床程序所在的服务器、保留图片数据的云存储、用于加速访问的 CDN,这都是不小的花销,如果只有出项没有进项,那么图床必然无法坚持下去。

有的小伙伴会说不是公益图床吗?为什么还收费?首先可以拆成两个部分,比如免费功能、收费服务。其次可以考虑赞助,相信会有很多小伙伴都不希望一个优秀的图床宣告停用。

另一件则为无限优化以降低成本。随着用户量的增加,访问量和数据量会随之增加,当达到一个临界点,图床运行相关环境也不得不升级。而我们要做的,就是尽可能的优化这个运行环境,使其可以服务更多用户,减少升级成本,毕竟减少成本就是变相增加图床寿命!

Blogger 选程序的那些事

杜老师之前就是一枚 WPer,后来因为 WordPress 太过于臃肿,不想再折腾了,所以选择了 Hexo。不过最近又遇到了新的问题……

WordPress 的优缺

WordPress 的优点可真不少,首先使用人群基数较大。据不完全统计,十个网站就有三个是 WordPress 创建,而且还不都是博客。这也带出其第二个优点,拓展性强,几乎我们所需要的功能,都可以通过插件来实现,甚至某些大牛,可以直接上手修改代码。因为人群基数关系,也有不少前端工程师们为其开发模板,所以我们可以很容易在 WordPress 平台中,找到心仪模板。

再说一个优点,也是因为人群基数大的关系,技术支持丰富,随便找个博客圈里问问,都能解决当下问题,省时省力。

夸赞完了该说说缺点了。第一个缺点是臃肿,为了让其更具备扩展性,程序作者为其加入不少函数,很多都是普通用户不需要的,所以代码十分臃肿。接下来是效率,WordPress 不仅耗费服务器资源,而且执行效率低下,作为一个依赖 MySQL 数据存储的程序,竟然不做 SQL 的优化,在服务器上经常可以看到关于 WordPress 的慢查询语句,而且偷偷的说,MySQL 的临时缓存加速对其无效,别问我为什么。

最后一个就是用出问题。你本想安静的这篇文章,却经常因为程序或插件,亦或者是模板升级带来一些问题,轻则无法正常使用,重则数据丢失,你的时间都浪费在处理这些问题上了。导致杜老师放弃 WordPress 最主要的原因是它的量级比较重,700 篇博客竟然需要 4H8G 的配置才能带动,也可能是杜老师没优化好的关系。

Hexo 的优缺

轻量部署、成本很低、定制性强、安全性高。

轻量部署,Hexo 并不需要复杂的网站运行环境,只需要支持 Node.js 即可,几条命令就可实现 Hexo 的安装使用。

成本很低,如果只是为了记录,对服务端的要求并不高,可以选择免费网站托管平台。如想自建托管平台,也不需要太高的服务器配置,入门级云主机配置即可实现超强并发。

定制性强,Hexo 外观及功能实现,大多都依赖于模板,而模板的使用及修改都非常简单,并不像 WordPress 那样需要掌握 PHP 语言才可以。

安全性高,生成的页面为 HTML 的格式,没有动态文件产生,不会出现 SQL 语句注入等安全问题。

功能有限、模板有限、容易出错、需要扩展。

功能有限,既然是 HTML,没有数据库的支持,功能方面必然有限。

模板有限,相比较 WordPress,Hexo 的模板不是很多,而且大多都是个人作者,不像 WordPress 有企业级模板作者。

容易出错,Hexo 本身还好些,不过其依赖的 Node.js 可能会报错,而且某些报错比较神奇,同样的环境有人没问题,有人就会报错。

需要扩展,很多功能都依赖第三方服务,如评论等。

目前状况

上述缺点还是比较好的,毕竟玩博客这么久,早已没有折腾的心,就想安静的写个文。且目前 Hexo 具备的功能可以满足杜老师需求,所以对 Hexo 来说还是比较满意。

只是随着文章数量增多,生成页面时间越来越长,其中优化过很多次「升级版本、修改参数」均未能提高其效率,所以想换一个程序。

我的需求

希望这款程序可以将.md 文件直接转换博客文章,毕竟.md 的备份修改都很方便。可以的话,最好是拥有自身的评论系统,依赖第三方整合性较差,且 Hexo 目前支持的第三方评论工具,大多都需要将数据存于其它位置,这种动态数据不管备份还是管理起来都很麻烦,数据放在自己手里才更放心。

之前有小伙伴推荐过 Ghost 以及 Hugo 等,但测试的效果不尽人意,期待有天能遇到心仪的博客程序,也欢迎大家的推荐!

通过 npm 调整 Node.js 版本

用了一段时间最新版的模板,发现问题还挺多的,虽说人生贵在折腾,但踏踏实实的写文章不香吗?所以杜老师将模板从测试版降低到正式版,重新部署的过程中报错,发现是 Node.js 的版本导致的,今天就来说下如何通过 npm 来调整 Node.js 的版本。

问题重现

1
2
3
4
5
6
7
(node:2058) Warning: Accessing non-existent property 'lineno' of module exports inside circular dependency
(Use `node --trace-warnings ...` to show where the warning was created)
(node:2058) Warning: Accessing non-existent property 'column' of module exports inside circular dependency
(node:2058) Warning: Accessing non-existent property 'filename' of module exports inside circular dependency
(node:2058) Warning: Accessing non-existent property 'lineno' of module exports inside circular dependency
(node:2058) Warning: Accessing non-existent property 'column' of module exports inside circular dependency
(node:2058) Warning: Accessing non-existent property 'filename' of module exports inside circular dependency

注意:在使用 hexo g 部署博客的页面时,报出上面错误。说是错误,其实只是警告信息,如不在意,可以忽略。但杜老师有强迫症,一定要解决该问题!

查看版本

通过 npm -v 可以查看 npm 版本:

1
2
root@dusays:~# npm -v
6.14.8

通过 node -v 可以查看 Node.js 版本:

1
2
root@dusays:~# node -v
v12.18.2

安装工具

1
2
3
4
root@dusays:~# npm i -g n
/usr/local/bin/n -> /usr/local/lib/node_modules/n/bin/n
+ n@7.3.0
added 1 package from 2 contributors in 4.265s

注意:使用 npm i -g n 命令安装Node.js 版本管理器。

调整版本

使用 n stable 安装稳定版:

1
2
3
4
5
6
7
8
9
10
root@dusays:~# n stable
installing : node-v14.17.3
mkdir : /usr/local/n/versions/node/14.17.3
fetch : https://nodejs.org/dist/v14.17.3/node-v14.17.3-linux-x64.tar.xz
installed : v14.17.3 (with npm 6.14.13)

Note: the node command changed location and the old location may be remembered in your current shell.
old : /usr/bin/node
new : /usr/local/bin/node
To reset the command location hash either start a new shell, or execute PATH="$PATH"

使用 n 12 安装指定版,通过 n 12.22 指定子版本:

1
2
3
4
5
root@dusays:~# n 12
installing : node-v12.22.3
mkdir : /usr/local/n/versions/node/12.22.3
fetch : https://nodejs.org/dist/v12.22.3/node-v12.22.3-linux-x64.tar.xz
installed : v12.22.3 (with npm 6.14.13)

杜老师说同款博客搭建

考虑网站运营成本,前段时间更换了服务器,所有服务环境需要重新部署,故写此文作为记录,也方便相同环境的朋友们做借鉴。如果有建议或遇到问题,欢迎在页面中评论与杜老师交流!

安装工具

1
2
apt update
apt -y install docker.io gdebi-core git npm

注意:docker.io 为评论后端所需,gdebi-core 用于安装 OSS 挂载工具,git 和 npm 是 Hexo 必备的工具。

评论后端

1
2
3
4
5
6
7
8
tee /etc/docker/daemon.json <<-'EOF'
{
"registry-mirrors": ["https://xxxxxxxx.mirror.aliyuncs.com"]
}
EOF
systemctl restart docker
docker run -d --restart=always -e MYSQL_HOST=HOSTNAME -e MYSQL_DB=DATABASE -e MYSQL_USER=USERNAME -e MYSQL_PASSWORD=PASSWORD -e SITE_NAME=杜老师说 -e SITE_URL=https://dusays.com -e IPQPS=0 -e SECURE_DOMAINS=dusays.com -e AKISMET_KEY=false -e AUTHOR_EMAIL=EMAILADDRESS -e SMTP_SERVICE=QQ -e SMTP_USER=EMAILADDRESS -e SMTP_PASS=PASSWORD -e GITHUB_ID=GITHUBID -e GITHUB_SECRET=GITHUBSECRET -p 8360:8360 lizheming/waline
docker run -d --restart=always --name watchtower -v /var/run/docker.sock:/var/run/docker.sock containrrr/watchtower

注意:首先添加了阿里云的镜像加速器,加速 Docker 镜像的下载速度。然后运行评论后端,最后运行容器版本自动更新工具,感兴趣的可以参考《通过 Watchtower 实现 Docker 容器自动更新》一文。

挂载存储

1
2
3
4
5
6
7
8
9
10
11
12
wget https://gosspublic.alicdn.com/ossfs/ossfs_1.80.6_ubuntu18.04_amd64.deb?spm=a2c4g.11186623.2.6.20e22315wihlec&file=ossfs_1.80.6_ubuntu18.04_amd64.deb
gdebi ossfs_1.80.6_ubuntu18.04_amd64.deb
echo BucketName:yourAccessKeyId:yourAccessKeySecret > /etc/passwd-ossfs
chmod 640 /etc/passwd-ossfs
mkdir /dusays
ossfs BucketName mountfolder -o url=Endpoint
tee /etc/rc.local <<-'EOF'
#!/bin/bash
ossfs BucketName mountfolder -o url=Endpoint
exit 0
EOF
chmod +x /etc/rc.local

注意:杜老师说运行于阿里云的 OSS,并通过 CDN 加速,故需安装并挂载 OSS。

安装程序

1
2
npm i -g hexo-cli
hexo init blog

注意:安装 Hexo 并生成博客目录。

相关模块

1
2
cd blog/
npm i -S hexo-generator-baidu-sitemap hexo-generator-feed hexo-generator-json-content hexo-generator-search hexo-pdf hexo-wordcount

注意:进入博客目录,安装 Hexo 的相关模块。

下载文件

1
2
3
4
5
6
vim _config.yaml
git config --global http.proxy http://dusays.com
git config --global user.email EMAILADDRESS
git config --global user.name USERNAME
git clone ssh://git@dusays.com/penndu/dusays.git source/
git clone https://github.com/penndu/hexo-theme-volantis themes/volantis

注意:杜老师说的文章和模板都托管在 Git 上,通过 git clone 下载到服务器中。

添加缓存

1
2
echo '/swapfile none swap sw 0 0' > /etc/fstab
swapon -a

注意:为了保障服务器系统的稳定,添加交换分区,如果添加失败,可以参考《初始化 CentOS7 系统「上篇」》一文。

生成页面

1
2
ln -s /dusays/ public
hexo g

注意:将 OSS 挂载目录与 Hexo 页面生成目录建立链接,即可生成网站页面。

GitLab 配合云主机实现持续集成

GitLab Runner 是一个与 GitLab CI/CD 配合使用以在管道中运行作业的应用程序。您可以选择在拥有或管理的基础设施上安装 GitLab Runner 应用程序。GitLab Runner 还可在 Docker 容器内运行或部署到 Kubernetes 集群中。

下载

如果是 Debian 或 Ubuntu,运行以下命令:

1
wget https://gitlab-runner-downloads.s3.amazonaws.com/latest/deb/gitlab-runner_amd64.deb

如果是 CentOS 或 Red Hat Enterprise Linux,运行以下命令:

1
wget https://gitlab-runner-downloads.s3.amazonaws.com/latest/rpm/gitlab-runner_amd64.rpm

安装

如果是 Debian 或 Ubuntu,运行以下命令:

1
dpkg -i gitlab-runner_amd64.deb

如果是 CentOS 或 Red Hat Enterprise Linux,运行以下命令:

1
rpm -i gitlab-runner_amd64.rpm

如若出现以下错误提示,说明 Git 和 cURL 命令未安装:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
root@dusays:~# dpkg -i gitlab-runner_amd64.deb
(Reading database ... 198268 files and directories currently installed.)
Preparing to unpack gitlab-runner_amd64.deb ...
Unpacking gitlab-runner (14.0.1) over (14.0.1) ...
dpkg: dependency problems prevent configuration of gitlab-runner:
gitlab-runner depends on git; however:
Package git is not installed.
gitlab-runner depends on curl; however:
Package curl is not installed.

dpkg: error processing package gitlab-runner (--install):
dependency problems - leaving unconfigured
Errors were encountered while processing:
gitlab-runner

运行下面的命令安装 Git 和 cURL:

1
2
apt -y install git curl # for Debian or Ubuntu
yum -y install git curl # for CentOS or Red Hat Enterprise Linux

注册

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Runtime platform                                    arch=amd64 os=linux pid=5349 revision=c1edb478 version=14.0.1
Running in system-mode.

Enter the GitLab instance URL (for example, https://gitlab.com/):
https://dusays.com/
Enter the registration token:
xxxxxxxxxxxxxxxxxxxx
Enter a description for the runner:
[dusays]:
Enter tags for the runner (comma-separated):

Registering runner... succeeded runner=FKPxD53P
Enter an executor: virtualbox, docker+machine, kubernetes, custom, parallels, shell, ssh, docker, docker-ssh, docker-ssh+machine:
custom
Runner registered successfully. Feel free to start it, but if it's running already the config should be automatically reloaded!

注意:首先输入 GitLab 的地址,然后复制项目——设置——CI/CD 中找到 token 值,再者输入 runner 的描述用于分辨,接着输入 runner 的 tags 可为空,最后设置执行方式即可。

设置

进入 GitLab 项目中,按照下图所示找到 runner 配置文件添加处,参考下面代码进行配置:

参考代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
stages:
- build
- test

build-code-job:
stage: build
script:
- echo "Check the ruby version, then build some Ruby project files:"
- ruby -v
- rake

test-code-job1:
stage: test
script:
- echo "If the files are built successfully, test some files with one command:"
- rake test1

test-code-job2:
stage: test
script:
- echo "If the files are built successfully, test other files with a different command:"
- rake test2

如何通过两款工具实现最佳效果

textlint 在转换 md 文件时只会处理正文的部分,而 pangu 在转换时对内容的判断不太友好,使得转换后的格式不尽人意。今天杜老师说一下如何通过两款工具实现最佳效果。

分别转换

将需要转换的文件保存至 DIR1 目录「DIR1 为目录名称,可自定义,下同」另外新建 DIR2 目录用于存放 pangu 转换的文件,执行以下脚本:

1
2
3
4
5
#!/bin/bash
for i in DIR1/*
do
pangu -f $i >> DIR2/$i
done

然后使用 textlint 转换 DIR1 目录中的文件,命令如下:

1
textlint --fix *

整合文件

接下来我们将两个工具转换后的文件合并,我们使用 pangu 转换文件的头部,textlint 转换文件的正文部门。首先新建保存整合文件的目录 DIR3,然后执行下面脚本,其中 N 为头部行数:

1
2
3
4
5
#!/bin/bash
for i in DIR2/*
do
head -N DIR2/$i >> DIR3/$i
done

将下面脚本中 N 的值设置与上面相同,执行即可整合正文部分「补上一句:两个脚本可以合成一个,感兴趣的可以尝试一下,非常简单」

1
2
3
4
5
6
7
#!/bin/bash
for i in DIR1/*
do
j=`cat $i | wc -l`
k=$[$j+1]
sed -n "N,$[k]p" $i >> DIR3/$i
done

如何通过脚本实现 pangu 批量格式化

相比较 textlint,pangu 可实现全文格式转换,不过其仅可以针对单个文件进行转换,杜老师说一下如何通过脚本实现 pangu 批量格式化。

脚本

1
2
3
4
5
#!/bin/bash
for i in OLD/*
do
pangu -f $i >> NEW/$i
done

注意:将上述脚本保存为执行文件,将需要转换的文件保存至 OLG 目录「OLG 为目录名称,可自定义,下同」转换后的文件会存入 NEW 目录。

思路

脚本中使用 for 循环遍历目录中的所有文件,并将文件名称赋值给变量 i。

pangu 通过变量 i 确定需转换的文件,并以原文件名保存至 NEW 目录。

pangu 自动格式化工具

上文中提到的自动格式化工具仅能针对正文的内容进行处理,如需处理全篇内容,可以尝试 pangu 自动格式化工具!

安装

pangu 有多种执行语言,包括 Go/Java/JavaScript/Python 等,本篇以 Python 为例,演示如何安装:

1
pip install -U pangu

使用 pip 工具 pangu ,需要安装依赖,以Ubuntu为例:

1
sudo apt -y install python3-pip

使用

1
pangu -f OLD.txt >> NEW.txt

注意:pangu仅可以针对单个文件进行转换,可通过 pangu -f OLD.txt 查看转换结果,然后再通过上面命令写入到文件。

textlint 自动格式化工具

textlint 这款开源工具由一位日本的开发者制作,其灵感源于代码自动格式化工具。textlint 使用 JavaScript 实现,我们可以通过编写一系列脚本来实现对文本内容和格式检查的各类个性化需求。

安装

正式使用 textlint 之前我们需要先执行安装步骤。textlint 基于 JavaScript 语言实现,其安装通过 npm 包管理工具来安装:

1
npm install textlint --global

前提是环境已安装了 Node.js和 npm 依赖,如未安装可以参考如下命令,以Ubuntu为例:

1
sudo apt -y install npm

用法

安装自动添加中英文空格的规则:

1
npm install textlint-rule-ja-space-between-half-and-full-width --global

通过终端切换到需要执行格式化目录下方,textlint 支持多层级目录和多文件批量处理,所以一般切换至项目根目录下方即可。然后执行下面命令初始化 textlint 针对该目录的配置文件,执行后会自动生成一个名为.textlintrc 的配置文件:

1
textlint --init

接下来向配置文件中添加相应的规则:

1
2
3
4
5
6
7
8
{
"filters": {},
"rules": {
"ja-space-between-half-and-full-width": {
"space": "always"
}
}
}

最后通过 textlint 实现对指定文件自动添加空格,执行:

1
textlint --fix *.md

中文文案排版指北

古人云打字的时候不喜欢在中文和英文之间加空格的人,感情路走得很辛苦,有七成的比例会在34岁的时候跟自己不爱的人结婚,而其余三成的人最后只能把遗产留给自己的猫。毕竟爱情跟书写都需要适时留白。统一中文文案排版,不仅可以提高访客访问体验,还可增强网站气质。今天分享一下杜老师的排版经验!

空格

中文与英文数字之间需增加空格:

正确错误
去不图床数据存放在阿里云的 OSS 上面去不图床数据存放在阿里云的OSS上面
去不图床已经托管 40000 多张图去不图床已经托管40000多张图

数字与单位间无需增加空格:

正确错误
去不图床数据已达到 15GB 以上去不图床数据已达到 15 GB 以上

温度、百分比与数字之间不需增加空格:

正确错误
今天是 40° 高温今天是 40 ° 高温
去不图床有高达 95% 的缓存命中率去不图床有高达 95 % 的缓存命中率

全角标点与其他字符之间不需加空格:

正确错误
去不图床网址是 7bu.top,很好记吧!去不图床网址是 7bu.top ,很好记吧!

标点

不重复用标点符号:

正确错误
我们的网站好快呀!我们的网站好快呀!!!
您感觉去不图床好用吗?您感觉去不图床好用吗???

使用全角中文标点:

正确错误
我们的网站好快呀!我们的网站好快呀!

数字使用半角字符:

正确错误
去不图床已经托管 40000 多张图去不图床已经托管 40000 多张图

英文整句、特殊名词,其內容用半角标点:

正确错误
Good good study, Day day up.Good good study,day day up。

名词

专有名词使用正确的大小写:

正确错误
杜老师说评论可使用 GitHub 登录杜老师说评论可使用 github 登录

不要使用不地道的缩写:

正确错误
压缩 JavaScript 可能会造成页面错误压缩 js 可能会造成页面错误

特色

链接之间增加空格:

正确错误
上传图片点击 这里上传图片点击 这里

简体中文使用直角引号:

正确错误
去不图床支持「鉴黄」功能去不图床支持“鉴黄”功能

Waline 评论系统贴图 API 设置示例

有小伙伴留言问到我的评论系统是如何整合去不图床的,在这里分享两个 API 设置示例,希望可以帮到有需要的博主,同时欢迎使用去不图床!

API 设置示例一

如果您和杜老师同样使用 Volantis 作为主题,那么仅需要在主题_config.yml 文件中,找到 Waline 设置项,加入 imageHosting: https://7bu.top/api/upload 就行了,注意该段是以去不图床为例:

1
2
3
4
5
6
7
8
9
10
11
12
13
waline:
js: https://cdn.jsdelivr.net/npm/@waline/client/dist/Waline.min.js
path: # 全局评论地址 目前设置全局评论地址后visitor失效,这是waline的问题
placeholder: 允许匿名评论,评论支持贴图,大家在截图后,在评论框粘贴,自动传至图床,欢迎使用体验~ # 评论占位提示
imageHosting: https://7bu.top/api/upload # 图床api「默认使用去不图床」
# 其他配置项按照yml格式继续填写即可 除了 [el path placeholder uploadImage] 选项
meta: [nick,mail,link] # waline comment header info
requiredFields: [nick,mail]
serverURL: https://n.dusays.com # Waline 的服务端地址「必填」 测试用地址: https://waline-ruddy.vercel.app
avatar: robohash # gravatar style https://waline.js.org/client/basic.html#avatar
pageSize: 10 # 评论每页显示数量
lang: zh-CN
visitor: true

API 设置示例二

如果您使用的其它主题,可按照官方设置加入 uploadImage 即可,具体参考如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<head>
..
<script src='//cdn.jsdelivr.net/npm/@waline/client/dist/Waline.min.js'></script>
...
</head>
<body>
...
<div id="waline"></div>
<script>
new Waline({
el: '#waline',
path: location.pathname,
serverURL: 'https://your-domain.vercel.app'
uploadImage: function(file) {
const formData = new FormData();
formData.append('image', file);
return fetch('https://7bu.top/upload/upload.html', {
method: 'POST',
body: formData
}).then(resp => resp.json()).then(resp => resp.data.url);
}
});
</script>
</body>

正向、反向代理区别

正向代理是一个位于客户端和目标服务器之间的服务器,为了从目标服务器取得内容,客户端向代理服务器发送一个请求并指定目标,然后代理服务器向目标服务器转交请求并将获得的内容返回给客户端。

正向代理介绍

这种代理其实在生活中是比较常见的,比如访问谷歌网站技术,其用到的就是代理技术。

用户想要访问某国外的网站,该网站无法在国内直接访问,但是我们可以访问到一个代理服务器,这个代理服务器可以访问到这个国外网站。这样用户对该国外网站的访问就需要通过代理服务器来转发请求,并且该代理服务器也会将请求的响应再返回给用户。这个上网的过程就是用到了正向代理。

所以,正向代理,其实是代理服务器代理了客户端,和目标服务器进行交互。

通过正向代理服务器访问目标服务器,目标服务器是不知道真正的客户端是谁的,甚至不知访问自己的是一个代理。

正向反向区别

  1. 正向代理其实是客户端代理,帮助客户端访问其无法访问的服务器资源。反向代理则是服务器的代理,帮助服务器做负载均衡、安全防护等等;

  2. 正向代理一般是客户端架设,如在自己的机器上安装一个代理软件。而反向代理一般是服务器架设的,比如在自己的机器集群中部署一个反向代理服务器;

  3. 在正向代理中,服务器不知道真正的客户端到底是谁,以为访问自己的就是真实客户端。而在反向代理,客户端不知道真正的服务器是谁,以为自己访问的是真实的客户端;

  4. 正向代理、反向代理的作用和目的不同。正向代理主要是来解决访问限制问题。而反向代理是提供负载均衡、安全防护等等作用。二者均能提高访问速度。

常见 Web 引擎的反向代理配置参考

反向代理是指以代理服务器来接受 internet 上的连接请求,然后将请求转发给内部网络上的服务器,并将从服务器上得到的结果返回给 internet 上请求连接的客户端,此时代理服务器对外就表现为一个反向代理服务器。

反向代理介绍

反向代理在计算机网络中是代理服务器的一种。服务器根据客户端请求,从其关系的一组或多组后端服务器上获取资源,然后再将这些资源返回给客户端,客户端只会得知反向代理的地址,而不知道在代理服务器后面服务器集群的存在。通过反向代理服务器访问目标服务器时,客户端是不知道真正的目标服务器是谁的,甚至不知道自己访问的是一个代理服务器。

反向代理用途:

  1. 隐藏服务器真实 IP。使用反向代理,可以对客户端隐藏服务器的地址;
  2. 负载均衡。反向代理服务器可以做负载均衡,根据所有真实服务器的负载情况,将客户端请求分发到不同的真实服务器上;
  3. 提高访问速度。反向代理服务器可以对于静态内容及短时间内有大量访问请求的动态内容提供缓存服务,提高访问速度;
  4. 提供安全保障。反向代理服务器可作为应用层防火墙,为网站提供对基于 Web 的攻击行为例如 DDoS 的防护,更容易排查恶意软件等。还可为后端服务器统一提供加密和 SSL 加速,提供 HTTP 访问认证等。

引擎配置示例

Apache 的配置示例:

1
2
3
4
5
6
7
8
#PROXY-START/
<IfModule mod_proxy.c>
ProxyRequests Off
SSLProxyEngine on
ProxyPass / http://127.0.0.1:8080/
ProxyPassReverse / http://127.0.0.1:8080/
</IfModule>
#PROXY-END/

Nginx 的配置示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#PROXY-START/
location /
{
proxy_pass http://127.0.0.1:8080;
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 REMOTE-HOST $remote_addr;

add_header X-Cache $upstream_cache_status;

#Set Nginx Cache

add_header Cache-Control no-cache;
expires 12h;
}

#PROXY-END/

OpenLiteSpeed 的配置示例:

1
2
3
4
5
6
7
8
9
extprocessor 反代示例 {
type proxy
address http://127.0.0.1:8080
maxConns 1000
pcKeepAliveTimeout 600
initTimeout 600
retryTimeout 0
respBuffer 0
}

运行在云主机的 Hexo

很多选择 Hexo 的朋友,都会将其架设到 GitHub 上面,毕竟 GitHub 提供 Web 服务是免费的,但其访问的速度确实不太尽人意。我们如果想将 Hexo 运行在云主机上,又该如何去操作呢?

准备工作

首先拥有一台主机,在这里我们选择硅云的主机作为演示,并安装 CentOS 最新版本,感兴趣的小伙伴也可以通过本站右侧广告栏进入到官网选购。

其次准备一个远程控制工具,像杜老师用的是 FinalShell。这里并无明确软件要求,可以连接并控制主机就行了。

运行环境

第一步安装 Node.js 及 npm,Node.js 是 Hexo 的环境支持,npm 可以安装 Hexo,一般安装其中一个,另一个会自动安装:

1
2
yum -y install nodejs
yum -y install npm

第二步安装 Git 工具,npm 安装 Hexo 时通过 Git 进行下载操作,默认安装 git 时会自动安装 git-core:

1
2
yum -y install git-core
yum -y install git

第三部开始安装 Hexo,并初始化博客目录,BLOGDIR 处可自定义:

1
2
npm install hexo-cli -g
hexo init BLOGDIR

最后生成站点页面文件即可,这里我们定义 BLOGDIR 项为 blog:

1
2
cd blog/
hexo g

设置访问

接下来安装 Web 引擎,这里我们选 Apache,记得安装好后启用服务:

1
2
yum -y install httpd
systemctl start httpd

通过软链形式替换掉 Web 站点目录,使 Apache 可以读取 Hexo 生成的页面文件,这里我们假设 blog 目录在 root 中:

1
2
3
4
cd /root/blog/
rm -rf /var/www/html/
mv public/ /var/www/html
ln -s /var/www/html/ public

流程演示

点击播放:

asciicast

Apache 主配置、站点配置文件参考

我们在搭建网站时,为了方便管理,常常会选用 PHP+MySQL 这种架构,Web 引擎可选择 Apache 或是 Nginx。今天杜老师说一下,选择 Apache 时,主配置文件和站点配置文件如何改写!

Nginx 主配置文件

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
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
ServerRoot "/www/server/apache"
Listen 80
Listen 443
LoadModule authn_file_module modules/mod_authn_file.so
LoadModule authn_core_module modules/mod_authn_core.so
LoadModule authz_host_module modules/mod_authz_host.so
LoadModule authz_groupfile_module modules/mod_authz_groupfile.so
LoadModule authz_user_module modules/mod_authz_user.so
LoadModule authz_core_module modules/mod_authz_core.so
LoadModule access_compat_module modules/mod_access_compat.so
LoadModule auth_basic_module modules/mod_auth_basic.so
LoadModule reqtimeout_module modules/mod_reqtimeout.so
LoadModule ext_filter_module modules/mod_ext_filter.so
LoadModule filter_module modules/mod_filter.so
LoadModule deflate_module modules/mod_deflate.so
LoadModule mime_module modules/mod_mime.so
LoadModule log_config_module modules/mod_log_config.so
LoadModule env_module modules/mod_env.so
LoadModule expires_module modules/mod_expires.so
LoadModule headers_module modules/mod_headers.so
LoadModule setenvif_module modules/mod_setenvif.so
LoadModule version_module modules/mod_version.so
LoadModule remoteip_module modules/mod_remoteip.so
LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_connect_module modules/mod_proxy_connect.so
LoadModule proxy_ftp_module modules/mod_proxy_ftp.so
LoadModule proxy_http_module modules/mod_proxy_http.so
LoadModule proxy_fcgi_module modules/mod_proxy_fcgi.so
LoadModule proxy_scgi_module modules/mod_proxy_scgi.so
LoadModule proxy_wstunnel_module modules/mod_proxy_wstunnel.so
LoadModule proxy_ajp_module modules/mod_proxy_ajp.so
LoadModule proxy_balancer_module modules/mod_proxy_balancer.so
LoadModule proxy_express_module modules/mod_proxy_express.so
LoadModule slotmem_shm_module modules/mod_slotmem_shm.so
LoadModule ssl_module modules/mod_ssl.so
LoadModule lbmethod_byrequests_module modules/mod_lbmethod_byrequests.so
LoadModule lbmethod_bytraffic_module modules/mod_lbmethod_bytraffic.so
LoadModule lbmethod_bybusyness_module modules/mod_lbmethod_bybusyness.so
LoadModule lbmethod_heartbeat_module modules/mod_lbmethod_heartbeat.so
LoadModule mpm_event_module modules/mod_mpm_event.so
oadModule unixd_module modules/mod_unixd.so
LoadModule status_module modules/mod_status.so
LoadModule autoindex_module modules/mod_autoindex.so
LoadModule dir_module modules/mod_dir.so
LoadModule alias_module modules/mod_alias.so
LoadModule rewrite_module modules/mod_rewrite.so
LoadModule http2_module modules/mod_http2.so
<IfModule http2_module>
ProtocolsHonorOrder On
Protocols h2 http/1.1
</IfModule>
<IfModule mod_deflate.c>
SetOutputFilter DEFLATE
SetEnvIfNoCase Request_URI .(?:gif|jpe?g|png)$ no-gzip dont-vary
SetEnvIfNoCase Request_URI .(?:exe|t?gz|zip|bz2|sit|rar|apk|7z|so|iso|app|doc|ppt|xls|wps|dll)$ no-gzip dont-vary
SetEnvIfNoCase Request_URI .(?:pdf|mov|avi|mp3|mp4|rm|mpeg|asf|wmv|wma|3gp|mkv|flv|f4v|webm|mpg|acc)$ no-gzip dont-vary
AddOutputFilterByType DEFLATE text/*
AddOutputFilterByType DEFLATE application/ms* application/vnd* application/postscript application/javascript application/x-javascript
BrowserMatch ^Mozilla/4 gzip-only-text/html
BrowserMatch ^Mozilla/4.0[678] no-gzip
BrowserMatch \bMSIE !no-gzip !gzip-only-text/html
</IfModule>
<IfModule unixd_module>
User www
Group www
</IfModule>
ServerAdmin you@example.com
ServerName 0.0.0.0:80
<Directory />
AllowOverride All
Require all granted
</Directory>
<IfModule dir_module>
DirectoryIndex index.html index.htm index.php
</IfModule>
<Files ".ht*">
Require all denied
</Files>
ErrorLog "/www/wwwlogs/error_log"
LogLevel warn
<IfModule log_config_module>
LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
LogFormat "%h %l %u %t \"%r\" %>s %b" common
<IfModule logio_module>
LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\" %I %O" combinedio
</IfModule>
CustomLog "/www/wwwlogs/access_log" common
</IfModule>
<IfModule alias_module>
ScriptAlias /cgi-bin/ "/www/server/apache/cgi-bin/"
</IfModule>
<IfModule cgid_module>
</IfModule>
<Directory "/www/server/apache/cgi-bin">
AllowOverride All
Options None
Require all granted
</Directory>
<IfModule mime_module>
TypesConfig conf/mime.types
AddType application/x-compress .Z
AddType application/x-gzip .gz .tgz
AddType application/x-httpd-php .php
AddType application/x-httpd-php-source .phps
</IfModule>
Include conf/extra/httpd-mpm.conf
Include conf/extra/httpd-vhosts.conf
Include conf/extra/httpd-default.conf
<IfModule proxy_html_module>
Include conf/extra/proxy-html.conf
</IfModule>
<IfModule ssl_module>
SSLRandomSeed startup builtin
SSLRandomSeed connect builtin
</IfModule>
TraceEnable off
IncludeOptional /www/server/panel/vhost/apache/*.conf
ServerLimit 1600

注意:以上为 Apache 主配置文件参考,这里假设已安装相关的模块。日志目录为/www/wwwlogs/,Nginx 安装目录/www/server/apache/,站点信息配置文件目录为/www/server/panel/vhost/apache/。

站点配置文件

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
<VirtualHost *:80>
ServerAdmin webmaster@example.com
DocumentRoot "/www/wwwroot/7bu.top/public"
ServerName e0a2fcea.7bu.top
ServerAlias 7bu.top www.7bu.top
ErrorLog "/www/wwwlogs/7bu.top-error_log"
CustomLog "/www/wwwlogs/7bu.top-access_log" combined
<Files ~ (\.user.ini|\.htaccess|\.git|\.svn|\.project|LICENSE|README.md)$>
Order allow,deny
Deny from all
</Files>
<FilesMatch \.php$>
SetHandler "proxy:unix:/tmp/php-cgi-72.sock|fcgi://localhost"
</FilesMatch>
<Directory "/www/wwwroot/7bu.top/public">
SetOutputFilter DEFLATE
Options FollowSymLinks
AllowOverride All
Require all granted
DirectoryIndex index.php index.html index.htm default.php default.html default.htm
</Directory>
</VirtualHost>
<VirtualHost *:443>
ServerAdmin webmasterexample.com
DocumentRoot "/www/wwwroot/7bu.top/public"
ServerName SSL.7bu.top
ServerAlias www.7bu.top 7bu.top
ErrorLog "/www/wwwlogs/7bu.top-error_log"
CustomLog "/www/wwwlogs/7bu.top-access_log" combined
SSLEngine On
SSLCertificateFile /www/server/panel/vhost/cert/7bu.top/fullchain.pem
SSLCertificateKeyFile /www/server/panel/vhost/cert/7bu.top/privkey.pem
SSLCipherSuite EECDH+CHACHA20:EECDH+CHACHA20-draft:EECDH+AES128:RSA+AES128:EECDH+AES256:RSA+AES256:EECDH+3DES:RSA+3DES:!MD5
SSLProtocol All -SSLv2 -SSLv3 -TLSv1
SSLHonorCipherOrder On
<FilesMatch \.php$>
SetHandler "proxy:unix:/tmp/php-cgi-72.sock|fcgi://localhost"
</FilesMatch>
<Files ~ (\.user.ini|\.htaccess|\.git|\.svn|\.project|LICENSE|README.md)$>
Order allow,deny
Deny from all
</Files>
<Directory "/www/wwwroot/7bu.top/public">
SetOutputFilter DEFLATE
Options FollowSymLinks
AllowOverride All
Require all granted
DirectoryIndex index.php index.html index.htm default.php default.html default.htm
</Directory>
</VirtualHost>

注意:以去不图床的配置文件为例,可自定义项分别是:监听端口、站点域名、网站目录、端口转发、证书信息、强制跳转、地址重写、文件缓存、文件屏蔽等等。

Nginx 主配置、站点配置文件参考

我们在搭建网站时,为了方便管理,常常会选用 PHP+MySQL 这种架构,Web 引擎可选择 Apache 或是 Nginx。今天杜老师说一下,选择 Nginx 时,主配置文件和站点配置文件如何改写!

Nginx 主配置文件

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
user  www www;
worker_processes auto;
error_log /www/wwwlogs/nginx_error.log crit;
pid /www/server/nginx/logs/nginx.pid;
worker_rlimit_nofile 51200;
events
{
use epoll;
worker_connections 51200;
multi_accept on;
}
http
{
include mime.types;
include proxy.conf;
default_type application/octet-stream;
server_names_hash_bucket_size 512;
client_header_buffer_size 32k;
large_client_header_buffers 4 32k;
client_max_body_size 50m;
sendfile on;
tcp_nopush on;
keepalive_timeout 60;
tcp_nodelay on;
fastcgi_connect_timeout 300;
fastcgi_send_timeout 300;
fastcgi_read_timeout 300;
fastcgi_buffer_size 64k;
fastcgi_buffers 4 64k;
fastcgi_busy_buffers_size 128k;
fastcgi_temp_file_write_size 256k;
fastcgi_intercept_errors on;
gzip on;
gzip_min_length 1k;
gzip_buffers 4 16k;
gzip_http_version 1.1;
gzip_comp_level 2;
gzip_types text/plain application/javascript application/x-javascript text/javascript text/css application/xml;
gzip_vary on;
gzip_proxied expired no-cache no-store private auth;
gzip_disable "MSIE [1-6]\.";
limit_conn_zone $binary_remote_addr zone=perip:10m;
limit_conn_zone $server_name zone=perserver:10m;
server_tokens off;
access_log off;
include /www/server/panel/vhost/nginx/*.conf;
}

注意:以上为 Nginx 主配置文件参考,这里假设已安装相关的模块。日志目录为/www/wwwlogs/,Nginx 安装目录/www/server/nginx/,站点信息配置文件目录为/www/server/panel/vhost/nginx/。

站点配置文件

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
server
{
listen 80;
listen 443 ssl http2;
server_name 7bu.top www.7bu.top;
index index.php index.html index.htm default.php default.htm default.html;
root /www/wwwroot/7bu.top/public;
if ($server_port !~ 443){
rewrite ^(/.*)$ https://$host$1 permanent;
}
ssl_certificate /www/server/panel/vhost/cert/7bu.top/fullchain.pem;
ssl_certificate_key /www/server/panel/vhost/cert/7bu.top/privkey.pem;
ssl_protocols TLSv1.1 TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:HIGH:!aNULL:!MD5:!RC4:!DHE;
ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
error_page 497 https://$host$request_uri;
if ($host ~ '^www.7bu.top'){
return 301 http://7bu.top$request_uri;
}
include /www/server/panel/vhost/open_basedir/nginx/7bu.top.conf;
include enable-php-73.conf;
include /www/server/panel/vhost/rewrite/7bu.top.conf;
location ~ ^/(\.user.ini|\.htaccess|\.git|\.svn|\.project|LICENSE|README.md)
{
return 404;
}
location ~ \.well-known{
allow all;
}
location ~ .*\.(gif|jpg|jpeg|png|bmp|swf)$
{
expires 30d;
error_log off;
access_log /dev/null;
}
location ~ .*\.(js|css)?$
{
expires 12h;
error_log off;
access_log /dev/null;
}
access_log /www/wwwlogs/7bu.top.log;
error_log /www/wwwlogs/7bu.top.error.log;
}

注意:以去不图床的配置文件为例,可自定义项分别是:监听端口、站点域名、网站目录、端口转发、证书信息、强制跳转、地址重写、文件缓存、文件屏蔽等等。

网站时间的那些事

我们想访问一个网站时,每次按下回车或是点击链接,都希望网站页面能尽快的映入到我们眼帘,那您知道每次等待的时间中,都发生了什么?

域名查询时间

我们需要知道,在网络中,两个设备间的通信是需要 IP 地址才可以的,也就是说,您每次访问网站时,都是通过 IP 地址实现的,可您输入的明明是域名,并不是 IP,这又是什么情况呢?

原因就是您的电脑,会自动去询问设置在您电脑上的 DNS 服务器,然后通过 DNS 服务器返回的 IP 地址访问网站。而询问的过程,就是域名查询时间,大家可以用 Ping 命令,测试一下与 DNS 服务器的连接时间,可以大致得出域名查询时间。为什么说大致,因为 Ping 命令只可以测出连接时间,DNS 还需要处理!

网络队列时间

电脑知道要访问网站的 IP 后,就会与之通信,而在网络中与之通信的不止是您一个,那么多人同时访问,先处理谁后处理谁?这时就需要排队了!排到您了,服务器自然会处理您的请求。

当然不只是网络资源要排队,服务器的内部处理进程,也需要排队的,等待排队还有数据处理,都需要时间的!

页面生成时间

以我们的常见的博客程序 WordPress 为例,WordPress 是用 PHP 语言所写,通过 MySQL 来存储数据,Nginx 为页面解析。所以 PHP 首先去找 MySQL 索要数据,然后再通过 Nginx 服务生成页面数据。

您的每次浏览 PHP 都需要去 MySQL 中索要一次数据,然后再经过 Nginx 生成,所以您会发现,有些网站打开后再刷新,速度并没有变很快!

文件传输时间

页面数据传输到您的浏览器之后,您的浏览器就会开始加载页面数据包含的文件,例如 JavaScript 库、CSS 样式表、图片等等,这些时间就取决于您的带宽和浏览器的处理能力了。

一般的浏览器会默认缓存这些静态类文件「简单来说就是不会经常变的文件」使得再刷新时,不用重新下载,从而加快浏览速度!

DevTools failed to load SourceMap 问题的解决

有时我们会压缩 JavaScript 文件后再调用,压缩过程中可能会破坏掉 JavaScript 文件中的部分代码导致调用失败,浏览器则会通过 SourceMap 找到原来的 JavaScript 文件!当找不到 SourceMap 则弹出警告提示。

问题表现

打开浏览器检查器会看到警告的提示:

解决方法

点击检查器配置项,取消 Enable tab moves focus 项勾选即可:

如何关闭浏览器 SameSite 警告

作为强迫症的完美患者,杜老师绝对不允许浏览器的调试工具中出现任何错误的提示,今天遇到了 SameSite 警告,记录一下解决方法!

问题原因

杜老师说新添加了说说页面,为了避免垃圾内容,设置了登录后才可发表,而登录信息会以 Cookie 的形式存放在本地。

而说说模块的调用是另一个域名,也就是说 Cookie 是属于另一个域名。当网站出现这种情况时,浏览器就会发出 SameSite 警告。

解决方法

Chrome 浏览器地址栏输入 chrome://flags,搜索框输入 Cookie deprecation messages,禁用,重启浏览器就行了:

Hexo 指定不进行渲染的文件或目录

有时候需要放一些已经做好的页面到博客上去,而默认情况下,Hexo 也会将这些页面进行处理,导致这些页面渲染上了博客主题,如何不处理这些页面呢?

设置方法

1
skip_render: DIRNAME/FILENAME.html

注意:假设 source 里面有个 DIRNAME 目录,要忽略该目录下的 FILENAME.html 页面,可以通过在_config.yml 设置 skip_render 来忽略,具体如上。

设置扩展

单个文件夹下全部文件:

1
skip_render: DIRNAME/*

单个文件夹下指定类型文件:

1
skip_render: DIRNAME/*.html

单个文件夹下全部文件及子目录:

1
skip_render: DIRNAME/**

多个文件夹及各种复杂情况:

1
2
3
skip_render:
- "DIRNAME/*.html"
- "DIRNAME/**/*"

Hexo 生成页面出现问题 WARN No layout

今天杜老师在更新本站的主题时,遇到了空白页面的问题,并弹出 WARN No layout 错误提示。记录一下以本站主题为例如何解决该问题!

问题原因

Hexo 本地测试运行重启后页面空白,终端上提示 WARN No layout。使用 hexo clean 然后重新 hexo g 再次运行还是空白。

运行 git clone 指令获得主题后,在 theme 主题下保存目录的名称为 volantis-x,如果在_config.yml 里设置的是 volantis,就会出现这样的 WARN,页面显示的是空白。

解决方法

  1. 把 theme 下的文件夹名称改为 volantis;

  2. 将_config.yml 里设置改为 volantis-x。

为 Nextcloud 添加 Markdown 编辑器

杜老师平时写博客都是用 Markdown,为了方便随时编写,特地将 md 文件存放在 NAS,而作为 NAS 程序的 Nextcloud,如果有 Markdown 编辑功能,岂不美哉?

添加功能

点击右上角的头像图标,选择应用,在 Office&text 一项中找到 Markdown Editor,点击下载并启用就行了:

注意问题

安装完 Markdown 编辑器后发现,打开 md 后缀的文件,用的依然是 Nextcloud 自带的编辑器,后来在官网中找到解决办法。

点击右上角的头像图标,选择应用,在您的应用一项中找到 Text 点禁用,则关闭 extcloud 自带的编辑器。如果不想影响 txt 后缀文件的编辑,还可以在 Office&text 一项中找到 Plain text editor,点击下载并启用就行了。

解决 Nextcloud 出现 trusted_domains 问题

最近买了个树莓派,在家里搭建 NAS,因为移动办公需求,做了一个内网穿透,为 NAS 绑定域名,而通过域名访问时,出现了 trusted_domains 问题,说下是如何解决的!

问题截图

当 Nextcloud 出现 trusted_domains 问题时,页面会显示如下的内容:

解决方法

1
2
3
4
5
6
7
'trusted_domains' =>
array (
0 => 'localhost',
1 => 'server1.example.com',
2 => '192.168.1.50',
3 => '[fe80::1:50]',
),

编辑 Nextcloud 目录下的 config.php 文件,找到 trusted_domains 项,安装上面格式添加域名即可!

IP/PV/UV 是什么

做服务器运维,亦或者网站运营时,经常会听到 IP/PV/UV,这些东东到底是什么呢?它们又有什么作用,今天杜老师为大家简单讲解一下!

IP 是什么

关于 IP 有很多解释,它是网络地址,通过它可以定位服务器;也是流量的代名词,我们常常听到某某明显自带 IP 的说法,说明 TA 代言或参演的作品会有很多人支持。

今天我们要说的 IP 是偏前者,指的是一个真实的地址。我们都知道在上网前需到服务商办理业务,就是租用宽带。上网时服务商会提供一个临时 IP,我们就是通过这个 IP 获得一个可通过互联网获取数据的身份。这里需要知道的是,即便家里的网络设备比较多,在使用时对外都是一样的 IP。

PV 是什么

PV 全称 Page View,中文译为页面浏览,指代网站中的一个页面被浏览的次数。为了让大家更容易理解,我们举个简单例子。

杜老师说中的两篇文章,当有访客去分别访问时,就会产生 2 个 PV 了。而且其中一个页面被访客刷新页面后,也会额外产生 1 个 PV 的。

UV 是什么

UV 全称 User View,中文译为用户浏览,指代有几个用户访问了你的网站。这个统计与 IP/PV 不同,为了让大家更好的理解,我们对比说明一下。

PV 的数值一般最大,因为不论浏览还是刷新,都会增加 PV 值;IP 的数值一般最小,因为同一网络内的访问,只算作 1 个 IP。比如同一网吧所有人都登录一个网站,对于该网站来说只进量了 1 个 IP。UV 在它们之间,一般会通过浏览器缓存信息判断是否是同一个用户。比如我用一个浏览器打开杜老师说的多个页面,也算作 1 个 UV。

有何用途

对于运维人员来说,IP 可以判断访客的地域,到底是什么地区的人喜欢访问我们的网站,这样可以针对该地区做优化,比如多加节点等提升访客的访问体验;PV 可以判断哪些页面更加受欢迎,可针对页面做优化,比如增加缓存等等;UV 可以判断用户量,用于调整服务器并发等性能。

对于站长来说,IP 同样用来判断访客的地域,对于主要来源地域,我们可以针对性的推荐服务。比如一个做菜教程网站,访客大部门来自于东北地区,就可以多发布一些东北菜系教程;PV 得出的数据让我们知道了哪些页面更受欢迎,这样可以发布更多相关内容页面。UV 可以判断出访客数量,如果以后要做广告挂载,这是一个重要的参考值,因为广告商需知道有多少人访问网站。

Firefox 火狐浏览器关闭缓存

为了给访客带来更好的体验,杜老师说经常需要升级网站,对页面的细节进行调整。而修改页面代码后,往往需要清空浏览器的缓存,才能看到更新后的内容,有什么办法能让火狐浏览器关闭缓存,今天杜老师就来说一下!

问题表现

最近做项目的时候,在 Firefox 火狐浏览器发现缓存难清理,用CTRL+F5或者CTRL+R等在谷歌和 IE 浏览器的快捷键没用,搜了一下,发现火狐清理缓存比较麻烦,默认快捷键CTRL+SHIFT+DEL

而且是弹窗选择性清理,还要点击按钮选择,在 Web 开发调试中非常的不方便不科学,然后问度娘发现火狐是要进入它的参数设置里设置本地不缓存的。

解决方案

Firefox 火狐浏览器地址栏输入 about:config

找到 browser.cache.check_doc_frequency 选项双击将 3 改成 1

找到 browser.cache.disk.enable 选项把 true 改为 false

找到 browser.cache.memory.enable 选项把 true 改为 false

常用页面加载速度优化方法

我们在打开网站时,会发现有些网站打开特别慢,有些网站瞬间打开,今天杜老师与大家聊聊常用页面加载速度优化方法!

加载速度

一个网站加载速度受很多因素的影响,在客户端方面,主要受网速和电脑性能影响。当然,浏览器也影响加载速度!

当然服务端的优化更为重要,受服务器性能、网速等综合因素的影响,我们下面说说优化细节。

合并文件

将 JavaScript 代码和 CSS 样式分别合并到一个共享的文件。这样不仅简化代码,而且执行 JavaScript 文件的时候,如果 JavaScript 文件比较多,就需要进行多次 GET 请求,延长加载速度,将 JavaScript 文件合并在一起后,自然就减少 GET 请求次数,提高加载速度。

图片技术

sprinting 是一种网页图片应用处理方式。它是将一个页面涉及到所有零星图片都包含到一张大图中去,然后用 CSS 技术展现出来。

这样一来,当访问页面时,载入的图片就不会像以前那样一幅一幅地慢慢显示出来,可以减少整个网页图片大小,并利用 sprinting 能很好地减少网页的 HTTP 请求,从而大大地提高页面的性能。

压缩文件

压缩技术如 gzip 可有效减少页面加载的时间。包括 HTML/XML/JSON/JavaScript 和 CSS 等,压缩率都可以在大小 70% 左右。

文本压缩用得较多,一般直接在空间开启就可以,而图片的压缩就比较随意了,很多都是直接上传,其实还有很大压缩空间。

一个小博客的成长

有学生找到我,说想做一个和我这个一样的博客,但不知道如何操作。今天杜老师与大家聊下,如何搭建一个博客,以及一个小博客的成长!

博客初建

首先你在博客的运营商,例如网易、新浪 and so on 上注册,他们提供免费域名,免费空间,甚至免费程序模板,我们所要做的,就是安心写写文章。

过段时间之后,你会发现,小博客无法满足你的要求了,例如代码高亮,自定义导航栏。这时我们就可以申请个空间,去搭建真正属于自己的博客。

前期的博客只是写着玩,无非花费太多,在目前的互联网上,你可以找到免费的空间,免费域名,甚至免费程序。不过一段时间之后,你会发现免费的才是最贵的,动不动就出现一些问题,让你没法安心的写博客。

既然如此,我们转战收费市场,在知名度较高的服务商,买个空间以及域名,将之前的博客转移过去。在你感叹终于可以安心写博客时,你的访问量也逐渐升高。服务商不断打电话催你:你的网站访问太大,小小的空间无法让你再施展,建议你升级下空间。

然而,空间的升级是无止境的,所以你干脆狠下心,买一台服务器。但服务器价格太高,买一个 VPS 也还不错。自己定义环境,想要啥就有啥。在你幻想再也不用听客服哔哔时,突然发现网站宕了。

原来,VPS 也无法满足你了,看来,网站的访问量已经特别高了,如果你想,相信访问量带来的广告费已经可以支付购买服务器的差价了。

最终,你还是将博客,运行在服务器上面。你想升级之路到此为止?非也,后面的路还长着呢!

博客做的越来越大,以致于一台服务器也承受不了时,我们就需要扩展架构了。

博客升级

要做的就是 Web 和数据库分离,使 Web 可以存放更多文件,数据库的存取效率更高。请求先发送到 Web 端,Web 端判断请求信息为静态还是动态的,静态本地处理直接返回,动态的就连接到数据库调用数据。

增加一台 Web 服务器,专门用于存放静态文件,在此上做 Nginx 基于文件类型的分发,静态的自己去处理,动态交给另一台服务器处理。这样就把大量请求分流,减少动态服务器的压力。

再增加一台 Web,同样进行动态文件处理,更大程度减少动态服务器的压力。

增加一台数据库服务器,将两台服务器读写分工,一台只负责读,另一台只负责写入。

在 Web 和数据库之间加入 Memcached 缓存服务器,加速数据处理过程。

大量购买节点,搭建 CDN 服务器,在最外层分担压力。

如何建好家装论坛

有个同学,父亲开了一家装修公司,想在网上搭建一个平台,做宣传的同时,也可以和同行相互交流。最后他来问我,选什么平台比较好,如何搭建这种平台,那杜老师就来说下如何建好家装论坛!

何为论坛

网络论坛是一个和网络技术有关的网上交流的场所。一般就是大家口中常提的 BBS。BBS 的英文全称是 Bulletin Board System,翻译为中文就是电子公告板。

BBS 最早是用来公布股市价格等类信息,当时 BBS 连文件传输的功能都没有,且只能在苹果计算机上运行。因为现在网络知识流行太快,每个行业都会有一个自己在网络中进行交流的一块区域,论坛是最好的地方。

搭建步骤

首先需要选择一个域名,最好配合地区以及行业。

其次选择一个网站空间,就是存放网站文件用的。如果是做论坛,建议选择国内空间,因为做起来后,对带宽的要求很大。虽然国外空间可以满足带宽要求,不过因为传输距离等等原因,速度不能达到理想标准。

然后选择程序,如果是做论坛,建议选择国内的 Discuz 或 PHPwind。虽然都是论坛,不过国外程序不太符合国人使用习惯。而且 Discuz 和 PHPwind 也有些不同,要先选个自己较熟悉的,往往后期再去熟悉可能会影响网站的访问。如果没有头绪,建议选 Discuz,它的模板插件都很丰富,而且使用率很高的,出现问题也很容易处理。

接下来就是模板了。一定要选个符合论坛主题的模板,当然前期可以使用默认,然后要合作者或是论坛会员投票选取,不要经常换取模板,因为模板的套接字不同,每换一次模板,百度都要重新收录一次,要知道人家可没有心情经常更新。

插件不是越多越好,先要讲究实用,因为过多插件也会拖慢论坛访问速度。建议多选择互动性插件,例如论坛任务插件等等。

上面提到了合作者。很多人可能优先想到了美工、运维技术人员,其实这些都不重要,模板可以解决美工问题。如果空间是主机商购买来的,那恭喜你,技术问题你也不用担心,他们都会帮你处理。最好的合作者是业内的同行,他们的专业性文章以及想法,都会提升论坛价值。

最后说下论坛内容。前期版块不需要弄太多,我见过一个新论坛,刚建不久各种版块。先不说专业不专业,一堆版块就会给人感觉太空,感觉这个论坛并不太受欢迎。毕竟论坛是建立在互动基础上的,人气是论坛价值的体现。

建议按照个人擅长,建立对应领域版块,等人气上来了,再扩充子版块,或是根据论坛会员以及论坛发展需求建立对应版块。

让 Hexo 支持在线编辑

每次发布博文都要登录到服务器太过麻烦,有没有什么方法可以让 Hexo 支持在线编辑呢?今天杜老师教大家通过第三方插件实现在线编辑 Hexo 博文!

插件安装

1
npm install --save hexo-admin

注意:上面的命令需要在 Hexo 根目录执行,过程中可能会报错,是因为版本兼容性关系,无需理会!

插件使用

1
hexo s

注意:每次在使用插件时,都需要使用 Hexo 集成的 server 引擎,运行上面的命令后,可通过浏览器打开 http://DOMAIN:4000/admin 访问编辑器。

登录验证

该插件不需要身份验证即可访问,所以为了安全,最好添加身份验证。访问插件页面,点击导航栏中的 Settings,点击页面的 Setup authentification here,根据提示依次输入用户名和密码,最后验证无需理会。输入后会在页面下生成代码,将其复制到 Hexo 博客根目录下的_config.yml 即可。

下次再登录时,需要输入用户名和密码!

在线部署

每次编辑好文章后,需登录到服务器的 Hexo 根目录中执行部署命令才可以,这样非常麻烦。插件集成自动部署功能,不过需要进行一些简单配置,将下面的代码复制到 Hexo 博客根目录下的_config.yml:

1
deployCommand: './g.sh'

然后依次执行以下命令。执行后即可通过导航栏中 Deploy,然后在页面输入框输入任意字符后点击 Deploy 即可:

1
2
echo 'hexo g' > g.sh
chmod +x g.sh

将 Hexo 部署到 CODING

GitHub 虽然免费和稳定,但因为其服务器在国外,故访问时会因为线路等原因发生访问缓慢,甚至超时等等问题。国内的 CODING 同样提供免费的代码托管和页面展示服务,我们可以将代码上传到 CODING 上展示!

准备工作

如果没有账号,请前往 CODING 注册一个账号。然后新建一个公开仓库,仓库名称格式为 USERNAME.coding.me

创建完成后记下该仓库的 HTTPS/SSH 地址,一般格式为 https://coding.net/USERNAME/USERNAME.coding.me.git,下一步会用到。

配置环境

1
2
git config --global user.email "EMAILADDRESS"
git config --global user.name "USERNAME"

注意:如果你只是安装好了 Git 但没有配置过,那么现在需要做的第一件事情就是设置你的 Git 用户名和邮箱。在 Git Bash 执行以上两条命令配置你的用户名和邮箱,这里需要用户名和邮箱与你的 CODING 用户名和邮箱保持一致。

配置文件

1
2
3
deploy:
type: git
repo: https://coding.net/USERNAME/USERNAME.coding.me.git

注意:进入到 Hexo 博客的根目录,编辑站点的配置文件_config.yml,将上面的代码填入文件末尾。

博客发布

1
hexo d

注意:输入这个命令即可将本地的博客文件,上传到 CODING,不过每次需要输入用户名和密码!

将 Hexo 部署到 GitHub

GitHub 可为用户免费提供静态页面的展示空间,我们可以将生成好的博客文件部署到 GitHub 上展示,就可以节省一部分空间及域名的费用!

准备工作

如果没有账号,请前往 GitHub 注册一个账号。然后新建一个公开仓库,仓库名称格式为 USERNAME.github.io

创建完成后记下该仓库的 HTTPS/SSH 地址,一般格式为 https://github.com/USERNAME/USERNAME.github.io.git,下一步会用到。

配置环境

1
2
git config --global user.email "EMAILADDRESS"
git config --global user.name "USERNAME"

注意:如果你只是安装好了 Git 但没有配置过,那么现在需要做的第一件事情就是设置你的 Git 用户名和邮箱。在 Git Bash 执行以上两条命令配置你的用户名和邮箱,这里需要用户名和邮箱与你的 GitHub 用户名和邮箱保持一致。

配置文件

1
2
3
deploy:
type: git
repo: https://github.com/USERNAME/USERNAME.github.io.git

注意:进入到 Hexo 博客的根目录,编辑站点的配置文件_config.yml,将上面的代码填入文件末尾。

博客发布

1
hexo d

注意:输入这个命令即可将本地的博客文件,上传到 GitHub,不过每次需要输入用户名和密码!

如何上线一个博客「下篇」

经过十多天的折腾,杜老师的私人技术博客终于和大家见面了。上线一个博客真的很困难吗?今天我们来聊聊吧!

服务系统选择

杜老师的学生大部分用的都是 CentOS 系统,这是一款重量级 Linux 操作系统,用作静态博客网站太过大材小用,所以杜老师选择了较为轻量的 Ubuntu 系统,这款麻雀虽小五脏俱全的系统深受杜老师喜爱。

版本没有严格要求,杜老师选择了 18.04TLS 这一版,TLS 是技术长期支持,表示官方会在很长一段时间内维护系统的更新升级。

运行环境搭建

我们需要使用 npm 软件管理器安装 Hexo 命令行,所以需要先安装 npm:

1
apt -y install npm

然后通过 npm 软件管理器安装 Hexo 命令行:

1
npm install hexo-cli -g

接下来就可以使用 Hexo 来配置博客网站,不过 Hexo 程序源码位于 GitHub,部署之前需要先安装 Git 工具:

1
apt -y install git

之后就可以使用 Hexo 命令来生成博客网站文件,命令执行后会自动创建一个目录为 blog,里面就是博客网站文件,你也可以将 blog 改成其它名称,不过不可以使用中文哦:

1
hexo init blog

生成博客网页

上面的命令是生成博客程序文件,我们还需运行下面的命令生成可以访问的网页文件。首先生成网页文件:

1
2
cd blog/
hexo g

有个网页文件之后,我们还需要可以访问该网页,我们通过 Nginx 来实现,安装的命令是:

1
apt -y install nginx

使用 hexo 的网页文件目录替换掉 Nginx 的默认网站根目录,并建立持续集成的关系:

1
2
3
4
cd /var/www/
mv html/ html.bak
mv ~/blog/public/ html
ln -s /var/www/html /root/blog/public

最后启动 Nginx 并设置开机启动即可:

1
2
systemctl start nginx
systemctl enable nginx

如何更新博客

经过上面的步骤后,就可以通过域名访问到刚创建好的博客了。如何更新博客的内容呢?通过 Hexo 自带的命令,就可以实现更新配置等操作,不过记得要在 blog 目录才可以:

1
2
cd blog/
hexo new TITLE

TITLE 为文章标题,你可以自定义,执行完上面的命令后系统会生成一个文件,并以红色字体提示,使用编辑器修改该文件内容即可,最后使用 Hexo 命令生成并更新网页文件即可:

1
hexo g

如何上线一个博客「中篇」

经过十多天的折腾,杜老师的私人技术博客终于和大家见面了。上线一个博客真的很困难吗?今天我们来聊聊吧!

为什么选择 Hexo

在上一篇博文中杜老师曾说过这款博客程序的名字是 Hexo,那么为什么会选择这款博客程序呢?它又有什么优点呢?

Hexo 是一个快速、简洁且高效的博客框架。Hexo 使用 Markdown 解析文章,在几秒内,即可利用靓丽的主题生成静态的网站。它在国外很受开发者的欢迎,因为开发者们可以使用这款程序,在 GitHub 上快速免费的搭建个人博客网站。

任性的杜老师

我考虑的当然不是免费搭建个人博客网站,而是这款博客程序的框架和设计理念,它可以快速生成静态的页面,不仅可以减少服务器的压力,而且可以更快相应请求,使访客获得更好的浏览体验。好比一家饭店事先准备好顾客所需的美食,当走到座位时佳肴已然端了过来,顾客少了等待,厨师少了繁忙。

GitHub 是开发者的天堂,里面有非常多的技术大牛分享的源码程序,但它对国内网络的支持不是很好,访问慢都是小事情,偶尔还会出现超时等无法访问的问题,这对于一个网站来说可是致命伤。毕竟大家不会选择一家动不动就关门谢客的小餐馆。

杜老师的选择

程序固然重要,但运行程序的环境更加重要。英雄联盟这款游戏很多人都喜欢,但如果要在运行于服务器的 Linux 系统上面玩,保证你会分分钟哭出来。

所以杜老师选择了阿里云服务器,虽然价格贵了一些,但为了网站的稳定、速度,还是很值得的。

都用哪些服务

除了 Hexo 博客程序和阿里云的服务器外,杜老师还注册了独立域名 dusays.com,开通了阿里云的 OSS 存储服务,及 CDN 网站加速服务。

最后我要说下,并不是每个人都需要花钱开通这些服务的,通过免费的 GitHub 也能搭建博客网站,杜老师只是想提供更好浏览体验。

如何上线一个博客「上篇」

经过十多天的折腾,杜老师的私人技术博客终于和大家见面了。上线一个博客真的很困难吗?今天我们来聊聊吧!

上线是何意思

在技术界,总有一个我们平时没听过的专业术语,上线就是其中一个。

所谓上线,简单理解就是将存于本地的已经设计好的作品放到互联网上,供他人访问和体验。

上线准备工作

上线之前,我们首先需要准备好相关的作品。比如我想上线一个博客,就需要预先设计好博客程序、模板等等。

虽然杜老师可以自行开发博客类程序,但同时很认同一个观点:不要重复的造轮子!既然网络上已经有非常多的博客程序,就不用再多一个了,拿来主义这时是不被谴责的。

手伸向了何方

我之前的网站程序是 WordPress,它是一款强大的博客类程序。但我这次并不想继续使用它,人生贵在尝试。

我选择了一款之前只是听说,但从未尝试过的博客程序 Hexo。这是一款基于 Node.js 语言开发的网站程序,说实话对这门语言我是一窍不通,但仍然无法阻止我想尝试的热情。

最后一些叮嘱

我会在接下来的文章中,发布我上线博客的教程,希望阅读过文章的朋友都可以拥有属于自己的博客。在这里我有句话想说:对于博客来说,我们享受的并不是搭建过程,而是随着内容更新,上面堆满了知识和经验。

这款 Hexo 博客在搭建过程并不轻松,杜老师在尝试的过程中备受折磨,好在本人越挫越勇的性格使得该博客能够成功上线。技术这种东西,一是靠练,二是靠试,三是坚持,希望大家都能成功!

新版本 Memos 说说页面部署代码分享

在柚子兄的帮助下,杜老师终于完成了 Memos 的版本升级。Memos 是真的糟糕,动不动 BREAKING CHANGE,前后对 API/S3 做了大量改动,严重影响了日常的使用,强烈建议在不影响使用的情况下升级版本。

特性

  1. 显示用户头像;

  2. 显示用户昵称与平台用户名;

  3. 支持大图显示;

  4. 可一键至说说广场进行评论。

效果

正常的浏览效果如下图:

夜间模式的浏览效果如下图:

代码

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
<link href="https://npm.onmicrosoft.cn/penndu@13.0.0/memos/css/style.css" rel="stylesheet" type="text/css">
<link href="https://npm.onmicrosoft.cn/penndu@13.0.0/memos/css/highlight.github.min.css" rel="stylesheet" type="text/css">
{% p center logo large, 点图片可放大! %}
<section id="main" class="container">
<div id="memos" class="memos">
</div>
</section>
<script type="text/javascript">
var memos = {
host: 'https://s.dusays.com/',
limit: '10',
creatorId: '1',
domId: '#memos',
username: 'penn',
name: 'Teacher Du',
}
</script>
<script type="text/javascript" src="https://npm.onmicrosoft.cn/penndu@13.0.0/memos/js/lazyload.min.js?v=17.8.3"></script>
<script type="text/javascript" src="https://npm.onmicrosoft.cn/penndu@13.0.0/memos/js/marked.min.js?v=11.1.1"></script>
<script type="text/javascript" src="https://npm.onmicrosoft.cn/penndu@13.0.0/memos/js/view-image.min.js?v=2.0.2"></script>
<script type="text/javascript" src="https://npm.onmicrosoft.cn/penndu@13.0.0/memos/js/moment.min.js?v=2.30.1"></script>
<script type="text/javascript" src="https://npm.onmicrosoft.cn/penndu@13.0.0/memos/js/moment.twitter.js"></script>
<script type="text/javascript" src="https://npm.onmicrosoft.cn/penndu@13.0.0/memos/js/highlight.min.js?v=11.9.0"></script>
<script type="text/javascript" src="https://npm.onmicrosoft.cn/penndu@13.2.0/memos/js/memo.js"></script>
<script>hljs.highlightAll();</script>

注意:如果不是 Volantis 主题需删除{% p center logo large, 点图片可放大! %}所在行。

使用

请根据需求修改对应的内容:

参数说明
host域名
limit每页显示条数
creatorId用户的 ID
domId显示位置
username广场的用户名
name昵称

通过 Gitea 部署 Hexo 教程

应 Zero 童靴需求,杜老师更新一篇通过 Gitea 部署 Hexo 的教程,可以实现通过 git 命令自动部署 Hexo 博客,并支持 VS Code 或者网页编辑器等形式更新站点内容。其部署思路同样适用于 Hugo 等静态博客框架。

写在前面

近年来静态博客框架占比越来越高了,其一大特性是可以托管到 Vercel 这类的免费平台上,进一步减少了博主运营成本。

但随着免费的资源越发紧俏,加上越来越严峻的网络限制,很多小伙伴开始将站点,迁移至境内平台上。

奈何境内的免费资源非常少,很多功能需要自行购买主机搭建,无疑增加了我们的使用成本以及学习成本。

本篇教程主要说明如何通过 Gitea 实现类似 GitHub Actions 那种自动部署功能,实现在主机上博客的更新和部署。

准备工作

  1. 需要在服务器上安装 Gitea,可以参考《使用 Docker 部署 Gitea 新一代的代码托管平台》一文部署;

  2. 需要在服务器上安装 Act Runner,可以参考《使用 Docker 部署 Gitea Actions 的 Runner》一文部署;

  3. 需要在服务器上安装 Hexo,可以参考《运行在云主机的 Hexo》一文部署;

  4. 需要在服务器上安装 Web 引擎,可选项非常多,杜老师使用 OpenResty,这里不多说部署方式了。

部署过程

  1. 新建站点目录。这里以 1Panel 面板为例,添加一个域名为 dusays.com 站点:
  1. 使用终端程序登录该服务器,并切换到站点目录,以刚刚的域名为例,命令如下:
1
cd /opt/1panel/apps/openresty/openresty/www/sites/dusays.com/index/
  1. 删除站点目录下的所有文件,并通过 Hexo 创建站点数据,命令如下:
1
2
rm -rf *
hexo init
  1. 创建 Act Runner 部署文件.gitea/workflows/deploy.yml,添加以下内容:
1
2
3
4
5
6
7
8
9
10
name: Gitea Actions Demo
run-name: ${{ gitea.actor }} is testing out Gitea Actions 🚀
on: [push]

jobs:
Explore-Gitea-Actions:
runs-on: self-hosted
steps:
- run: cd /opt/1panel/apps/openresty/openresty/www/sites/dusays.com/index/ && git pull origin main
- run: cd /opt/1panel/apps/openresty/openresty/www/sites/dusays.com/index/ && hexo generate
  1. 配置 git 上传的用户名和邮箱:
1
2
git config --global user.name "TeacherDu"
git config --global user.email "teacherdu@dusays.com"
  1. 生成 SSH 密钥并添加公钥到 Gitea,执行下面命令,然后一直回车,会生成 id_rsaid_rsa.pub。复制 id_rsa.pub 文件的内容并登录 Gitea,进入个人设置,添加到 SSH 公钥:
1
2
ssh-keygen -t rsa
cat ~/.ssh/id_rsa.pub
  1. 在 Gitea 上创建一个新仓库:
  1. 新建.gitignore 文件避免同步易变动文件,添加以下内容:
1
2
3
4
5
6
7
8
.DS_Store
Thumbs.db
db.json
*.log
node_modules/
public/
.deploy*/
_multiconfig.yml
  1. 提交并推送到远程仓库:
1
2
3
4
5
6
git init
git checkout -b main
git add .
git commit -m "first commit"
git remote add origin https://gitea.dusays.com/penn/hexo.git
git push -u origin main
  1. 将站点的运行目录设置为 public

注意事项

可以直接在 Gitea 修改站点内容,或者通过 VS Code 等工具接入进行编辑。

不要直接修改服务器中站点文件,如果出现内容冲突导致无法自动部署,可以从 Gitea 中重新拉取数据解决该问题。

❌