记一次部署 Yohaku 作为个人空间
这两天访问到 静かな森 时注意到其主题 Yohaku 非常符合我的个人审美,相较于我原来功能更全面但不精细的 Astral Reverie 说,Yohaku 在文字创作的深度上更适合生活记录、个人空间,其记录的体现形式也覆盖了个人的琐事、学习、灵感的需求。由于属于本人首次接触现代前端项目,在此之前以 PHP 及原生 CSS 和 JS 为主要的我在部署 Yohaku 时遇到了许多大大小小的问题,故在此做文章以记录,供以后参考。
由于本人已有带有公网 IPv4 地址的云服务器,因此本篇文章主要介绍在 Linux 云服务器环境下(带宝塔面板)进行部署。基于 Vercel 部署的方案本文并未涉及,如有需要请参考互联网的其他文章。
引用
相关项目仓库:
本文章引用的相关文档、技术说明和指南:
Important
Yohaku 项目为闭源项目,因此 Innei 在 GitHub 的 Yohaku 仓库为私有属性仓库,如果需要访问该仓库,需要通过 GitHub Sponsor 赞助开发者。
https://github.com/sponsors/Innei
环境部署和需要
Yohaku 项目的本体位于 GitHub 上,需要首先进行编译构建后部署到服务器;由于 Node.js 项目在编译时对设备性能开销较大,因此选择采用 GitHub Action 工作流的形式呈现。
域名注册和配置 DNS
目前主流的域名注册渠道有国内的腾讯云、阿里云、百度云,外国的 Cloudflare、GoDaddy 和 DynaDot。在这里我个人推荐使用 Cloudflare 进行注册,或者你也可以选择你喜欢的域名服务商,这一点并无区别。
注册域名后,进入你的域名服务商的「DNS 解析」管理处(注意:腾讯云的域名管理在 DNSPod 进行),分别添加以下 A 解析记录,解析地址填写你的服务器的 公网 IP:
- @
- api
Note
解析记录指你的域名的三级、四级或更高域名;例如对
example.com进行 A 解析到地址1.1.1.1,记录为 api 时,DNS 服务器会将api.example.com解析到1.1.1.1。需要注意,@ 指代域名的 root,记录 @ 代表的就是其本身。
服务器环境和账号注册
首先我们需要准备一个具备公网上网的服务器,并拥有一个独立域名。以腾讯云为例,一般一个云服务器的价格在每月 CNY 30 - CNY 70 之间,一个域名的价格最低只需要每年 CNY 10。这些资源对于建立网站来说并不贵,甚至可以说非常划算。除了这两项硬件要求,我们还需要以下软件上的硬性要求:
- 一个 GitHub 账户(可前往此处注册)
- 在服务器部署以下运行环境
- Docker
- Node.js 20.11 或更新版本(特别提示:此软件无法在较旧服务器搭载的 CentOS 7 环境中运行)
- pnpm
- pm2
- sharp
此外,基于 Yohaku 具有的各种功能实现,推荐有以下软件:
- Clerk 账号
- TMDB 账号
对于服务器的 Node.js 环境配置,你可以参考下面这些代码:
curl -fsSL https://rpm.nodesource.com/setup_20.x | sudo bash -
sudo dnf install -y nodejs
# 验证
node -v
npm install -g pnpm
# 验证
pnpm -v
npm install -g pm2
# 验证
pm2 -v
cd && mkdir -p mx-space/core && cd $_
pnpm add sharp
如果你使用宝塔面板 Node.js 管理器安装的 Node.js,并且因此在终端无法找到 Node.js,你可以参考管理器显示的安装路径,并将其添加到你的 PATH。
对于服务器的 Docker 环境配置,腾讯云的宝塔应用服务器一般会配备好 Docker,1Panel 面板同样会自带 Docker。你可以通过在终端输入 docker -v 以确定你是否安装了 Docker。如果终端回馈了一个版本号,即代表该服务器安装了 Docker。
如有需要,你可以在参考下面这个安装 Docker 的终端指令:
# 如果你的服务器在国内,建议使用阿里云的安装脚本
curl -fsSL https://get.docker.com | bash -s docker --mirror Aliyun
# 在国外,可以直接使用官方脚本安装
curl -fsSL https://get.docker.com | bash -s docker
# 查询版本以验证安装
docker -v
后端服务配置
部署 MixSpace
Tip
对于这部分内容,你可以从官方文档获取更详细的解释: https://mx-space.js.org/docs/core/docker
Yohaku 项目是一个前后端分离的项目,其依托于 MixSpace 后端存在。因此我们首先需要部署 MixSpace,以更简易操作的 Docker 为例,首先拉取用于部署后端的 docker-compose.yml :
cd && mkdir -p mx-space/core && cd $_
# 拉取 docker-compose.yml 文件
wget https://fastly.jsdelivr.net/gh/mx-space/core@master/docker-compose.yml
在 docker-compose.yml 里 environment 字段填入以下必要的信息:
- JWT_SECRET=
- ALLOWED_ORIGINS=
对于这两个属性字段,有以下解释:
JWT 密钥:需要填写长度不小于 16 个字符,不大于 32 个字符的字符串,用于加密用户的 JWT,务必保存好自己的密钥,不要泄露给他人。被允许的域名:需要填写被允许的域名,将你之前在 DNS 配置的解析域名填入此处,用英文逗号,分隔。需要注意,填入的域名为完整且无前缀的域名。例如:api.example.com,example.com;而不是这样:https://api.example.com或只填入api甚至@。
启动 Core:
docker compose up -d
配置反向代理
此处以宝塔面板为例,打开宝塔面板,进入 网站,新建一个网站,域名填写为 api.你的域名,其余不动并点击创建。此时尝试访问你的域名,如果显示为「网站创建成功啦」字样,即代表你的配置没有问题。
在你新建的网站项目右侧点击 设置,在弹窗的左侧找到 SSL 配置一个证书(例如 Let's Encrypt 免费证书)并开启 HTTPS。
随后重复上述步骤,新建另一个域名为 你的域名 的网站。
在你的后台网站 设置 中,在 反向代理 栏目下点击 添加反代,目标 填写 http://127.0.0.1:2333,发送域名填写 $host,点击确定。
在你的前台网站 设置 中,在 反向代理 栏目下点击 添加反代,目标 填写 http://127.0.0.1:2323,发送域名填写 $host,点击确定。
随后前往 https://api.你的域名/proxy/qaqdmin 配置后端服务器。
意外处理
如果遇到可能的各种意外,我推荐你询问 AI Agent。
新时代新风气,我们遇到了一个人工智能蓬勃发展的时代,所以在你遇到了问题的时候请先询问各种 AI 助手程序,它们会帮助你解决大部分疑问。
我在这里仅列出一个我遇到的问题,即我原先在服务器配置了 Cloudreve,因此 Docker 中已经存在名为 redis 的容器,此时需要在 docker-compose.yml 中将相关容器换一个名字部署即可。
更新 MixSpace
在大版本号相同的情况下(例如 11.0.6 -> 11.6.1 或 11.0.6 -> 11.0.8,只要第一个小数点前的数字没有改变,那么都属于大版本号相同),进行 MixSpace 的更新十分简单:
- 进入 MixSpace Core 部署目录;
- 直接
pull拉取新版本; - 上线新版本。
cd ./mx-space/core
docker compose pull app
docker compose up -d app
观察到 Started 字样后,打开你的后台页面,并进行更新检查:
- 文章列表正常显示;
- 文章内关联的评论和内容显示正常;
- 后台登录正常;
- 发送一篇文章,并删除它,测试文章是否能被正常发布和删除。
前端 Yahaku 部署
我采用了 @Innei 提供的 GitHub Actions 进行预构建形式进行部署。
Tip
对于这部分内容,如果你有一定经验,可以参考开发者的官方文档:
Fork 部署工作流仓库
首先,需要从作者的仓库 Fork 一份 deploy 到你的 GitHub 账户。
Note
所谓「Fork(分叉)」在 GitHub 里的意思就是“合法抄作业”。 作者写好了一个“自动部署工作流”的模板仓库,此时你需要根据你的服务器和域名需要对这个工作流进行一些参数微调,但你不能直接改他的代码,所以你需要点一下 Fork 按钮,把他的整个仓库原封不动地复制到你自己的 GitHub 账号下。这样这个仓库就是你的了,你想怎么折腾都行。
- 登录你的 GitHub 账号。
- 打开原作者的这个工作流仓库地址: yohaku-deploy-action
- 视线移到屏幕的右上角,找到一个叫 Fork 的按钮(旁边通常有个小数字),点它!
- 页面会跳出一个 "Create a new fork" 的确认界面。你啥都不用改,直接滑到最下面点击绿色的 Create fork 按钮。
- 等个两三秒,页面刷新后,你会发现左上角的仓库名字变成了
你的用户名/yohaku-deploy-action。
获取 GH_PAT
虽然同为 GitHub 下的功能,但 GitHub Actions 本身并没有权限查看账户名下私有仓库的代码。因此需要配置一个账户的 API 密钥(即 Personal Access Token (PAT)),以供 GitHub Actions 访问仓库。
在 GitHub 任意页面的右上角,点击你的个人头像,在下拉菜单里选择最下面的 Settings(设置)。
在左边那一长溜菜单里,滑到最底下,点击 Developer settings(开发者设置)。
在左边菜单选 Personal access tokens -> 然后选 Tokens (classic)。
在页面右上角,点击 Generate new token -> 选 Generate new token (classic)。(这时候可能会让你输一下 GitHub 密码验证身份)。
到了新建钥匙的页面:
- Note(备注): 随便填,比如写
Deploy-Shiro。 - Expiration(有效期): 选
No expiration(永不过期),免得以后又要重新搞。 - Select scopes(权限范围): 找到
repo这一项,把旁边的大方框打上勾(代表这把钥匙可以访问你的私有仓库)。
- Note(备注): 随便填,比如写
滑到最下面,点击绿色的 Generate token。
Important
页面会显示一串很长很长的乱码(
ghp_开头的),立刻马上把它复制下来,存到你的本地记事本里! 这串密码只显示一次,刷新页面就再也看不到了。
配置 Secrets
接下来将账户的 API 密钥以及其他必要信息填入 Deploy 仓库的配置信息中:
- 回到第一步 Fork 出来的那个仓库主页**(
你的用户名/yohaku-deploy-action)。 - 点击仓库右上方的 Settings(设置) 标签页。
- 在左侧菜单里找,依次点击:Secrets and variables -> Actions。
- 点击页面绿色的按钮 New repository secret。
- 到了填写页面:
- Name(名字): 严格填写
GH_PAT(全大写,必须长这样)。 - Secret(内容): 把你刚才在第二步保存在记事本里的那一长串
ghp_钥匙粘贴进去。
- Name(名字): 严格填写
- 点击 Add secret。
继续点击 New repository secret,把下面这些都加上:
HOST:填你服务器的 IP(比如1.1.1.1)USER:填root或其它你的用户名PASSWORD:填你服务器的 root 密码(如果不安全,可以用KEY填 SSH 密钥,二选一填就行,填密码比较适合新手)PORT:填22(如果你的 SSH 没改过端口就是 22)BASE_URL:填https://你的域名NEXT_PUBLIC_API_URL:填https://api.你的域名/api/v3NEXT_PUBLIC_GATEWAY_URL:填https://api.你的域名
Note
注意确保宝塔面板和你的服务商的云服务器仪表盘防火墙暴露了
22端口。
配置 .env 环境变量文件
在你的服务器 /~ 目录下新建一个名为 shiro 的文件夹,然后新建一个名为 .env 的文件:
cd && mkdir -p shiro && cd $_ && touch .env
在 .env 中填入以下内容,并在空白处填入对应的值:
Tip
虽然按照开发者官方的说法,应该令
NEXT_PUBLIC_GATEWAY_URL=${BASE_URL}、NEXT_PUBLIC_API_URL={BASE_URL}/api/v3。但 Next.js 有时候对
${BASE_URL}这种动态拼接的写法解析会犯傻。为了不给它报错的机会,我建议直接把完整的网址写死。
BASE_URL=
NEXT_PUBLIC_API_URL=
NEXT_PUBLIC_GATEWAY_URL=
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=
CLERK_SECRET_KEY=
NEXT_PUBLIC_CLERK_SIGN_IN_URL=/sign-in
NEXT_PUBLIC_CLERK_SIGN_UP_URL=/sign-up
NEXT_PUBLIC_CLERK_AFTER_SIGN_IN_URL=/
NEXT_PUBLIC_CLERK_AFTER_SIGN_UP_URL=/
TMDB_API_KEY=
GH_TOKEN=
1. 基础网址部分(直接写死更稳妥)
# 你的网站主域名
BASE_URL=https://你的域名
# 后端 API 地址(直接写完整网址)
NEXT_PUBLIC_API_URL=https://api.你的域名/api/v3
# 网关地址
NEXT_PUBLIC_GATEWAY_URL=https://api.你的域名
2. Clerk 身份验证(网站的后台登录)
这是一个用来做登录服务的第三方服务。
- 去 Clerk 官网 注册个账号,新建一个应用。
- 然后在它的控制台里找到这两个 Key 填进来:
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=pk_test_xxxxxxxxxxx (填你在Clerk获取的公钥)
CLERK_SECRET_KEY=sk_test_xxxxxxxxxxx (填你在Clerk获取的私钥)
# 下面这四个是登录跳转的路由,保持原样不用动它!
NEXT_PUBLIC_CLERK_SIGN_IN_URL=/sign-in
NEXT_PUBLIC_CLERK_SIGN_UP_URL=/sign-up
NEXT_PUBLIC_CLERK_AFTER_SIGN_IN_URL=/
NEXT_PUBLIC_CLERK_AFTER_SIGN_UP_URL=/
3. 其他杂项 API
TMDB_API_KEY=
GH_TOKEN=ghp_xxxxxxxxxxxxxxxxx
TMDB_API_KEY:TMDB 是一个电影数据库。Yohaku 博客里支持展示电影卡片。如果你暂时不想搞,可以留空(留空可能电影页面没数据,但不影响网站整体运行)。如果想搞,去 themoviedb.org 申请个 API 填进来。GH_TOKEN:GitHub 动态展示的 Token。你可以直接把上一步申请的那串 ghp_ 开头的“万能钥匙”填在这里。
GitHub Actions
接下来前往仓库的 Action 页面,由 GitHub Actions 对该项目进行预构建。
- 点击顶部的 Actions 标签页。
- 如果看到一个提示说 「I understand my workflows, go ahead and enable them」,就点击绿色的按钮同意启用。
- 在左侧菜单点击工作流名字 Build and Deploy。
- 在右边找到一个写着 Run workflow 的按钮,点它,然后再点弹出的绿色 Run workflow。
如果不存在 Run workflow 按钮,则点进 .github/workflows/ 文件夹,打开 deploy.yml,点击右上角编辑(笔)按钮,随后点击 Commit changes。
Note
当点击保存(Commit)时,系统就会认为你更新了代码(触发 push),随后自行开始 Build and Deploy。
意外处理
如果在使用 GitHub Action 构建 Yohaku 时存在错误,并且日志表现为:
0s
Run sh ./ci-release-build.sh
sh ./ci-release-build.sh
shell: /usr/bin/bash -e {0}
env:
HASH_FILE: build_hash
PNPM_HOME: /home/runner/setup-pnpm/node_modules/.bin
BASE_URL: ***
NEXT_PUBLIC_API_URL: ***
NEXT_PUBLIC_GATEWAY_URL: ***
No projects matched the filters in "/home/runner/work/shiroi-deploy-action/shiroi-deploy-action"
./ci-release-build.sh: 8: cd: can't cd to apps/web/.next
Error: Process completed with exit code 2.
则可尝试对 deploy.yml 做以下修改:
Caution
此方法为个人依据错误分析,并结合 AI Agent 建议进行的修订,可能存在某些暂未发现的 BUG。如果你也遇到了类似的问题,可以尝试联系作者,或者在 GitHub 的 Issue 下提交问题。
name: Build and Deploy
on:
push:
branches:
- main
# schedule:
# - cron: '0 3 * * *'
repository_dispatch:
types: [trigger-workflow]
permissions: write-all
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
env:
HASH_FILE: build_hash
SOURCE_REPO: innei-dev/Yohaku
BUILD_COMMAND: pnpm --filter @yohaku/web build:ci
STANDALONE_SUBPATH: standalone/apps/web
jobs:
prepare:
name: Prepare
runs-on: ubuntu-latest
if: ${{ github.event.head_commit.message != 'Update hash file' }}
outputs:
hash_content: ${{ steps.read_hash.outputs.hash_content }}
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Read HASH_FILE content
id: read_hash
run: |
content=$(cat ${{ env.HASH_FILE }}) || true
echo "hash_content=$content" >> "$GITHUB_OUTPUT"
check:
name: Check Should Rebuild
runs-on: ubuntu-latest
needs: prepare
outputs:
canceled: ${{ steps.use_content.outputs.canceled }}
steps:
- uses: actions/checkout@v4
with:
repository: innei-dev/Yohaku
token: ${{ secrets.GH_PAT }} # `GH_PAT` is a secret that contains your PAT
fetch-depth: 0
lfs: true
submodules: recursive
- name: Use content from prev job and compare
id: use_content
env:
FILE_HASH: ${{ needs.prepare.outputs.hash_content }}
run: |
file_hash=$FILE_HASH
current_hash=$(git rev-parse --short HEAD)
echo "File Hash: $file_hash"
echo "Current Git Hash: $current_hash"
if [ "$file_hash" == "$current_hash" ]; then
echo "Hashes match. Stopping workflow."
echo "canceled=true" >> $GITHUB_OUTPUT
else
echo "Hashes do not match. Continuing workflow."
fi
build:
name: Build artifact
runs-on: ubuntu-latest
needs: check
if: ${{needs.check.outputs.canceled != 'true'}}
strategy:
matrix:
node-version: [lts/*]
outputs:
sha_short: ${{ steps.store.outputs.sha_short }}
branch: ${{ steps.store.outputs.branch }}
steps:
- uses: actions/checkout@v4
with:
repository: ${{ env.SOURCE_REPO }}
token: ${{ secrets.GH_PAT }} # `GH_PAT` is a secret that contains your PAT
fetch-depth: 0
lfs: true
submodules: recursive
- name: Checkout LFS objects
run: git lfs checkout
- uses: pnpm/action-setup@v2
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
cache: 'pnpm'
- uses: jongwooo/next-cache@v1
- name: Install dependencies
run: pnpm install
- name: Build project
env:
BASE_URL: ${{ secrets.BASE_URL }}
NEXT_PUBLIC_API_URL: ${{ secrets.NEXT_PUBLIC_API_URL }}
NEXT_PUBLIC_GATEWAY_URL: ${{ secrets.NEXT_PUBLIC_GATEWAY_URL }}
run: |
${{ env.BUILD_COMMAND }}
cd apps/web/.next
rm -rf cache
cp -r ../public ./standalone/public
mv ./static ./standalone/apps/web/.next/static
cd ./standalone
echo ';process.title = "Yohaku (NextJS)"' >> server.js
cd "$GITHUB_WORKSPACE"
mkdir -p assets
rm -f assets/release.zip
(cd apps/web/.next && zip --symlinks -r "$GITHUB_WORKSPACE/assets/release.zip" ./* -x "dev/*" -x "cache/*")
# - uses: actions/upload-artifact@v4
# with:
# name: dist
# path: assets/release.zip
# retention-days: 7
- name: Cache Build Artifacts
id: cache-primes
uses: actions/cache/save@v4
with:
path: assets
key: ${{ github.run_number }}-release
- name: Store artifact commit version
shell: bash
id: store
run: |
sha_short=$(git rev-parse --short HEAD)
branch_name=$(git rev-parse --abbrev-ref HEAD)
echo "sha_short=$sha_short" >> "$GITHUB_OUTPUT"
echo "branch=$branch_name" >> "$GITHUB_OUTPUT"
deploy:
name: Deploy artifact
runs-on: ubuntu-latest
needs: build
steps:
# - name: Download artifact
# uses: actions/download-artifact@v4
# with:
# name: dist
- name: Restore cached Build Artifacts
id: cache-primes-restore
uses: actions/cache/restore@v4
with:
path: |
assets
key: ${{ github.run_number }}-release
- name: Move assets to root
run: mv assets/release.zip release.zip
- name: Create PM2 config file
run: |
cat > ecosystem.config.js << 'EOF'
module.exports = {
apps: [
{
name: 'Shiroi',
script: './server.js',
cwd: __dirname,
exec_mode: 'fork',
instances: 1,
autorestart: true,
watch: false,
max_memory_restart: '180M',
env: {
NODE_ENV: 'production',
HOSTNAME: '0.0.0.0',
PORT: process.env.PORT || 2323,
},
log_date_format: 'YYYY-MM-DD HH:mm:ss',
merge_logs: true,
},
],
};
EOF
- name: copy file via ssh password
uses: appleboy/[email protected]
with:
host: ${{ secrets.HOST }}
username: ${{ secrets.USER }}
password: ${{ secrets.PASSWORD }}
key: ${{ secrets.KEY }}
port: ${{ secrets.PORT }}
source: 'release.zip'
target: '/tmp/yohaku'
- name: copy PM2 config via ssh password
uses: appleboy/[email protected]
with:
host: ${{ secrets.HOST }}
username: ${{ secrets.USER }}
password: ${{ secrets.PASSWORD }}
key: ${{ secrets.KEY }}
port: ${{ secrets.PORT }}
source: 'ecosystem.config.js'
target: '/tmp/yohaku'
- name: Exec deploy script with SSH
uses: appleboy/ssh-action@master
with:
command_timeout: 5m
host: ${{ secrets.HOST }}
username: ${{ secrets.USER }}
password: ${{ secrets.PASSWORD }}
key: ${{ secrets.KEY }}
port: ${{ secrets.PORT }}
script: |
set -e
source $HOME/.bashrc
basedir=$HOME/yohaku
workdir=$basedir/${{ github.run_number }}
mkdir -p $workdir
mkdir -p $basedir/.cache
mv /tmp/yohaku/release.zip $workdir/release.zip
install -m 644 /tmp/yohaku/ecosystem.config.js $basedir/ecosystem.config.js
cd $workdir
unzip -qq -o $workdir/release.zip
rm -r /tmp/yohaku
rm -rf $workdir/${{ env.STANDALONE_SUBPATH }}/.env
ln -s $HOME/yohaku/.env $workdir/${{ env.STANDALONE_SUBPATH }}/.env
export NEXT_SHARP_PATH=$(npm root -g)/sharp
# https://github.com/Unitech/pm2/issues/3054
# symlink workdir node entry file to basedir
ln -sf $workdir/${{ env.STANDALONE_SUBPATH }}/server.js $basedir/server.js
mkdir -p $workdir/${{ env.STANDALONE_SUBPATH }}/.next
rm -rf $workdir/${{ env.STANDALONE_SUBPATH }}/.next/cache
ln -sf $basedir/.cache $workdir/${{ env.STANDALONE_SUBPATH }}/.next/cache
cd $basedir
if pm2 describe Shiroi >/dev/null 2>&1; then
pm2 reload ecosystem.config.js --update-env
else
pm2 start ecosystem.config.js --update-env
fi
rm $workdir/release.zip
pm2 save
echo "Deployed successfully"
- name: After deploy script
run: |
hash=${{ needs.build.outputs.sha_short }}
# curl -X "POST" "https://mx.innei.in/api/v2/fn/shiro/new-version-hook" -H 'Content-Type: application/json' -d "{\"hash\": \"$hash\", \"key\": \"\"}"
${{ secrets.AFTER_DEPLOY_SCRIPT }}
store:
name: Store artifact commit version
runs-on: ubuntu-latest
needs: [deploy, build]
steps:
- name: Checkout
uses: actions/checkout@v4
with:
persist-credentials: false # otherwise, the token used is the GITHUB_TOKEN, instead of your personal token
fetch-depth: 0 # otherwise, you will failed to push refs to dest repo
# Get the commit version from the build job
- name: Use outputs from build
env:
SHA_SHORT: ${{ needs.build.outputs.sha_short }}
BRANCH: ${{ needs.build.outputs.branch }}
run: |
echo "SHA Short from build: $SHA_SHORT"
echo "Branch from build: $BRANCH"
- name: Write hash to file
env:
SHA_SHORT: ${{ needs.build.outputs.sha_short }}
run: echo $SHA_SHORT > ${{ env.HASH_FILE }}
- name: Commit files
run: |
git config --local user.email "41898282+github-actions[bot]@users.noreply.github.com"
git config --local user.name "github-actions[bot]"
git add ${{ env.HASH_FILE }}
git commit -a -m "Update hash file"
- name: Push changes
uses: ad-m/github-push-action@master
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
branch: ${{ github.ref }}
在 MixSpace 配置
Note
与此部分内容有关的官方文档:
进入 Mix Space 后台,进入「配置与云函数」页面,点击右上角的新增按钮,在编辑页面中,填入以下设置:
- 名称:
shiro - 引用:
theme - 数据类型:
JSON - 数据(此处以官方示例数据为模板):
{
"footer": {
"otherInfo": {
"date": "2020-{{now}}",
"icp": {
"text": "萌 ICP 备 20236136 号",
"link": "https://icp.gov.moe/?keyword=20236136"
}
},
"linkSections": [
{
"name": "关于",
"links": [
{
"name": "关于本站",
"href": "/about-site"
},
{
"name": "关于我",
"href": "/about"
},
{
"name": "关于此项目",
"href": "https://github.com/innei/Shiro",
"external": true
}
]
},
{
"name": "更多",
"links": [
{
"name": "时间线",
"href": "/timeline"
},
{
"name": "友链",
"href": "/friends"
},
{
"name": "监控",
"href": "https://status.innei.in/status/main",
"external": true
}
]
},
{
"name": "联系",
"links": [
{
"name": "写留言",
"href": "/message"
},
{
"name": "发邮件",
"href": "mailto:[email protected]",
"external": true
},
{
"name": "GitHub",
"href": "https://github.com/innei",
"external": true
}
]
}
]
},
"config": {
"color": {
"light": [
"#33A6B8",
"#FF6666",
"#26A69A",
"#fb7287",
"#69a6cc",
"#F11A7B",
"#78C1F3",
"#FF6666",
"#7ACDF6"
],
"dark": [
"#F596AA",
"#A0A7D4",
"#ff7b7b",
"#99D8CF",
"#838BC6",
"#FFE5AD",
"#9BE8D8",
"#A1CCD1",
"#EAAEBA"
]
},
"bg": [
"/static/images/F0q8mwwaIAEtird.jpeg",
"/static/images/IMG_2111.jpeg.webp.jpg"
],
"custom": {
"css": [],
"styles": [],
"js": [],
"scripts": []
},
"site": {
"favicon": "/innei.svg",
"faviconDark": "/innei-dark.svg"
},
"hero": {
"title": {
"template": [
{
"type": "h1",
"text": "Hi, I'm ",
"class": "font-light text-4xl"
},
{
"type": "h1",
"text": "Innei",
"class": "font-medium mx-2 text-4xl"
},
{
"type": "h1",
"text": "👋。",
"class": "font-light text-4xl"
},
{
"type": "br"
},
{
"type": "h1",
"text": "A NodeJS Full Stack ",
"class": "font-light text-4xl"
},
{
"type": "code",
"text": "<Developer />",
"class": "font-medium mx-2 text-3xl rounded p-1 bg-gray-200 dark:bg-gray-800/0 hover:dark:bg-gray-800/100 bg-opacity-0 hover:bg-opacity-100 transition-background duration-200"
},
{
"type": "span",
"class": "inline-block w-[1px] h-8 -bottom-2 relative bg-gray-800/80 dark:bg-gray-200/80 opacity-0 group-hover:opacity-100 transition-opacity duration-200 group-hover:animation-blink"
}
]
},
"description": "An independent developer coding with love."
},
"module": {
"activity": {
"enable": true,
"endpoint": "/fn/ps/update"
},
"donate": {
"enable": true,
"link": "https://afdian.net/@Innei",
"qrcode": [
"/static/images/20191211132347.png",
"/static/images/0424213144.png"
]
},
"bilibili": {
"liveId": 1434499
}
}
}
}
点击按钮保存配置。
最后
本次部署 Yohaku 的过程,本质上是一次对现代 CI/CD 工作流的实战演练。从宝塔面板的环境纠偏,到 GitHub Actions 的深度调试,每解决一个 Error 都是对自身知识体系的重构。
部署成功只是第一步,真正的乐趣在于后续的创作或定制。如果你在参考本文过程中遇到了新的“玄学问题”,欢迎在评论区留言交流,或者直接向作者 Innei 请教。希望这篇文章能在你搭建个人空间时提供关键帮助。
