A Record of Deploying Yohaku as a Personal Space
These past few days, when visiting 静かな森, I noticed that its theme Yohaku matches my personal aesthetic very well. Compared to my previous Astral Reverie, which was more feature-rich but less refined, Yohaku is more suitable for life records and personal space in terms of depth of text creation. Its manifestation also covers personal trivial matters, learning, and inspiration needs. Since this is my first time dealing with a modern frontend project, and before this I primarily used PHP along with vanilla CSS and JS, I encountered many problems, big and small, when deploying Yohaku. Hence, this article is written to document the process for future reference.
Since I already have a cloud server with a public IPv4 address, this article mainly covers deployment on a Linux cloud server environment (with Baota panel). The deployment plan based on Vercel is not covered in this article; if needed, please refer to other articles on the internet.
References
Related project repository:
Relevant documentation, technical instructions, and guides referenced in this article:
Important
The Yohaku project is a closed-source project, so Innei's Yohaku repository on GitHub is a private repository. If you need access to this repository, you need to sponsor the developer via GitHub Sponsor.
https://github.com/sponsors/Innei
Environment Deployment and Requirements
The main body of the Yohaku project is located on GitHub. It needs to be compiled and built first, then deployed to the server. Since Node.js projects have high performance overhead during compilation, I chose to use the GitHub Action workflow approach.
Domain Name Registration and DNS Configuration
Currently popular domain registration channels include domestic ones like Tencent Cloud, Alibaba Cloud, Baidu Cloud, and foreign ones like Cloudflare, GoDaddy, and DynaDot. I personally recommend using Cloudflare for registration, or you can choose your favorite domain service provider; there is no difference.
After registering the domain, go to the "DNS Resolution" management of your domain service provider (Note: Tencent Cloud's domain management is done at DNSPod), and add the following A resolution records, filling in your server's public IP as the resolution address:
- @
- api
Note
Resolution records refer to third-level, fourth-level, or higher domain names of your domain; for example, when performing A resolution for
example.comto address1.1.1.1, if the record is api, the DNS server will resolveapi.example.comto1.1.1.1. Note that @ represents the root of the domain; the record @ represents the domain itself.
Server Environment and Account Registration
First, we need to prepare a server with public network access and have an independent domain name. Taking Tencent Cloud as an example, the price of a cloud server is generally between CNY 30 and CNY 70 per month, and the minimum price of a domain name is only CNY 10 per year. These resources are not expensive for building a website; in fact, they are quite cost-effective. In addition to these two hardware requirements, we also need the following software prerequisites:
- A GitHub account (register here)
- Deploy the following runtime environments on the server
- Docker
- Node.js 20.11 or newer (Special note: This software cannot run on CentOS 7 systems installed on older servers)
- pnpm
- pm2
- sharp
Additionally, based on the various functional implementations of Yohaku, the following software is recommended:
- Clerk account
- TMDB account
For the Node.js environment configuration on the server, you can refer to the following code:
curl -fsSL https://rpm.nodesource.com/setup_20.x | sudo bash -
sudo dnf install -y nodejs
# Verify
node -v
npm install -g pnpm
# Verify
pnpm -v
npm install -g pm2
# Verify
pm2 -v
cd && mkdir -p mx-space/core && cd $_
pnpm add sharp
If you installed Node.js using the Baota panel Node.js manager and therefore cannot find Node.js in the terminal, you can refer to the installation path displayed by the manager and add it to your PATH.
For the Docker environment configuration on the server, Tencent Cloud's Baota application server usually comes with Docker pre-installed, and the 1Panel panel also comes with Docker. You can check whether Docker is installed by entering docker -v in the terminal. If the terminal returns a version number, it means Docker is installed on the server.
If needed, you can refer to the following terminal commands for installing Docker:
# If your server is in China, it is recommended to use Alibaba Cloud's installation script
curl -fsSL https://get.docker.com | bash -s docker --mirror Aliyun
# If abroad, you can use the official script directly
curl -fsSL https://get.docker.com | bash -s docker
# Check the version to verify the installation
docker -v
Backend Service Configuration
Deploy MixSpace
Tip
For this part, you can get more detailed explanations from the official documentation: https://mx-space.js.org/docs/core/docker
The Yohaku project is a front-end and back-end separated project that relies on the MixSpace backend. Therefore, we first need to deploy MixSpace. Taking the easier Docker approach as an example, first pull the docker-compose.yml for deploying the backend:
cd && mkdir -p mx-space/core && cd $_
# Pull the docker-compose.yml file
wget https://fastly.jsdelivr.net/gh/mx-space/core@master/docker-compose.yml
Fill in the following necessary information in the environment field of docker-compose.yml:
- JWT_SECRET=
- ALLOWED_ORIGINS=
For these two attribute fields, here is an explanation:
- JWT Secret: Requires a string with a length of no less than 16 characters and no more than 32 characters, used to encrypt the user's JWT. Be sure to keep your own secret safe and do not leak it to others.
- Allowed Origins: Fill in the allowed domain names. Enter the resolved domain name you configured in DNS earlier here, separated by commas. Note that the entered domain name should be complete and without prefixes. For example:
api.example.com,example.com; not like this:https://api.example.comor justapior even@.
Start Core:
docker compose up -d
Configure Reverse Proxy
Here, take the Baota panel as an example. Open the Baota panel, go to Websites, create a new website, fill the domain as api.yourdomain.com, leave the rest unchanged, and click create. At this point, try to visit your domain. If it displays "Website created successfully", it means your configuration is correct.
Click Settings on the right side of your newly created website project, find SSL on the left side of the popup, configure a certificate (e.g., Let's Encrypt free certificate), and enable HTTPS.
Then repeat the above steps to create another website with the domain yourdomain.com.
In the Settings of your backend website, under the Reverse Proxy section, click Add Reverse Proxy, fill the Target with http://127.0.0.1:2333, fill the Send Domain with $host, and click OK.
In the Settings of your frontend website, under the Reverse Proxy section, click Add Reverse Proxy, fill the Target with http://127.0.0.1:2323, fill the Send Domain with $host, and click OK.
Then go to https://api.yourdomain.com/proxy/qaqdmin to configure the backend server.
Troubleshooting
If you encounter various unexpected issues, I recommend asking an AI Agent.
New era, new atmosphere. We live in an era of booming artificial intelligence. So when you encounter problems, please first ask various AI assistant programs; they will help you solve most of your questions.
I will only list one issue I encountered here. I had previously configured Cloudreve on the server, so there was already a container named redis in Docker. In this case, I just needed to rename the relevant container in docker-compose.yml to a different name and deploy it.
Updating MixSpace
When the major version number is the same (e.g., 11.0.6 -> 11.6.1 or 11.0.6 -> 11.0.8, as long as the number before the first decimal point does not change, it is considered the same major version), updating MixSpace is very simple:
- Enter the MixSpace Core deployment directory;
- Directly
pullto pull the new version; - Bring the new version online.
cd ./mx-space/core
docker compose pull app
docker compose up -d app
After seeing the Started message, open your backend page and perform an update check:
- The article list displays normally;
- The related comments and content within the article display normally;
- Backend login works normally;
- Write an article, delete it, and test whether the article can be published and deleted normally.
Front-end Yohaku Deployment
I used the GitHub Actions provided by @Innei for pre-build deployment.
Tip
For this part, if you have some experience, you can refer to the developer's official documentation:
Fork the Deployment Workflow Repository
First, you need to fork a copy of the deploy repository from the author's repository to your GitHub account.
Note
"Fork" on GitHub essentially means "legally copying homework". The author has written a template repository for the "auto-deployment workflow". At this point, you need to fine-tune some parameters of this workflow based on your server and domain name needs, but you cannot directly modify his code. So you need to click the Fork button to copy his entire repository unchanged to your own GitHub account. Then this repository will be yours, and you can do whatever you want with it.
- Log in to your GitHub account.
- Open the author's workflow repository address: yohaku-deploy-action
- Move your gaze to the upper right corner of the screen, find a button called Fork (usually with a small number next to it), and click it!
- A "Create a new fork" confirmation page will pop up. You don't need to change anything, just scroll to the bottom and click the green Create fork button.
- Wait two or three seconds; after the page refreshes, you will notice that the repository name in the upper left corner has changed to
YourUsername/yohaku-deploy-action.
Get GH_PAT
Although it is a function under GitHub, GitHub Actions itself does not have permission to view the code of private repositories under your account. Therefore, you need to configure an account API key (i.e., Personal Access Token (PAT)) for GitHub Actions to access the repository.
- On any GitHub page, click your profile picture in the upper right corner, and select Settings at the bottom of the dropdown menu.
- In the long list on the left, scroll to the very bottom and click Developer settings.
- In the left menu, select Personal access tokens -> then Tokens (classic).
- In the upper right corner of the page, click Generate new token -> select Generate new token (classic). (You may be asked to enter your GitHub password at this point for identity verification).
- On the new key creation page:
- Note: Fill in anything, e.g.,
Deploy-Shiro. - Expiration: Select
No expiration(never expires) to avoid having to do this again later. - Select scopes: Find the
repoitem and check the large checkbox next to it (meaning this key can access your private repositories).
- Note: Fill in anything, e.g.,
- Scroll to the bottom and click the green Generate token.
Important
The page will display a very long string of garbled characters (starting with
ghp_). Copy it down immediately and save it to your local notepad! This password is shown only once and will never be seen again after the page is refreshed.
Configure Secrets
Next, fill in the account API key and other necessary information into the Deploy repository's configuration:
- Go back to the repository page you forked in the first step (
YourUsername/yohaku-deploy-action). - Click the Settings tab in the upper right of the repository.
- In the left menu, find and click: Secrets and variables -> Actions.
- Click the green New repository secret button.
- On the fill-in page:
- Name: Strictly fill in
GH_PAT(all uppercase, must be exactly like this). - Secret: Paste the long
ghp_key you saved in your notepad from step 2.
- Name: Strictly fill in
- Click Add secret.
Continue clicking New repository secret and add the following as well:
HOST: Fill in your server's IP (e.g.,1.1.1.1)USER: Fill inrootor another username you usePASSWORD: Fill in your server's root password (if it's not secure, you can useKEYto fill in the SSH key; choose one of the two; filling in the password is more suitable for beginners)PORT: Fill in22(if you haven't changed your SSH port, it's 22)BASE_URL: Fill inhttps://yourdomain.comNEXT_PUBLIC_API_URL: Fill inhttps://api.yourdomain.com/api/v3NEXT_PUBLIC_GATEWAY_URL: Fill inhttps://api.yourdomain.com
Note
Make sure the Baota panel and your cloud service provider's server dashboard firewall expose port
22.
Configure the .env Environment Variable File
On your server, create a new folder named shiro under /~ directory, then create a file named .env:
cd && mkdir -p shiro && cd $_ && touch .env
Fill in the following content in .env, and fill in the corresponding values in the blanks:
Tip
According to the developer's official instructions,
NEXT_PUBLIC_GATEWAY_URLshould be set to${BASE_URL}andNEXT_PUBLIC_API_URLto{BASE_URL}/api/v3.However, Next.js sometimes gets confused when parsing dynamically concatenated expressions like
${BASE_URL}. To avoid giving it a chance to error, I recommend hardcoding the full URL directly.
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 Section (Hardcoding is more reliable)
# Your website's main domain
BASE_URL=https://yourdomain.com
# Backend API address (directly write the full URL)
NEXT_PUBLIC_API_URL=https://api.yourdomain.com/api/v3
# Gateway address
NEXT_PUBLIC_GATEWAY_URL=https://api.yourdomain.com
2. Clerk Authentication (Website backend login)
This is a third-party service for login.
- Go to the Clerk website to register an account and create a new application.
- Then find these two Keys in its console and fill them in:
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=pk_test_xxxxxxxxxxx (fill in the public key you get from Clerk)
CLERK_SECRET_KEY=sk_test_xxxxxxxxxxx (fill in the private key you get from Clerk)
# The following four are login redirect routes; keep them as is, no need to modify!
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. Other Miscellaneous APIs
TMDB_API_KEY=
GH_TOKEN=ghp_xxxxxxxxxxxxxxxxx
TMDB_API_KEY: TMDB is a movie database. Yohaku blog supports displaying movie cards. If you don't want to set it up for now, you can leave it blank (the movies page might have no data, but it won't affect the overall site operation). If you want to set it up, go to themoviedb.org to apply for an API and fill it in.GH_TOKEN: Token for dynamic GitHub display. You can directly fill in the "master key" starting withghp_that you obtained in the previous step.
GitHub Actions
Next, go to the Actions page of the repository and let GitHub Actions pre-build the project.
- Click the Actions tab at the top.
- If you see a prompt saying "I understand my workflows, go ahead and enable them", click the green button to agree and enable them.
- In the left menu, click the workflow name Build and Deploy.
- On the right, find a button that says Run workflow, click it, and then click the green Run workflow that appears.
If the Run workflow button does not exist, go into the .github/workflows/ folder, open deploy.yml, click the edit (pen) button in the upper right corner, and then click Commit changes.
Note
When you click Save (Commit), the system will think you have updated the code (triggering a push), and then it will automatically start Build and Deploy.
Troubleshooting
If there is an error when using GitHub Action to build Yohaku, and the log shows:
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.
You can try making the following modifications to deploy.yml:
Caution
This method is my personal modification based on error analysis combined with AI Agent suggestions, and there may be some undiscovered bugs. If you encounter a similar issue, you can try contacting the author or submitting an issue on GitHub.
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 }}
Configure in MixSpace
Note
Official documentation related to this part:
Enter the Mix Space backend, go to the "Configuration and Cloud Functions" page, click the add button in the upper right corner, and in the edit page, fill in the following settings:
- Name:
shiro - Reference:
theme - Data Type:
JSON - Data (using the official sample data as a template):
{
"footer": {
"otherInfo": {
"date": "2020-{{now}}",
"icp": {
"text": "萌 ICP 备 20236136 号",
"link": "https://icp.gov.moe/?keyword=20236136"
}
},
"linkSections": [
{
"name": "About",
"links": [
{
"name": "About this site",
"href": "/about-site"
},
{
"name": "About me",
"href": "/about"
},
{
"name": "About this project",
"href": "https://github.com/innei/Shiro",
"external": true
}
]
},
{
"name": "More",
"links": [
{
"name": "Timeline",
"href": "/timeline"
},
{
"name": "Friends",
"href": "/friends"
},
{
"name": "Status",
"href": "https://status.innei.in/status/main",
"external": true
}
]
},
{
"name": "Contact",
"links": [
{
"name": "Write a message",
"href": "/message"
},
{
"name": "Send email",
"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
}
}
}
}
Click the button to save the configuration.
Conclusion
The process of deploying Yohaku this time was essentially a hands-on exercise in modern CI/CD workflows. From correcting environment issues with the Baota panel to deeply debugging GitHub Actions, each resolved Error was a restructuring of my own knowledge system.
Successful deployment is only the first step; the real fun lies in subsequent creation or customization. If you encounter new "mysterious problems" while referencing this article, feel free to leave a comment for discussion, or directly consult the author Innei. I hope this article can provide key help when you are building your personal space.
