本地部署
云服务器到期了只保留一个域名,正巧买了一个开发板安装了wifi刚好可以用来当服务器。这次使用了halo建站,主要是轻量再加上想试试新的平台。在服务器上的管理面板是1panel,但1panel应用市场里的halo是pro版的,所以自己在docker部署了社区版:
version: "3"
services:
halo:
image: halohub/halo:2.25.1
container_name: halo
restart: always
ports:
- "8090:8090" # 自行修改未占用端口
volumes:
- ./halo-data:/root/.halo
environment:
- JVM_OPTS=-Xmx256m
默认使用H2存储,改成MYSQL,环境变量:
PATH=/opt/java/openjdk/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
JAVA_HOME=/opt/java/openjdk
LANG=en_US.UTF-8
LANGUAGE=en_US:en
LC_ALL=en_US.UTF-8
JAVA_VERSION=jdk-21.0.11+10
JVM_OPTS=
HALO_WORK_DIR=/root/.halo2
SPRING_CONFIG_LOCATION=optional:classpath:/;optional:file:/root/.halo2/
TZ=Asia/Shanghai
SPRING_R2DBC_URL=r2dbc:pool:mysql://192.168.1.6:3306/halo
SPRING_R2DBC_USERNAME=root
SPRING_R2DBC_PASSWORD=
SPRING_SQL_INIT_PLATFORM=mysql
启动:
docker run -d \
--name halo \
--restart always \
-p 8090:8090 \
-v ~/halo-data:/root/.halo \
halohub/halo:2.25.1
上线
由于没云服务器了且每次便宜服务器只能买一年一直换太麻烦了所以用Cloudflare Tunnel内网穿透,且自带https安全认证方便省事。
1.创建隧道
进入 Zero Trust 面板Networks -> Tunnels点击 Create a Tunnel,选择默认的 Cloudflare (Recommended) 模式。cloudflare会给出一键安装命令,我选择docker,直接粘贴进命令行。我的域名是.cn所以无法转移到cloudflare,所以把DNS解析地址改成cloudflare给的,会有弹窗教程。到 Cloudflare Zero Trust 后台,点击左侧的 Networks -> Tunnels。切换到 Public Hostname(公共主机名) 标签页。点击 Add a public hostname(添加公共主机名) 按钮。
填入以下信息:
Domain:点击下拉菜单,选择你从阿里云刚绑定过来的那个域名。
Path:留空不填。
Type:选择 HTTP(虽然外网访问是 HTTPS,但由于是内网穿透,这里选 HTTP ,Cloudflare 会在边缘节点自动帮你加密)。
URL:填写:127.0.0.1:8090。
2.发布
与上一步一样。由于我的域名绑定到之前的云服务器公网ip所以要先删除,在DNS->记录,直接删除即可。
网站布置
1.外观
首先选一个好看的主题,这个看自己的审美。我选择了氢·简,因为我第一次进入halo的主题商店就看到这个刚发布的,还挺有缘而且挺简洁的所以就用了,但是实际发现并不简洁,后面会自己改一下或者换主题吧。
这个主题下面有一个不能隐藏的版权链接,直接在设置里->主题->高级设置->自定义 CSS
/* 精准隐藏页脚的 Built with 容器以及 Theme / CMS 标签 */
.hydro-footer__credits,
.hydro-footer__credit {
display: none !important;
}第一次修改
2026年6月15日改动
将主题修改为
2.看板娘
现在部署live2d的看板娘直接在插件市场里面安装就行了live2d 看板娘,而且能接入ai且有agent能力。我选择的ai是智谱4.7flash,主要是因为免费而且看板娘也不需要很聪明。要注意的是添加模型那里的选项是没有免费模型的,要自己输入glm-4.7-flash。
3.Steam信息展示
同样是插件:Steam 信息展示。 有些主题不支持的话就新增页面,地址为域名/steam,我找了好久才找到,插件设置里面是没有的。但加载很慢最好整上加速,不知道为什么我的crash开了局域网连接docker也连接失败。
4.音乐
依旧插件用的是Navidrome 播放器。参考
文章
1.音乐
文章内独立的音乐链接是使用了HTML 块实现的,然而原版编辑器中并不支持HTML块,依旧安装插件Markdown / HTML 内容块,不得不说halo这个平台的编辑器挺垃圾的都没有,markdown都不支持。
<!-- 引入 APlayer 核心样式与脚本(国内CDN,移动端全网络兼容) -->
<link rel="stylesheet" href="https://cdn.staticfile.org/aplayer/1.10.1/APlayer.min.css">
<script src="https://cdn.staticfile.org/aplayer/1.10.1/APlayer.min.js"></script>
<!-- 播放器容器,添加保底高度避免移动端样式塌陷 -->
<div id="aplayer-p5r-local" style="min-height: 66px; margin: 16px 0;"></div>
<!-- 纯本地化歌曲数据配置模板 -->
<script>
const ap = new APlayer({
container: document.getElementById('aplayer-p5r-local'),
preload: 'none', /* 不预加载音频 */
autoplay: false, /* 关闭自动播放,防止和全局自建播放器冲突 */
theme: '#b71c1c', /* 播放器主题色 */
audio: [
{
name: 'Take Over',
artist: 'Lyn',
url: '',
cover: ''
},
{
name: 'Life Will Change',
artist: 'Lyn, アトラスサウンドチーム, ATLUS GAME MUSIC',
url: '',//音乐
cover: ''//封面
}
]
});
</script>
第一次修改
2026年7月13日,发现这样手机上需要刷新一下才能显示,查了一下是PJAX问题,用 1px 透明图的onload 事件触发初始化,元素插入 DOM 就会执行,绕过 PJAX 脚本不执行的限制,同时处理APlayer 资源加载,避免重复加载和未定义报错。改为页脚全局注入:
<!-- 全局 APlayer PJAX 兼容方案 -->
<link rel="stylesheet" href="https://cdn.staticfile.org/aplayer/1.10.1/APlayer.min.css">
<script>
(function() {
// 全局只加载一次 APlayer 脚本
function loadAPlayer(callback) {
if (typeof APlayer !== 'undefined') {
callback();
return;
}
const script = document.createElement('script');
script.src = 'https://cdn.staticfile.org/aplayer/1.10.1/APlayer.min.js';
script.onload = callback;
document.head.appendChild(script);
}
// 扫描并初始化所有播放器容器
function initAllPlayers() {
const players = document.querySelectorAll('.aplayer-auto:not([data-inited])');
if (players.length === 0) return;
loadAPlayer(function() {
players.forEach(function(container) {
if (container.dataset.inited) return;
container.dataset.inited = 'true';
const theme = container.dataset.theme || '#b71c1c';
let audio = [];
try {
audio = JSON.parse(container.dataset.audio || '[]');
} catch(e) {
console.error('APlayer 音频配置格式错误', e);
return;
}
new APlayer({
container: container,
preload: 'none',
autoplay: false,
theme: theme,
audio: audio
});
});
});
}
// 首屏加载
document.addEventListener('DOMContentLoaded', initAllPlayers);
// PJAX 页面切换后重新扫描
document.addEventListener('pjax:complete', initAllPlayers);
// DOM 动态插入兜底
const observer = new MutationObserver(initAllPlayers);
observer.observe(document.body, { childList: true, subtree: true });
})();
</script>文章内使用方法为:
<div
class="aplayer-auto"
style="min-height: 66px; margin: 16px 0;"
data-theme="#b71c1c"
data-audio='[
{"name":"歌曲名1","artist":"歌手1","url":"音频链接1","cover":""},
{"name":"歌曲名2","artist":"歌手2","url":"音频链接2","cover":""}
]'
></div>