1Panel+Vercel部署前后端分离博客Mix Space
准备
- 云服务器(笔者为腾讯云轻量应用服务器2核内存2GB,重装系统为 Debian 12)
- 后端和前端两个域名,后端域名必须 ICP 备案否则无法访问
- github 账号和 vercel 账号
docker容器构建
用本地终端 ssh 服务器,如果重装过操作系统,需要在本地终端先清除服务器的 ssh 指纹
ssh-keygen -R 服务器公网IP
ssh root@服务器公网IP
使用docker部署,构建docker环境并拉取mix space构建文件
apt update && apt upgrade -y # 更新包管理器
curl -fsSL https://get.docker.com | bash -s docker --mirror Aliyun # 国内镜像源安装docker
docker -v
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 字段
- JWT_SECRET=... # JWT密钥
- ALLOWED_ORIGINS=akatsuki033896.asia # 域名
- ENCRYPT_ENABLE=false # 不加密
接下来配置docker的国内镜像源否则无法pull,建立并编辑 /etc/docker/daemon.json
mkdir -p /etc/docker
vim /etc/docker/daemon.json
docker info | grep cd -A 5 "Registry" # 应返回镜像列表
{
"registry-mirrors": [
"https://mirror.ccs.tencentyun.com",
"https://docker.mirrors.ustc.edu.cn",
"https://hub-mirror.c.163.com"
]
}
启动docker并pull
systemctl start docker
docker compose up -d # pull
docker compose ps
1Panel 配置网页反向代理
经查阅发现宝塔面板部署反代存在问题,使用1Panel部署配置反向代理,不建议手写反代
在根目录下安装1Panel
bash -c "$(curl -sSL https://resource.fit2cloud.com/1panel/package/v2/quick_start.sh)"
根据终端提示操作,记住以下配置
1Panel在27978端口,外部地址即管理页面为 http://服务器公网IP:27978
请使用您的浏览器访问面板:
[1Panel 2026-01-05 02:57:04 install Log]: 外部地址:
[1Panel 2026-01-05 02:57:04 install Log]: 内部地址:
[1Panel 2026-01-05 02:57:04 install Log]: 面板用户:
[1Panel 2026-01-05 02:57:04 install Log]: 面板密码:
接下来在本机浏览器访问外部地址通过1Panel提供的GUI操作
Let's Encrypt 证书申请
准备工作
- 在应用中心安装OpenResty(基于 NGINX 和 LuaJIT 的 Web 平台)
- 在页面中注册Acme账号用于申请 Let's Encrypt
- 在购买域名的运营商获取 accesskey 和 secretkey 用于申请DNS账号,阿里云的情况需要创建RAM子账号,RAM子账号权限管理添加权限,打开 AliyunDNSFullAccess 否则解析不到地址
- 记住获取的 accesskey 和 secretkey,生成后只显示一次,离开页面失效
申请过程
选择注册的Acme账号和DNS账号,勾选自动续签
反向代理
在左侧网站中创建网站,选择静态网站,启用https导入证书
编辑配置文件,在 server 块最后加入以下内容
# WebSocket 地址
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 地址
location /api/v2 {
proxy_pass http://127.0.0.1:2333/api/v2;
}
# 简读 render 地址
location /render {
proxy_pass http://127.0.0.1:2333/render;
}
# Shiro 地址
location / {
proxy_pass http://127.0.0.1:2323;
}
# 后端管理页面地址
location /proxy {
proxy_pass http://127.0.0.1:2333/proxy;
}
location /qaqdmin {
proxy_pass http://127.0.0.1:2333/proxy/qaqdmin;
}
后端管理页面配置
后端管理页面地址为 https://域名/qaqdmin,根据指示设置好,API 地址网关地址等会自动读取生成
在附加功能 - 配置与云函数中黏贴默认配置
- 名称: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: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": [
"/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
}
}
}
}
使用vercel部署shiro前端
笔者的服务器太垃圾了无法在服务器内编译
- 根据提示填写前端的github仓库,项目创建后vercel会自动帮你fork一个新仓库,之后仓库有更新vercel都会自己deploy
- 此时前端在 build 的时候尝试访问后端 API 会报错找不到,deploy后显示错误,这是正常的
- 在 Settings 的 Environment Variable 配置环境变量
NEXT_PUBLIC_API_URL=https://域名/api/v2 # 后端api
NEXT_PUBLIC_GATEWAY_URL=https://域名 # 网关
ENABLE_EXPERIMENTAL_COREPACK=1 # 部署时启用corepack 取默认值
- 在一开始deploy的production上redeploy
- 完成部署,接下来可根据文档修改云函数来配置,注意不会立刻生效
前端的域名添加
由 vercel 构建的项目会使用 vercel.app 的免费域名,申请一个新的域名用于前端
- 在 settings - domain 中添加你的域名,勾选重定向www,此时是 Invalid 状态
- 根据 vercel 的指示在购买域名的运营商设置 dns 解析,回到网页并 refresh,vercel 会帮你申请 ssl 证书,valid 即可使用你的域名访问构建好的项目