Preface#
The previous blog used Typecho, and in 2024 I stumbled upon Mix-Space, a front-end and back-end separated personal space, which I really liked, so I migrated the blog. It has now been successfully deployed, and I hope it can help others who also want to deploy. || It's also a reminder for myself qwq ||
This article's tutorial is: the back-end is deployed using Docker, while the front-end is built using Github Action to construct Shiro and then pushed to the server (of course, you can also choose the more convenient Docker, but the closed-source version is not provided).
Mix-Space and Shiro Theme Related Links#
Mix Space is a small personal space site program. Unlike traditional blog programs, it adopts a front-end and back-end separation design, suitable for those who enjoy writing in different styles or types.
Mix Space - An Alternative Personal Space - Mix Space Documentation
Shiro is a personal site front-end made by Innei for Mix Space.
A minimalist personal website, embodying the purity of paper and freshness of snow.
Shiro - A brand new style, setting sail again - 静かな森
1 Panel Installation#
Refer to the official website's Online Installation - 1Panel Documentation steps, I am using Ubuntu, so just execute the following command
curl -sSL https://resource.fit2cloud.com/1panel/package/quick_start.sh -o quick_start.sh && sudo bash quick_start.sh
Follow the prompts step by step, during which you will be asked to enter some account information, passwords, and the default port of 1 Panel, you can just press enter to use the defaults, which can all be changed in the panel.
Finally, a log will be output, which contains your panel address, username, and password; you can log in to the panel using the address and account inside.
Back-end Core Deployment#
Check and Install Docker#
I deployed the back-end using Docker, which is also a recommended method.
Since the 1 Panel panel will install Docker by default, there is no need to check if it is already installed.
Pull and Modify Configuration Files#
You can use the command line to pull files or use the 1 panel panel to pull them, and you can modify the storage path as needed.
# Return to the root directory and create the mx-space/core folder, then switch to the core folder
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
Modify some contents in docker-compose.yml
services:
app:
container_name: mx-server
image: innei/mx-server:latest
environment:
- TZ=Asia/Shanghai
- NODE_ENV=production
- DB_HOST=mongo
- REDIS_HOST=redis
# Fill in your blog's domain name, separate multiple with commas, you can also add your local address here to allow them to access themselves
- ALLOWED_ORIGINS=blog.lolita.best,localhost:*,127.0.0.1:*
# Fill in your generated JWT secret, 16≤ secret length ≤32 characters (be sure to keep your secret safe and do not disclose it)
- JWT_SECRET=xxxxx
# Whether to enable encryption-related configurations, the default here is false and empty, if encryption is needed, refer to the official configuration documentation
- ENCRYPT_ENABLE=false
- ENCRYPT_KEY=
volumes:
- ./data/mx-space:/root/.mx-space
ports:
#-'2333:2333' Modified the docker port mapping, not opening the port
- '127.0.0.1:2333:2333'
depends_on:
- mongo
- redis
networks:
- mx-space
restart: unless-stopped
healthcheck:
test: ['CMD', 'curl', '-f', 'http://127.0.0.1:2333/api/v2/ping']
interval: 1m30s
timeout: 30s
retries: 5
start_period: 30s
mongo:
container_name: mongo
image: mongo
volumes:
- ./data/db:/data/db
networks:
- mx-space
restart: unless-stopped
redis:
image: redis:alpine
container_name: redis
volumes:
- ./data/redis:/data
healthcheck:
test: ['CMD-SHELL', 'redis-cli ping | grep PONG']
start_period: 20s
interval: 30s
retries: 5
timeout: 3s
networks:
- mx-space
restart: unless-stopped
networks:
mx-space:
driver: bridge
Start Core#
After configuration is complete, directly use the following command in the current directory to start Core
# The same command can be used later if you need to update the back-end or modify the yaml configuration to update the container
docker compose pull && docker compose up -d
After successful startup, you can see the running status of the mx-server, redis, and mongo containers in the 1 Panel.
At this point, you have successfully deployed the back end
Reverse Proxy Settings#
After the back-end is deployed, you also need to set up a reverse proxy to access it, and here I will also set up the SSL certificate
Apply for Website Certificate#
You can directly apply for a certificate in the website/certificate section of the 1 Panel panel.
We need to first create an Acme account, and after filling in the email, the rest can be left as default.
Next is the verification method when applying for the certificate; I used the DNS account method for verification, which requires creating a DNS account. The panel supports many DNS service providers, just choose your own; I used CloudFlare.
The API token for CloudFlare can be applied in "Manage Account/Account API Tokens", and you can directly use the template for "Edit Zone DNS".
After completing the above steps, the preparation work is done; click to apply for the certificate and fill in your website domain name.
Create Website and Set Up Reverse Proxy#
The first time you use 1 Panel, it will prompt you to install OpenResty from the app store; just install it as prompted.
Choose to create a static website, fill in your domain name, and leave the rest as default.
Click on the web configuration, switch to HTTPS, and select the certificate you applied for earlier; the SSL is configured.
Next, go to the configuration file, copy the content below and add it at the end, save and reload (remember to modify the commented areas to your own).
Here, a single domain method is used; if you need a dual domain for front and back ends, please refer to the official configuration documentation.
# WebSocket address
location /socket.io {
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "Upgrade";
proxy_buffering off;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_pass http://127.0.0.1:2333/socket.io;
}
# API address
location /api/v2 {
proxy_pass http://127.0.0.1:2333/api/v2;
}
# Simple read render address
location /render {
proxy_pass http://127.0.0.1:2333/render;
}
# Shiro address
location / {
proxy_pass http://127.0.0.1:2323;
}
# Background address
location /proxy {
proxy_pass http://127.0.0.1:2333/proxy;
}
location /qaqdmin { # If you need to modify your background address, you can change it here
proxy_pass http://127.0.0.1:2333/proxy/qaqdmin;
}
# RSS address
location ~* \/(feed|sitemap|atom.xml) {
proxy_pass http://127.0.0.1:2333/$1;
}
After setting up, you can now access the background management address via https://your-domain/qaqdmin
, and fill in the corresponding content as instructed.
Front-end Deployment#
I used the closed-source version of Shiro and automatically deployed it using Github Action; the open-source version should also be able to follow the steps below.
Fork the Shiroi-deploy-action Repository on Github and Modify the Workflows File#
Repository address: GitHub - innei-dev/shiroi-deploy-action
After forking, modify the deploy.yml
file in the workflows folder (the parts that need to be modified are marked with Chinese comments).
name: Build and Deploy
on:
workflow_dispatch: # Added manual execution of the workflow
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:
PNPM_VERSION: 9.x.x
HASH_FILE: build_hash
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/shiroi # Fill in the repository you need to access, such as the open-source version innei/shiro
token: ${{ secrets.GH_PAT }} # `GH_PAT` is a secret that contains your PAT
fetch-depth: 0
lfs: true
- 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: [20.x]
outputs:
sha_short: ${{ steps.store.outputs.sha_short }}
branch: ${{ steps.store.outputs.branch }}
steps:
- uses: actions/checkout@v4
with:
repository: innei-dev/shiroi # Fill in the repository you need to access, such as the open-source version innei/shiro
token: ${{ secrets.GH_PAT }} # `GH_PAT` is a secret that contains your PAT
fetch-depth: 0
lfs: true
- name: Checkout LFS objects
run: git lfs checkout
- uses: pnpm/action-setup@v2
with:
version: ${{ env.PNPM_VERSION }}
- 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
run: |
sh ./ci-release-build.sh
# - 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: 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/shiro'
- 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_stop: true Removed this line command as it is no longer in use; it will prompt but does not affect, you can leave it unchanged
script: |
set -e
export NVM_DIR=~/.nvm # Define the installation directory of .nvm, otherwise, the terminal will not find the command even though it is installed
source ~/.nvm/nvm.sh # Recognize nvm command, otherwise it may report command not found
source $HOME/.bashrc
basedir=$HOME/mx-space/shiro # Fill in the path you want, since my back-end files are in mx-space, I want my shiro to also be in the mx-space folder for easy management
workdir=$basedir/${{ github.run_number }}
mkdir -p $workdir
mkdir -p $basedir/.cache
mv /tmp/shiro/release.zip $workdir/release.zip
rm -r /tmp/shiro
cd $workdir
unzip -qq -o $workdir/release.zip
rm -rf $workdir/standalone/.env
ln -s $HOME/mx-space/shiro/.env $workdir/standalone/.env # Your .env file path, I store it in the mx-space/shiro folder for easy management
export NEXT_SHARP_PATH=$(npm root -g)/sharp
# copy workdir ecosystem.config.js to basedir if not exists
if [ ! -f $basedir/ecosystem.config.js ]; then
cp $workdir/standalone/ecosystem.config.js $basedir/ecosystem.config.js
fi
# https://github.com/Unitech/pm2/issues/3054
# symlink workdir node entry file to basedir
ln -sf $workdir/standalone/server.js $basedir/server.js
mkdir -p $workdir/standalone/.next
rm -rf $workdir/standalone/.next/cache
ln -sf $basedir/.cache $workdir/standalone/.next/cache
cd $basedir
pm2 reload ecosystem.config.js --update-env
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 fail 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 }}
Set Up Secrets for the Workflow#
HOST
Server addressUSER
Server usernamePASSWORD
Server passwordPORT
Server SSH portKEY
Server SSH Key (optional, either password or key)GH_PAT
Github Token that can access the previous repository
Configure the .env File#
Return to 1 Panel, create a .env
file in the specified location in your workflow, and copy the following content, modifying it to your own content.
As above, it is root/mx-space/shiro
# Back-end API address
NEXT_PUBLIC_API_URL=https://blog.lolita.best/api/v2
# Back-end gateway address
NEXT_PUBLIC_GATEWAY_URL=https://blog.lolita.best
# TMDB information retrieval
TMDB_API_KEY=Fill in your TMDB-API
# GitHub token, used to obtain front-end version hash
GH_TOKEN=Fill in your own token
Install Necessary Environments on the Server#
To deploy the Shiro theme, you need to install Node.js
, npm
, pnpm
, pm2
, sharp
.
You can enter the following commands in the terminal of 1 Panel to install them.
Now, the Node.js official website also has installation methods; just follow the prompts.
# Download and install nvm:
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.1/install.sh | bash
# In lieu of restarting the shell
\. "$HOME/. Nvm/nvm. Sh"
# Download and install Node. Js:
Nvm install 23
# Verify the Node. Js version:
Node -v # Should print "v 23.8.0".
Nvm current # Should print "v 23.8.0".
# Download and install pnpm:
Corepack enable pnpm
# Verify pnpm version:
Pnpm -v
# The following are additional supplementary contents
npm i -g pm2 # Install pm2
npm i -g sharp # Install sharp
Since the workflow uses unzip for decompression, you need to confirm whether unzip is installed on the server; otherwise, it will report an error.
# Update packages and install unzip
sudo apt update && sudo apt install -y unzip
# Use the following command to verify if it is installed
unzip -v
Start the Workflow#
Manually run the workflow in Github and wait for the workflow to complete without errors to succeed.
Configure Shiro Theme Cloud Functions in the Management Background#
Warning
Reminder
The configuration update of cloud functions does not refresh immediately; please be patient.
The Shiro theme also needs to work with cloud functions. Enter the management background / additional features / configuration and cloud functions, and first import the relevant files.
Then click the add button in the upper right corner, and in the editing page, fill in the following settings:
- Name: shiro
- Reference: theme
- Data Type: JSON
- Data: Copy the following example on the right and change it to your own information.
Data content reference: Configuration - Mix Space Documentation
{
"footer": {
"otherInfo": {
"date": "2019-{{now}}",
"icp": {
"text": "萌ICP备20248012号",
"link": "https://icp.gov.moe/?keyword=20248012"
}
},
"linkSections": [
{
"name": "About",
"links": [
{
"name": "About this site",
"href": "/about-site"
},
{
"name": "About me",
"href": "/about",
"external": true
}
]
},
{
"name": "More",
"links": [
{
"name": "Timeline",
"href": "/timeline"
},
{
"name": "Friend Links",
"href": "/friends",
"external": true
}
]
},
{
"name": "Contact",
"links": [
{
"name": "Leave a message",
"href": "/message",
"external": true
},
{
"name": "Send an email",
"href": "mailto:[email protected]",
"external": true
},
{
"name": "GitHub",
"href": "https://github.com/Sumikanya",
"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": [
"https://github.com/Innei/static/blob/master/images/F0q8mwwaIAEtird.jpeg?raw=true",
"https://github.com/Innei/static/blob/master/images/IMG_2111.jpeg.webp.jpg?raw=true"
],
"custom": {
"css": [],
"styles": [],
"js": [],
"scripts": []
},
"site": {
"favicon": "https://cn.cravatar.com/avatar/08d99bea604c306b51ebe162e93412f1?s=36",
"faviconDark": "https://cn.cravatar.com/avatar/08d99bea604c306b51ebe162e93412f1?s=36"
},
"hero": {
"title": {
"template": [
{
"type": "h1",
"text": "Hi, I'm ",
"class": "font-light text-4xl"
},
{
"type": "h1",
"text": "Hoshino Junka",
"class": "font-medium mx-2 text-4xl"
},
{
"type": "h1",
"text": "💕。",
"class": "font-light text-4xl"
},
{
"type": "br"
},
{
"type": "h1",
"text": "A Lo girl who loves technology and digital ",
"class": "font-light text-4xl"
},
{
"type": "code",
"text": "🦋<INFP>🦋",
"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": "I hope to leave my mark in this world",
"Hitokoto": {
"random": true,
"custom": "Custom Hitokoto"
}
},
"module": {
"activity": {
"enable": true,
"endpoint": "/fn/ps/update"
},
"donate": {
"enable": false,
"link": "https://afdian.net/@Innei",
"qrcode": [
"https://cdn.jsdelivr.net/gh/Innei/img-bed@master/20191211132347.png",
"https://cdn.innei.ren/bed/2023/0424213144.png"
]
},
"bilibili": {
"liveId": 19781
}
}
}
}
Set Up PM2
Service to Restore Processes After Restart#
pm2 startup
pm2 save
How to manually start Shiro? You can enter the front-end path of shiro and run the following code.
By default, the github workflow configuration has already started it.
pm2 start ecosystem.config.js
You can use the following command to view the running processes.
pm2 list
Deployment Complete#
After both the front-end and back-end are successfully deployed, you can directly access your webpage to see the current effect.
Reference Links#
Many thanks to the official and other related tutorials for building
Mix-Space Deploying the Latest Front-end Shiro - 华岁云小屋
Trying Github Action Build and Deploy Shiroi - 华岁云小屋
Mix Space - An Alternative Personal Space - Mix Space Documentation
mx-space + Shiro: A blog as pure as paper • Arthals' ink
The General Process and Supplement for Deploying Shiroi - Ethan
Migrating Data from WordPress to Mix Space - FoskyM's Blog
This article is synchronized to xLog by Mix Space
The original link is https://blog.lolita.best/posts/blog/MxspaceDeployShiro