本文档记录了基于 Halo 2.24 版本的系统重构过程,主要涉及后端服务部署、静态资源分离、访问统计私有化以及前端组件的适配与调优。
一、 后端服务部署 (Halo 2.24)
1. 部署思路与注意事项
最初依赖面板工具的图形化界面部署 Docker 时,存在数据挂载路径不可控的隐患。为了确保数据的绝对安全和跨版本更新的稳定性,改为在终端通过原生 docker-compose 结合绝对路径进行部署。
在网络配置上,放弃了常规的端口映射(如 -p 8090:8090),改用 network_mode: "host"。
原因: 主机模式可以跳过 Docker 内部网桥的转发损耗。Halo 容器启动后直接占用宿主机的 8090 端口,这与服务器现有的 Nginx 反向代理规则(代理至
127.0.0.1:8090)完全契合,降低了网络层面的排错成本。
2. 操作步骤
在服务器创建主目录:
/www/wwwroot/halo在该目录下新建
docker-compose.yml:
version: "3"
services:
halo:
image: halohub/halo:2.24
container_name: halo
restart: always
network_mode: "host"
volumes:
- ./:/root/.halo2在终端执行
cd /www/wwwroot/halo并运行docker compose up -d启动服务。
二、 静态资产分离 (Cloudflare R2)
1. 部署思路与注意事项
为了降低服务器带宽压力并提高图片加载速度,将附件与图片存储剥离到 Cloudflare R2 对象存储中。
注意事项: 在 R2 中生成 API Token 时,权限必须选择 Object Read & Write(对象读写),否则 Halo 后台无法上传图片。绑定的域名(如
cdn.yourdomain.com)需开启 Cloudflare 的 DNS 代理以利用其 CDN 节点。
2. 操作步骤
在 Cloudflare R2 创建存储桶,并绑定自定义域名。
在 Halo 后台安装「S3 对象存储」插件。
填入 R2 提供的 Endpoint、Access Key、Secret Key,并在绑定域名处填入
cdn.yourdomain.com(无需携带 http/https 前缀)。
三、 数据统计部署 (Umami 3.1.0)
1. 部署思路与注意事项
Umami 提供了轻量级的网站访问统计功能,且数据保留在本地服务器。
注意前端代码变化: Umami V3 版本将前端探针的加载方式为
defer。defer可以保证脚本在后台下载,并在 HTML 文档完全解析完毕后再执行,从而不阻塞页面渲染。
2. 操作步骤
创建目录
/www/wwwroot/umami。新建
docker-compose.yml,配置 Umami 与 PostgreSQL 数据库:
version: '3'
services:
umami:
image: ghcr.io/umami-software/umami:3.1.0
ports:
- "127.0.0.1:3001:3000"
environment:
DATABASE_URL: postgresql://umami:umami_password@db:5432/umami
DATABASE_TYPE: postgresql
APP_SECRET: <随机生成一段复杂的密钥>
depends_on:
- db
restart: always
db:
image: postgres:15-alpine
environment:
POSTGRES_DB: umami
POSTGRES_USER: umami
POSTGRES_PASSWORD: <你的数据库密码>
volumes:
- umami-db-data:/var/lib/postgresql/data
restart: always
volumes:
umami-db-data:终端执行启动,并在宝塔中设置反向代理,登录后台获取
data-website-id。
四、 前端组件调优:全局悬浮音乐播放器
这是本次重构中调整步骤最多的环节。以下是问题排查与迭代的完整路径:
1. 方案迭代过程
阶段一:官方 iframe 外链。 最初使用网易云官方的 iframe 代码,但遇到了浏览器的“混合内容拦截”(HTTPS 网站禁止加载 HTTP 脚本)以及版权歌单直接禁播的问题。此外,为了让播放器只在首页显示,加入了基于路由的 JS 拦截代码,但维护成本较高。
阶段二:引入开源方案。 决定改为全站全局播放(切换文章时音乐不断),改用 APlayer + MetingJS 开源方案。初期遇到了组件无法显示的现象,经排查,是因为为其添加了
display: none导致 APlayer 初始化时无法读取容器宽高而渲染失败。阶段三:环境适配与修复。 播放器依然无法加载,通过浏览器
F12控制台查看日志,确认了两个网络环境问题:Jsdelivr CDN 在国内网络环境下存在加载超时。
MetingJS 的官方解析 API 域名(
api.i-meto.com)在国内存在 DNS 解析故障。
2. 最终解决方案与原理
基于上述排查结果,对前端代码进行了以下三项关键处理:
替换静态资源节点: 将 APlayer 库的加载源替换为国内的
staticfile.net。API 劫持替换: 在引入 MetingJS 脚本之前,声明
meting_api变量,将音频解析请求强制重定向至国内稳定可用的第三方镜像源(api.injahow.cn)。CSS 样式隔离: Halo 主题自带的
text-align: center会导致播放器内部的歌曲列表排版错乱。通过注入优先级(!important)更高的局部 CSS 代码,强制列表内容左对齐。参数声明逻辑: 诸如
order="random"(随机播放)等控制命令,直接作为属性写在<meting-js>标签内部,以符合声明式语法,避免异步执行带来的参数丢失。
3. 最终代码配置
路径:Halo 后台 -> 设置 -> 代码注入 -> 页脚(Footer)
<script defer src="https://tongji.yourdomain.com/script.js" data-website-id="你的专属UUID请在后台获取"></script>
<link rel="stylesheet" href="https://cdn.staticfile.net/aplayer/1.10.1/APlayer.min.css">
<script src="https://cdn.staticfile.net/aplayer/1.10.1/APlayer.min.js"></script>
<script>
var meting_api = 'https://api.injahow.cn/meting/?server=:server&type=:type&id=:id&pages=:page&r=:r';
</script>
<script src="https://fastly.jsdelivr.net/npm/[email protected]/dist/Meting.min.js"></script>
<style>
.aplayer .aplayer-list ol li { text-align: left !important; }
.aplayer .aplayer-list ol li .aplayer-list-author { float: right !important; }
</style>
<meting-js
server="netease"
type="playlist"
id="替换为你自己的网易云歌单ID"
fixed="true"
autoplay="false"
theme="#2980b9"
loop="all"
order="random"
preload="auto"
list-folded="true">
</meting-js>五、 后续修改注意事项
如果后期需要更改音乐设置,请直接修改上述代码第 5 模块中的对应属性:
更换歌单: 修改
id="替换为你自己的网易云歌单ID"为新歌单编号。请注意,第三方 API 无法解析网易云系统自带的“我喜欢的音乐”歌单。且歌单中若包含 VIP 或版权受限歌曲,API 将只能抓取到 30 秒的试听版本。建议新建一个仅包含免费歌曲的公开歌单。自动播放: 修改
autoplay="true"即可开启。但需受限于现代浏览器的防打扰策略,访客在首次打开页面时,可能仍需在页面空白处点击一次鼠标,音频才会正常输出。