使用docker-compose快速部署mix-space + shiro
这篇文章简单记录一下如何使用docker-compose搭建一个Innei大佬那样的博客,前后端都是由Innei开源的mix-space后端+Shiro主题。
准备工作
这篇文章写于2024年10月26日,如果时间过了很久,建议先看一下官方的文档:https://mx-space.js.org/docs/docker。
这个博客程序由mix-space(或者叫mx-space?)和Shiro两部分组成,其中mix-space是后端部分,提供所有的博客功能,比如存储服务,比如文章内容查询,还有缓存...以及云函数(这个确实是我没有想到的)。mix-space是后端,同时也是管理面板的所在。Shiro是一个独立的前端服务器,是访客实际访问到的部分。
在官方文档中分别提供了部署后端和前端的方法,因为本文着重讲mix-sapce与Shiro搭配的使用方式,所以直接合并两个部署方式。
像刚刚说的,后端是管理面板,前端才是访客访问的部分。并且,后端也是各种实际使用的API的实际访问地址,因此,现在有两个前端服务需要使用。官网中提到可以使用单域名模式也可以使用多域名模式,由于实际测试时单域名模式有诸多需要考虑的点,以及Innei大佬自己的博客也是多域名模式,所以这里直接按照多域名方式部署,暂且称呼博客前端为example.blog,博客后端为mix.example.blog。
那么现在就已经确定了所有要使用的域名了。还需要的内容是:
需要确定一个JWT_SECRET值
这个值可以非常简单的生成,无论是Windows(11+)还是linux(的绝大部分发行版),都可以通过:
openssl rand -hex 16
这个命令获得一串随机值,这个就可以用了。
如果需要用到Github内容查询的话,还需要一个GH_PAT,就是Classic模式的Github个人密钥,通过访问Github的个人密钥生成页面可以快速创建一个。
开始部署
首先要准备一个带有Docker环境的机器,你用BT面版还是1panel还是完全不用面版都可以。找到一个你打算存放博客信息的地方,然后,创建一个.env
文件:
NEXT_PUBLIC_API_URL=https://mix.example.blog/api/v2
NEXT_PUBLIC_GATEWAY_URL=https://mix.example.blog
GH_TOKEN=
其中,这里的前两个参数要写的是后端API的地址。后端的API地址是/api/v2
,网关地址是直接后端的地址, 这个网关就是WebSocket地址,填写不正确是无法连接的,如果使用前端域名的话,这里可以确实可以用,但是要在前端中做对应的转发。
然后,在最后一行的等号后面粘贴之前获得的Github的Token。
创建一个docker-compose.yml
文件:
services:
shiro:
container_name: shiro
image: innei/shiro:latest
volumes:
- ./.env:/app/.env
restart: always
environment:
- NEXT_SHARP_PATH=/usr/local/lib/node_modules/sharp
ports:
- 2323:2323
app:
container_name: mx-server
image: innei/mx-server:latest
environment:
- TZ=Asia/Shanghai
- NODE_ENV=production
- DB_HOST=mongo
- REDIS_HOST=redis
- JWT_SECRET=这里写你的secret
- ALLOWED_ORIGINS=example.blog,mix.example.blog
- ENCRYPT_ENABLE=
- ENCRYPT_KEY=
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
ports:
- '127.0.0.1:27017:27017'
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
这里,Shiro放在2323端口,mix-server放在2333端口。注意修改你的JWT_SECRET和你的ALLOWED_ORIGINS,前者是之前准备的随机字符串,后者是你打算在哪些域名中使用,域名以逗号分隔。
注意,.env和docker-compose.yml必须在相同位置。
完成后,拉取镜像:
docker compose pull
这里是拉取镜像。有条件的话,建议把每个镜像的版本号从latest改为实际使用的版本号,后续更新会更容易一些。
启动容器:
docker compose up -d
映射域名
使用Nginx或者Caddy等工具的话大体思路都是一样的,分别映射到两个域名在官网的这个地方有写好的Nginx配置文件。这里我用Nginx Proxy Manager偷了个懒,直接创建两个域名的映射了。注意虽然后端没什么要改的,但是前端设置路径映射的时候一定要注意,如果设置完哪些出现问题,请在子路径配置里面点一下右边齿轮,手动添加一下配置,主要是添加带有/
末尾的配置,例如:
location /proxy {
proxy_pass http://127.0.0.1:2333/proxy;
}
location /proxy/ {
proxy_pass http://127.0.0.1:2333/proxy/;
}
另外,为了使得Shiro的轻管理可以正确跳转到后端管理页面,这里推荐修改一下,/qaqdmin
不在转发后端,而是重定向跳转过去:
location /qaqdmin {
#proxy_pass http://127.0.0.1:2333/proxy/qaqdmin;
return 302 https://mix.example.blog/proxy/qaqdmin$is_args$args;
}
这样大体就设置好了,如果你有BT或者1panel的话还可以申请一个Let's Encrypt免费证书。
前端还需要一步...
Shiro主题的一部分额外选项通过后端的云函数返回特定格式的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:i@innei.ren",
"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": [
"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": "/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": [
"https://cdn.jsdelivr.net/gh/Innei/img-bed@master/20191211132347.png",
"https://cdn.innei.ren/bed/2023/0424213144.png"
]
},
"bilibili": {
"liveId": 1434499
}
}
}
}
可以自己进行按需修改。JSON格式较为严格,请不要添加多余的符号。完成后,在后台的附加功能>配置与云函数中选择右上角的加号图标,名称设置为shiro
,引用设置为theme
,然后把JSON粘贴的在右侧,点击右上角对勾保存。如果前端没有获得更新,就在后端的仪表盘清空一下缓存。
从Wordpress迁移?
如果之前使用的是Wordpress,那么可以将你的文章、评论、浏览量、标签、分类、页面都转移过来,但是注意Wordpress的自定义菜单和自定义链接无法转移。具体可以参考 wordpress-to-mxspace 这个项目,需要python环境。需要注意的是,原博客的草稿会导致导入数据出现问题,建议提前删除草稿,另外原博客的一些短码、隐藏等功能是无法迁移的,文章slug会保留但是不一定按照Wordpress原本的格式进行,这些需要特别注意。
仍有一些问题...
在一段时间的使用后其实我还发现了一些问题:
- 后端站点标题是固定的...虽然问题不大
- 单域名模式进入后端会遇到js访问不到的情况...不知道原因
- 错误处理有些缺乏,比如刚刚迁移Wordpress时如果有草稿就会导致一些字段(比如摘要)变成null值,而前端的posts页面会直接崩掉
- 后端的编辑器还是有点简单了,这篇文章实际上是在Typora里面码的...
不过这些其实都是问题不大的,因为前后端都是开源的,可以很简单的修改。可以fork一下项目,然后自己开一个分支修改,然后借助阿里云个人容器镜像服务做一个免费的自动化的构建,然后最后再替换上面的docker-compose文件的image地址就可以了,还是不困难的。
最后
这个主题真的很得我心,而且后端的功能虽然不像完整的CMS框架那样功能丰富插件丰富,但是也内置了巨量的功能,缺少的功能可以自行拓展,而且我也看到代码里还有一些功能没有做到面板里面,相信修改一下可能还有更多隐藏功能可以挖掘。我一直再找一个类似这样的博客程序,现在终于找到了。