Mixspace+shiroi 部署踩坑实录
壹 · 缘起
来自于一次友链交换 Shiroi的主题真的让人眼前一亮
一个极简主义的个人网站主题,如纸的纯净,似雪的清新。
外加原有的纯静态播客升级改造难度大 遂跑路换了 Mixspace+Shiroi
考察下来直接支持作者大佬 innei 冲了 白い 赞助版 殊不知掉进了大坑 研究了一天
对于不太了解NextJS/React框架的同学(比如我)(菜的抠脚) 因为项目文档并不是很详细 很多东西都得自己探索
这里是我的一些踩坑经历和心路历程 私以为水平达不到文档的地步 要是能帮到你 那我是很开心的 (≧◡≦)
贰 · 基础部署
后端部署
最简单的方式就是 Docker
下载docker-compose.yml
wget https://fastly.jsdelivr.net/gh/mx-space/core@master/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
- ALLOWED_ORIGINS=localhost
- JWT_SECRET=
- ALLOWED_ORIGINS=
- ENCRYPT_ENABLE=false
volumes:
- ./data/mx-space:/root/.mx-space
ports:
- '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
密钥JWT_SECRET
:需要填写长度不小于 16 个字符,不大于 32 个字符的字符串,用于加密用户的 JWT,务必保存好自己的密钥,不要泄露给他人。被允许的域名ALLOWED_ORIGINS
:需要填写被允许的域名,通常是前端的域名,如果允许多个域名访问,用英文逗号,分隔。
然后直接docker compose up -d
后端就快速部署了 建议进行反代 单独分配一个域名 后期使用
访问 https://example.com/proxy/qaqdmin 进行初始化
后端主题 API设置
进入 Mix Space 后台,进入「配置与云函数」页面,点击右上角的新增按钮,在编辑页面中,填入以下设置:
- 名称:
shiro
- 引用:
theme
- 数据类型:
JSON
- 数据:
{
"footer": {
"otherInfo": {
"date": "2017-{{now}}",
"icp": {
"text": "晋公网安备号 | 晋ICP备",
"link": "https://beian.miit.gov.cn"
}
},
"linkSections": [
{
"name": "😊关于",
"links": [
{
"name": "关于我",
"href": "/about"
}
]
},
{
"name": "🧐更多",
"links": [
{
"name": "时间线",
"href": "/timeline"
},
{
"name": "友链",
"href": "/friends"
}
]
},
{
"name": "🤗联系",
"links": [
{
"name": "写留言",
"href": "/message"
},
{
"name": "发邮件",
"href": "mailto:",
"external": true
},
{
"name": "GitHub",
"href": "https://github.com/",
"external": true
}
]
},
{
"name": "><萌备案",
"links": [
{
"name": "萌ICP备",
"href": "https://icp.gov.moe/"
}
]
}
]
},
"config": {
"color": {
"light": [
"#33A6B8",
"#FF6666",
"#26A69A",
"#fb7287",
"#69a6cc",
"#F11A7B",
"#78C1F3",
"#FF6666",
"#7ACDF6"
],
"dark": [
"#F596AA",
"#A0A7D4",
"#ff7b7b",
"#99D8CF",
"#838BC6",
"#FFE5AD",
"#9BE8D8",
"#A1CCD1",
"#EAAEBA"
]
},
"custom": {
"css": [
],
"styles": [
],
"js": [
],
"scripts": [
]
},
"site": {
"favicon": ".svg",
"faviconDark": ".svg"
},
"hero": {
"title": {
"template": [
{
"type": "h1",
"text": "Hi, I'm ",
"class": "font-light text-4xl"
},
{
"type": "h1",
"text": "Guoweiyi",
"class": "font-medium mx-2 text-4xl"
},
{
"type": "h1",
"text": "🤩。",
"class": "font-light text-4xl"
},
{
"type": "br"
},
{
"type": "h1",
"text": "不知何时春日悄来临,",
"class": "font-light text-4xl"
},
{
"type": "br"
},
{
"type": "h1",
"text": "不知何日春花已落尽。",
"class": "font-light text-4xl"
},
{
"type": "code",
"text": "<Student & 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": "文稿是技术类文章/手记是生活有感而发"
},
"module": {
"activity": {
"enable": true,
"endpoint": "fn/shiro/status"
},
"donate": {
"enable": true,
"qrcode": [
"https://www.gwy.fun/%E5%9B%BEapi/131751243999_.pic.jpg"
]
},
"bilibili": {
"liveId": 22157691
},
"signature": {
"svg": ""
}
}
}
}
前端部署
如果你不想折腾可以使用 Docker/ Vercel 部署一键解决 但是 Docker 赞助版需要自己构建镜像
如果你使用赞助版 那么我们开始
折腾探索方法一 GitHub Action 构建
是作者推荐的 利用 GitHub Action 去构建 Shiroi 然后部署到远程服务器 参考 https://github.com/innei-dev/shiroi-deploy-action
需要注意的是提示.env 文件有很多配置是不需要的 因为作者放弃了 Clerk 具体参考这个
NEXT_PUBLIC_API_URL=https://innei.ren/api/v2
NEXT_PUBLIC_GATEWAY_URL=https://api.innei.ren
TMDB_API_KEY=
GH_TOKEN=
- Tips
- 一定 一定 要提前在服务器装好 Node.js, npm, pnpm, pm2, sharp 要不会很卡 Action 构建处理起来很麻烦
- 你的云服务器配置最好大于2核2G 实测一个 2 核 2 G 云服务器 不能同时承担后端和前端 4G 云服务器是比较合理的 可以参考这位佬的blog和官方文档进行部署 此处不多赘述
方法二 本地构建 Standalone 上传
我更推荐这种方式完成前端部署
主要优点 可进行二次开发 例如 更改适合自己的提示语
确保你的 node 环境为 22 以上
Step1 克隆代码 安装 构建
更改.env 配置后端域名同上
git clone https://github.com/innei-dev/Shiroi
cd Shiroi
pnpm i
pnpm build
Step2 本地运行测试
pnpm prod:pm2
Step3 上传服务器
另:目录结构说明
./.next/standalone
包含:
server
文件夹,包含服务端代码node_modules
,只包含必要依赖- 入口文件
server.js
(Next.js 服务端启动入口) - 以及其他运行时文件
手动把 .next/static
放到 standalone/.next/static
下,即:
├── standalone/
│ ├── .next/
│ │ └── static/ ← 这里
│ ├── server.js
│ └── node_modules/
然后把整个 .next/standalone
目录压缩上传到服务器即可
服务器同上需装好 Node.js, npm, pnpm, pm2, sharp
pnpm i
pm2 start server.js --name shiroi
可以使用pm2 list
pm2 stop
pm2 delete
管理项目
进行反向代理 便大功告成了喵><
贰 · 踩坑记录
1.CDN 问题
有同学说 可以把我的静态文件 /static 放到阿里云 OSS+CDN 不可以很大程度提升访问速度吗
答案是 可以 但会付出一定代价
部署方法
作者已经在next.config.js 支持了 静态文件
assetPrefix: isProd ? env.ASSETPREFIX || undefined : undefined,
直接在.env 文件加上这一行就可以
ASSETPREFIX=https://youcdn.test.com/
然后重新构建 把static上传对象存储 便可本地预览测试
上传服务器你就会发现出问题了
SecurityError: Failed to construct 'SharedWorker': Script at 'https://www.gwy.fun/_next/static/chunks/shiro-ws-worker.dd693989cebaf294.js' cannot be accessed from origin 'https://gwy.fun'
一个典型的 跨域(CORS)限制问题,特别出现在使用 SharedWorker
时 浏览器安全机制 不允许跨源加载 SharedWorker 脚本。
这是 两个不同的 origin(因为子域不同),会被浏览器认为是跨源,导致SharedWorker
脚本无法跨 origin 加载(哪怕你设置了 CORS header,依然不允许)
解决方法 不通过 CDN 加载 Worker 脚本(CDN 其余资源照用)
你可以做 CDN 部分代理:
- 页面和静态资源(CSS/JS)用 CDN;
- 但
/shiro-ws-worker.xxxxxxxxxx.js'
这个路径不要从 CDN 加载,而是保留同源。
实现方式一:将 Worker 路由反向代理到源站
nginx
# www.gwy.fun 上的配置
location /_next/static/chunks/shiro-ws-worker {
proxy_pass http://localhost:3000; # 或源站 IP
proxy_set_header Host $host;
}
确保这个路径始终从源站拉,而不是 CDN 缓存节点。
实现方式二:Worker 独立部署在原始域名
const sameOriginURL = location.origin + '/shiro-ws-worker.xxxxxxxx.js'
const worker = new SharedWorker(sameOriginURL, { name: 'shiro-ws-worker' })
然后将此 Worker 文件不上传到 CDN,始终由源站提供。
这个方案充满了妥协和麻烦 故我最后弃用这种方式 直接由服务器提供静态文件
2.AI问题
AI总结功能 国内无法使用ChatGPT 你的服务器可能无法连接
可使用国内阿里云百炼或者腾讯混元的api使用 有很大的免费token额度
申请到token后可以本地进行测试 例如
curl https://dashscope.aliyuncs.com/compatible-mode/v1/chat/completions \
-H "Content-Type: application/json" \
-H "Authorization: Bearer sk-xxxxxxxxxxxx" \
-d '{
"model": "deepseek-v3",
"messages": [
{
"role": "user",
"content": "你好"
}
],
"enable_enhancement": true
}'
无误后填入后台
OpenAI Endpoint https://dashscope.aliyuncs.com/compatible-mode/v1 (不带chat/completions)
OpenAI 默认模型 即为你选择的模型 (需要注意的是要选择可以流式输出的模型如qwen-plus-latest)
其他坑
这些是我还没有研究清楚的 希望有大佬支招
mac 版我的动态推送 ProcessReporter如何推送正在听的歌曲
作者并未详细说明 自我探索之后发现需要创建 Slack 项目 具体如下
GitHub 上有开源工具
apple‑music‑to‑slack
,采用 Rust 编写:- 读取 Mac 上 Music 当前播放的歌曲,并将其自动更新为 Slack 状态
- 安装步骤:
- 在 api.slack.com 创建自定义 App,授权
users.profile:write
,获取 OAuth Token。 - 编译并运行该工具,将环境变量
SLACK_SECRET_TOKEN
设置为上一步获取的 Token。
- 在 api.slack.com 创建自定义 App,授权
虽然使用了该工具 但仍无法正常推送到 Slack 等待研究
我的状态填写问题 直接请求https://api.test.com/api/v2/fn/shiro/ps 可以获取到我的当前状态 但填写至主题文件 网页请求时会报 500 错误
叁 · 结语
整体还是很喜欢佬写的这个主题页面 故坚持研究下来了 本文在解决问题后也会长期更新下去
欢迎大佬们批评指正 文笔稚嫩 废话很多 敬请原谅