余白之间:用1Panel部署Yohaku/Shiroi主题完全指南
Note这是「Mix Space + Yohaku 部署系列」的第二篇,专注于前端主题 Yohaku 的安装。如尚未部署后端,请先阅读第一篇——《从零开始 · 用 1Panel 部署 Mix Space 后端》
Yohaku,取自日文「余白」,意为留白——画面中那些有意空出的地方,往往比填满的部分更有分量。
这是 Mix Space 生态中最新一代的前端主题。它的故事从开源的 Shiro 开始,经由闭源赞助版 Shiroi 的沉淀,一路演进至今日的 Yohaku——三代传承,设计语言与实现在每一步都在悄然迭代。整站以书写为隐喻,页面像一封徐徐展开的信纸,用克制的色彩和呼吸式的动画,让阅读本身成为主角。
三代主题的关系,简单梳理一下:
- Shiro → Mix Space 最初的开源前端主题,代码公开在 GitHub
- Shiroi → Shiro 的闭源捐赠版,在 Shiro 基础上演进,赞助后可访问
- Yohaku(余白) → 由 Shiro / Shiroi 进一步演进而来的全新设计,同样以闭源赞助形式维护,是目前最新的一代
本文部署的主角是 Yohaku,由于它是闭源主题,需要自行构建 Docker 镜像,下文会手把手带你完成。(本教程亦兼容 Shiroi)
前提说明:本文假设你拥有闭源版仓库的访问权限,且已完成 Mix Space 后端的部署,手边备好了两个地址:
后端 API 地址:形如https://你的域名/api/v3(后端版本V13之前为v2)后端网关地址:形如https://你的域名
如尚未部署后端,请先阅读第一篇完成。
第一步 · 构建 Docker 镜像
(使用开源版 Shiro 的请直接跳转第二步) 由于作者没有提供 Shiroi / Yohaku 主题预构建的 Docker 镜像,所以需要我们自行构建。但请不要在低配服务器上直接构建——服务器的内存会被撑爆 💥
我们的方案是借助 GitHub Actions 在云端完成构建,然后把镜像推送到 GitHub Packages(ghcr.io)私有仓库里。服务器只需要拉取现成的镜像,非常简便。
1.1 准备仓库
访问以下仓库,点击右上角的 Fork:
再访问以下链接新建仓库(Choose visibility 一定要选择 Private!!!),建议命名为 yohaku,如不同需在后面的工作流文件做出对应修改。
1.2 申请 GitHub 经典访问令牌(Classic Token)
Actions 需要有权限读取 Shiroi 私有仓库、并将构建好的镜像推送到 GitHub Packages。我们要提前准备一个经典令牌(Classic Token)。
访问https://github.com/settings/tokens/new
填写备注(例如 yohaku-build),有效期可设为永久,然后勾选以下权限:
| 权限 | 用途说明 |
|---|---|
repo | 读写仓库,含私有仓库访问 |
workflow | 更新 GitHub Action 工作流 |
write:packages | 将镜像推送到 GitHub Packages |
read:packages | 从 GitHub Packages 拉取镜像 |
点击 Generate token,立即将生成的 Token 复制保存好——它只显示这一次!
1.3 配置仓库 Actions 变量
进入你 Fork 的仓库,依次点击:
Settings → Secrets and variables → Actions → Repository secrets
添加以下两个变量:
| 变量名 | 填写内容 |
|---|---|
BASE_URL | Core 后端所绑定的域名(如https://jiye.funcun.top) |
GH_PAT | 上一步申请的 Personal Access Token |
NEXT_PUBLIC_GATEWAY_URL | 可选,如https://jiye.funcun.top |
NEXT_PUBLIC_API_URL | 可选,如https://jiye.funcun.top/api/v3 |
进入新建的 Yohaku 仓库,如刚刚的操作添加变量
| 变量名 | 填写内容 |
|---|---|
UPSTREAM_REPO_SECRET | 上一步申请的 Personal Access Token |
1.4 启用并触发构建
先进入新建的 Yohaku 仓库,将 Fork 仓库中的 upstream-sync.yml 文件上传到该仓库,然后在服务器/其它设备执行以下脚本,根据提示输入即可(有默认的选项建议默认)
#!/bin/bash
set -euo pipefail
# =============================================
# 脚本介绍:
# 本脚本用于将上游仓库的指定分支,强制同步到你个人仓库的目标分支。
# 适用于从公开/私有的上游仓库拉取更新,并推送到自己的分支(如镜像同步)。
# 强制推送会覆盖目标分支的历史,请谨慎操作!
# =============================================
echo "======================================="
echo " 上游仓库 → 个人仓库 强制同步工具"
echo "======================================="
echo ""
echo "本脚本将执行以下操作:"
echo "1. 克隆上游仓库到临时目录"
echo "2. 添加你的个人远程仓库"
echo "3. 将上游分支强制推送到个人仓库的目标分支"
echo "注意:目标分支的现有内容将被完全覆盖!"
echo "======================================="
echo ""
# ---------- 收集你的个人仓库信息 ----------
read -r -p "请输入你的 GitHub 用户名: " USERNAME
read -r -p "请输入你的目标仓库名: " REPO
echo "请输入你的 GitHub Personal Access Token(输入时不显示,需有 repo 权限):"
read -r -s TOKEN
echo # 换行
# ---------- 收集上游仓库信息 ----------
read -r -p "上游仓库是否为私有?(y/n,默认 n): " UPSTREAM_PRIVATE
UPSTREAM_PRIVATE=${UPSTREAM_PRIVATE:-n}
read -r -p "请输入上游仓库的完整地址(如 https://github.com/innei-dev/Yohaku.git): " UPSTREAM
if [ "$UPSTREAM_PRIVATE" = "y" ] || [ "$UPSTREAM_PRIVATE" = "Y" ]; then
echo "上游仓库为私有,需要提供访问该仓库的 Token(输入时不显示):"
read -r -s UPSTREAM_TOKEN
echo
# 构造带认证的上游 URL
UPSTREAM_AUTH_URL=$(echo "$UPSTREAM" | sed "s|https://|https://x-access-token:${UPSTREAM_TOKEN}@|")
else
UPSTREAM_AUTH_URL="$UPSTREAM"
fi
read -r -p "请输入临时目录名(默认 temp-upstream): " TEMP_DIR
TEMP_DIR=${TEMP_DIR:-temp-upstream}
read -r -p "请输入上游仓库的分支名(默认 main): " SRC_BRANCH
SRC_BRANCH=${SRC_BRANCH:-main}
read -r -p "请输入要推送到个人仓库的目标分支名(默认 sync): " DST_BRANCH
DST_BRANCH=${DST_BRANCH:-sync}
# ---------- 构建个人远程地址 ----------
MY_REMOTE="https://${USERNAME}:${TOKEN}@github.com/${USERNAME}/${REPO}.git"
# ---------- 处理临时目录 ----------
while [ -d "$TEMP_DIR" ] && [ "$(ls -A "$TEMP_DIR" 2>/dev/null)" ]; do
echo ""
echo "警告:目录 '$TEMP_DIR' 已存在且不为空。"
read -r -p "是否删除并重新创建?(y/n): " answer
if [ "$answer" = "y" ] || [ "$answer" = "Y" ]; then
rm -rf "$TEMP_DIR"
echo "已删除旧目录。"
else
read -r -p "请输入一个新的临时目录名: " TEMP_DIR
fi
done
# ---------- 执行同步 ----------
echo ""
echo "正在克隆上游仓库 $UPSTREAM 到 $TEMP_DIR ..."
git clone "$UPSTREAM_AUTH_URL" "$TEMP_DIR"
cd "$TEMP_DIR"
echo "正在添加你的远程仓库 myrepo ..."
git remote add myrepo "$MY_REMOTE"
echo "正在强制推送 $SRC_BRANCH -> myrepo/$DST_BRANCH ..."
git push --force myrepo "$SRC_BRANCH:$DST_BRANCH"
cd ..
echo "清理临时目录 $TEMP_DIR ..."
rm -rf "$TEMP_DIR"
echo ""
echo "======================================="
echo "同步完成!"
echo "已将 $UPSTREAM 的 $SRC_BRANCH 分支"
echo "强制推送到 $USERNAME/$REPO 的 $DST_BRANCH 分支。"
echo "======================================="
完成后进入 Yohaku 仓库的 Actions 标签页,如有提示请点击启用。然后找到构建 Workflow,点击右侧的 Run workflow 手动触发一次。
构建过程通常需要 5 ~ 10 分钟,可以去泡杯茶等待 ☕
构建完成后,在仓库侧边栏的 Packages 中就能看到你的镜像,地址格式为:
ghcr.io/你的用户名(全小写)/yohaku:latest
1.5 在 1Panel 中配置 ghcr.io 私有仓库
由于镜像存放在私有 GitHub Container Registry,1Panel 需要先登录认证才能拉取。
登入 1Panel 面板,前往 容器 → 仓库 → 创建仓库,填写:
| 字段 | 内容 |
|---|---|
| 名称 | ghcr.io(任意便于识别的名字) |
| 仓库地址 | ghcr.io |
| 用户名 | 你的 GitHub 用户名 |
| 密码 | 你的 Personal Access Token(GH_PAT) |
保存后,1Panel 会自动验证连接。这样以后拉取私有镜像就畅通无阻了 🔐
第二步 · 通过 1Panel 安装 Yohaku
2.1 上传应用包
登入 1Panel 面板,在左侧菜单进入 主机 → 文件,导航到路径:
/opt/1panel/resource/apps/local
点击上传,选择你从 Fork 的仓库下载的 yohaku.zip 文件。
2.2 解压,注意路径!
上传完成后,点击 yohaku.zip,选择解压。
这一步是新手最常踩的坑,请务必注意!
解压时需要手动将目标路径补全为:
/opt/1panel/resource/apps/local/yohaku
路径不对,可能产生一堆位于错误目录的文件,应用商店将无法识别此本地应用。
2.3 同步本地应用
前往 1Panel 应用商店,点击右上角的同步本地应用按钮,稍等片刻后在搜索框输入 yohaku,便能看到刚刚添加的应用了。
点击安装,进入配置页面。
2.4 填写安装配置项
安装页面共有四个必填项(另有一条只读说明),从上到下依次填写:
🐳 镜像地址(Image Address)
这里填写容器镜像。根据你部署的版本选择:
开源版 Shiro(直接使用官方预构建镜像):
innei/shiro:latest
闭源版 Shiroi / Yohaku(填写第一步自行构建的私有镜像):
ghcr.io/你的用户名(全小写)/shiroi:latest
📡 公开 API 地址(PUBLICAPIURL)
填写你的 Mix Space 后端 API 地址:
https://你的后端域名/api/v2
注意保留末尾的 /api/v2 路径。
🌐 公开网关地址(PUBLICGATEWAYURL)
填写你的 Mix Space 后端网关地址(即后端根域名):
https://你的后端域名
不需要加任何路径后缀。
🔗 API URL 与客户端 API 地址
API_URL 与 NEXT_PUBLIC_CLIENT_API_URL 这两项的值与公开 API 地址保持一致,填入相同内容即可:
https://你的后端域名/api/v2
2.5 开始安装 🎉
确认配置无误,点击开始安装。
1Panel 会自动拉取镜像并启动容器,此过程根据网络状况可能需要几分钟。当状态显示为运行中(Running),Yohaku 就正式上线了!
第三步 · 配置反向代理与 HTTPS
参见上篇博客,若已配置可略过。
附:Yohaku 支持的扩展 Markdown 语法
Yohaku 继承自 Shiro 体系,支持一套丰富的扩展 Markdown 语法,让你的博文不止于纯文字。以下是写作时可以使用的特色语法——
数学公式(KaTeX)
行内公式:
质能方程 $E = mc^2$ 改变了人类对宇宙的认知。
块级公式:
$$
\int_{-\infty}^{+\infty} e^{-x^2} dx = \sqrt{\pi}
$$
提示横幅(Notice / Banner)
::: warning
这里是警告内容,背景会呈现醒目的颜色。
:::
::: banner {note}
这里是备注,适合附加额外说明。
:::
::: banner {error}
这里是错误提示,用于强调危险操作。
:::
GFM Alert 语法
> [!NOTE]
> 这是一条备注,提醒读者注意某些事项。
> [!IMPORTANT]
> 这是重要信息,不容忽视。
> [!WARNING]
> 这是警告,可能涉及潜在风险。
剧透遮罩(Spoiler)
这部电影的结局是 ||主角其实已经死了||,令人意想不到。
注意:这与删除线 ~~文字~~ 的效果不同,Spoiler 会用遮罩隐藏内容,鼠标悬停后才显示。
富链接(Rich Link)
对于单独成行的链接,Yohaku 会自动渲染为带封面和摘要的卡片样式:
https://github.com/Innei/Yohaku
支持识别的平台包括 GitHub 仓库、Commit、Issue、Gist,以及 YouTube、Twitter 等。
内联链接图标
行内链接会自动附上对应网站的 Favicon:
访问 [Innei 的主页](https://innei.in) 了解更多。
Mention(提及)
感谢 [Innei]{GH@Innei} 创作了这么美的主题。
GH@用户名 会自动渲染为带头像的 GitHub 用户卡片。
折叠块(Collapse)
<details>
<summary>点击展开查看详细内容</summary>
这里是折叠起来的详细说明……
</details>
常见问题
Q:镜像拉取速度极慢或失败怎么办?
国内服务器拉取 ghcr.io 时可能较慢。可以在 GitHub Actions 的构建 Workflow 中添加同步推送至阿里云 ACR 的步骤,再从阿里云拉取。具体配置可参考薄荷の小屋的教程。
Q:Actions 构建失败,如何排查?
进入仓库的 Actions 页面,点击失败的 Workflow 查看详细日志,常见原因:
GH_PAT权限不够,检查是否勾选了repo和write:packagesDOCKER_NAMESPACE没有全部小写- 仓库被设为公开,导致权限冲突
Q:解压后应用商店搜不到 yohaku?
大概率是解压路径不对。请确认解压目标为 /opt/1panel/resource/apps/local/yohaku(不是 /opt/1panel/resource/apps/local)。确认后重新点击「同步本地应用」。
Q:页面能访问,但提示后端连接失败?
检查以下几点:
- 四个 API 地址配置项是否填写正确,尤其是
/api/v2路径不能遗漏 - Mix Space 后端的
ALLOWED_ORIGINS中是否已包含 Yohaku 前端的域名 - 后端反向代理和 HTTPS 证书是否正常工作
参考资料
本文写作过程中参考了以下资料,感谢各位博主的慷慨分享 💝
- 1Panel 在线安装文档
- GitHub Action 构建 Shiroi Docker 镜像 · Mikuの极光星
- Mix Space + Shiro 全容器化部署指南 · 薄荷の小屋
- 自助创建 1Panel 应用 · FIT2CLOUD 社区论坛
- 自助创建 1Panel 应用工具
- Shiro Markdown 扩展语法文档
- Yohaku 主题文档
- 添加NEXT_PUBLIC_CLIENT_API_URL
- 添加API_URL
- 破事水 | Actions 同步上游项目及合并到自己分支
- GitHub Actions 构建 Yohaku 的 Docker 镜像
余白,是一种态度。
愿你的博客,也能成为那封值得被细细展开的信纸 🌿
