宝塔面板 Docker 博客完整发布与更新指南
适用环境:Ubuntu/Linux、宝塔面板、Docker Compose V2、
linux/amd64服务器。
部署方式:本地构建 Docker 镜像,服务器只负责加载镜像,不在服务器编译源码。
一、最终服务器目录结构
服务器只需要保留以下内容:
/www/wwwroot/zhu-blog/
├── .env
├── docker-compose.bt.yml
└── storage/
└── uploads/
每次更新时,临时上传两个镜像 TAR:
/www/wwwroot/zhu-blog/
├── panxi-blog-backend-版本-linux-amd64.tar
└── panxi-blog-frontend-版本-linux-amd64.tar
更新完成并验证成功后,两个 TAR 可以删除。
服务器不再需要:
backend/
frontend/
src/
migrations/
node_modules/
Dockerfile
源码文件
历史 ZIP/TAR 发布包
二、本地提交代码
2.1 提交后端
在 Windows PowerShell 中执行:
cd D:\code\backend\blog-backend
git status
git add -A
git commit -m "release: 发布新版本"
git log -1 --oneline
如果没有需要提交的内容,Git 会提示工作区干净,可以继续打包。
2.2 提交前端
cd D:\code\frontend\blog-frontend
git status
git add -A
git commit -m "release: 发布新版本"
git log -1 --oneline
三、本地打包 Docker 镜像
3.1 设置版本号
只需要修改一次版本号:
$Version = "v2-$(Get-Date -Format 'yyyyMMdd-HHmm')-update"
生成示例:
v2-20260816-2030-update
版本号只能包含:
英文字母、数字、点、下划线、短横线
3.2 打包后端
cd D:\code\backend\blog-backend
.\scripts\package-image.ps1 `
-Version $Version `
-Platform "linux/amd64"
生成文件:
D:\code\backend\blog-backend\release\
├── panxi-blog-backend-版本-linux-amd64.tar
└── panxi-blog-backend-版本-linux-amd64.zip
3.3 打包前端
cd D:\code\frontend\blog-frontend
.\scripts\package-image.ps1 `
-Version $Version `
-Platform "linux/amd64"
生成文件:
D:\code\frontend\blog-frontend\release\
├── panxi-blog-frontend-版本-linux-amd64.tar
└── panxi-blog-frontend-版本-linux-amd64.zip
3.4 检查生成的文件
$BackendTar = "D:\code\backend\blog-backend\release\panxi-blog-backend-$Version-linux-amd64.tar"
$FrontendTar = "D:\code\frontend\blog-frontend\release\panxi-blog-frontend-$Version-linux-amd64.tar"
Get-Item $BackendTar, $FrontendTar |
Select-Object Name, Length, LastWriteTime
检查 SHA256:
Get-FileHash -Algorithm SHA256 -LiteralPath $BackendTar
Get-FileHash -Algorithm SHA256 -LiteralPath $FrontendTar
保存输出的 SHA256,上传后可以再次比对。
四、ZIP 是否需要解压
推荐直接上传 .tar,不需要上传 .zip。
Docker 可以直接加载 TAR:
docker load -i 镜像文件.tar
不要执行:
tar -xf 镜像文件.tar
Docker 镜像 TAR 不需要手动解压。
ZIP 主要用于本地归档。如果只保留了 ZIP,可以在本地解压:
$BackendUnpack = "D:\code\release-unpacked\backend-$Version"
$FrontendUnpack = "D:\code\release-unpacked\frontend-$Version"
Expand-Archive `
-LiteralPath "D:\code\backend\blog-backend\release\panxi-blog-backend-$Version-linux-amd64.zip" `
-DestinationPath $BackendUnpack `
-Force
Expand-Archive `
-LiteralPath "D:\code\frontend\blog-frontend\release\panxi-blog-frontend-$Version-linux-amd64.zip" `
-DestinationPath $FrontendUnpack `
-Force
然后从解压目录中找到 TAR 并上传。
五、上传发布包
5.1 使用宝塔面板上传
打开:
宝塔面板 → 文件 → /www/wwwroot/zhu-blog
直接上传:
panxi-blog-backend-版本-linux-amd64.tar
panxi-blog-frontend-版本-linux-amd64.tar
不需要创建 backend 和 frontend 目录。
5.2 使用 SCP 上传
在本地 PowerShell 中执行:
$Server = "root@服务器IP"
$RemoteDir = "/www/wwwroot/zhu-blog/"
scp $BackendTar "${Server}:${RemoteDir}"
scp $FrontendTar "${Server}:${RemoteDir}"
示例:
scp "D:\code\backend\blog-backend\release\panxi-blog-backend-v2-20260816-update-linux-amd64.tar" root@服务器IP:/www/wwwroot/zhu-blog/
scp "D:\code\frontend\blog-frontend\release\panxi-blog-frontend-v2-20260816-update-linux-amd64.tar" root@服务器IP:/www/wwwroot/zhu-blog/
六、部署前备份
6.1 设置目录和备份编号
登录服务器后执行:
APP_DIR=/www/wwwroot/zhu-blog
BACKUP_TIME=$(date +%Y%m%d-%H%M%S)
BACKUP_DIR="/www/backup/zhu-blog/$BACKUP_TIME"
mkdir -p "$BACKUP_DIR"
chmod 700 "$BACKUP_DIR"
6.2 备份环境变量和 Compose 配置
cp -a "$APP_DIR/.env" "$BACKUP_DIR/.env"
cp -a "$APP_DIR/docker-compose.bt.yml" "$BACKUP_DIR/docker-compose.bt.yml"
6.3 备份上传文件
tar -czf "$BACKUP_DIR/storage.tar.gz" \
-C "$APP_DIR" \
storage
检查备份:
ls -lah "$BACKUP_DIR"
du -sh "$BACKUP_DIR"
6.4 备份数据库
如果数据库由宝塔管理,推荐使用:
宝塔面板 → 数据库 → 对应数据库 → 备份
如果服务器已经安装 pg_dump,也可以执行:
set -a
source /www/wwwroot/zhu-blog/.env
set +a
pg_dump \
--dbname="$DATABASE_URL" \
--format=custom \
--file="$BACKUP_DIR/database.dump"
unset DATABASE_URL
检查数据库备份:
ls -lh "$BACKUP_DIR/database.dump"
如果提示:
pg_dump: command not found
请使用宝塔数据库备份功能,不要因为缺少该命令而中断其他部署步骤。
七、为当前镜像创建回滚标签
更新前给旧镜像添加回滚标签。添加标签不会复制镜像,不会立即额外占用大量空间。
ROLLBACK_TAG=$(date +%Y%m%d-%H%M%S)
docker tag \
panxi-blog-backend:local \
"panxi-blog-backend:rollback-$ROLLBACK_TAG"
docker tag \
panxi-blog-frontend:local \
"panxi-blog-frontend:rollback-$ROLLBACK_TAG"
echo "本次回滚标签:$ROLLBACK_TAG"
记住输出的回滚编号。
查看回滚镜像:
docker image ls | grep panxi-blog
八、校验上传文件
先设置本次版本号:
VERSION="v2-20260816-update"
APP_DIR=/www/wwwroot/zhu-blog
BACKEND_TAR="panxi-blog-backend-${VERSION}-linux-amd64.tar"
FRONTEND_TAR="panxi-blog-frontend-${VERSION}-linux-amd64.tar"
根据实际文件名修改 VERSION。
检查文件:
ls -lh \
"$APP_DIR/$BACKEND_TAR" \
"$APP_DIR/$FRONTEND_TAR"
计算服务器 SHA256:
sha256sum \
"$APP_DIR/$BACKEND_TAR" \
"$APP_DIR/$FRONTEND_TAR"
将结果与本地 PowerShell 的 Get-FileHash 结果比较。
SHA256 一致后再继续部署。
九、加载新 Docker 镜像
cd /www/wwwroot/zhu-blog
docker load -i "$BACKEND_TAR"
docker load -i "$FRONTEND_TAR"
加载后检查:
docker image inspect panxi-blog-backend:local \
--format '后端镜像={{.Id}} 创建时间={{.Created}}'
docker image inspect panxi-blog-frontend:local \
--format '前端镜像={{.Id}} 创建时间={{.Created}}'
十、部署新版本
执行:
cd /www/wwwroot/zhu-blog
docker compose -f docker-compose.bt.yml \
up -d \
--force-recreate \
--remove-orphans
不需要先执行:
docker compose down
up -d --force-recreate 会重新创建容器,通常只有短暂中断。
十一、验证部署结果
11.1 检查容器状态
docker compose \
-f /www/wwwroot/zhu-blog/docker-compose.bt.yml \
ps
正常状态应类似:
backend Up ... (healthy)
frontend Up ...
11.2 检查后端健康状态
curl -fsS http://127.0.0.1:5800/api/health
查看 HTTP 状态:
curl -I http://127.0.0.1:5800/api/health
11.3 检查前端
curl -I http://127.0.0.1:3000
正常应返回:
HTTP/1.1 200
或其他正常的 2xx/3xx 响应。
11.4 检查容器和本地镜像 ID
检查后端:
docker image inspect panxi-blog-backend:local \
--format '后端本地镜像={{.Id}}'
docker inspect \
--format '后端容器镜像={{.Image}} 配置名称={{.Config.Image}}' \
"$(docker compose -f /www/wwwroot/zhu-blog/docker-compose.bt.yml ps -q backend)"
检查前端:
docker image inspect panxi-blog-frontend:local \
--format '前端本地镜像={{.Id}}'
docker inspect \
--format '前端容器镜像={{.Image}} 配置名称={{.Config.Image}}' \
"$(docker compose -f /www/wwwroot/zhu-blog/docker-compose.bt.yml ps -q frontend)"
本地镜像 ID 和容器镜像 ID 应一致。
11.5 查看日志
后端日志:
docker compose \
-f /www/wwwroot/zhu-blog/docker-compose.bt.yml \
logs --tail=100 backend
前端日志:
docker compose \
-f /www/wwwroot/zhu-blog/docker-compose.bt.yml \
logs --tail=100 frontend
持续查看日志:
docker compose \
-f /www/wwwroot/zhu-blog/docker-compose.bt.yml \
logs -f --tail=100
按 Ctrl+C 退出日志查看,不会停止容器。
11.6 浏览器功能验证
至少检查:
- 网站首页能正常打开
- 网站顶部名称显示正确
- 图片和历史上传文件能正常访问
- 后台可以正常登录
- 文章列表能正常加载
- 文章发布、下线、删除、置顶操作正常
- 置顶文章存在对应标记
- 最多只允许置顶三篇文章
- 深色背景下按钮文字清晰可见
十二、部署失败时回滚
假设部署前生成的回滚标签是:
20260816-203000
设置回滚编号:
ROLLBACK_TAG="20260816-203000"
把旧镜像重新标记为 local:
docker tag \
"panxi-blog-backend:rollback-$ROLLBACK_TAG" \
panxi-blog-backend:local
docker tag \
"panxi-blog-frontend:rollback-$ROLLBACK_TAG" \
panxi-blog-frontend:local
重新创建容器:
cd /www/wwwroot/zhu-blog
docker compose -f docker-compose.bt.yml \
up -d \
--force-recreate \
--remove-orphans
验证:
docker compose -f docker-compose.bt.yml ps
curl -fsS http://127.0.0.1:5800/api/health
curl -I http://127.0.0.1:3000
十三、验证成功后清理发布包
13.1 查看待删除的 TAR、ZIP 和临时文件
只检查根目录,不进入其他目录:
find /www/wwwroot/zhu-blog \
-maxdepth 1 \
-type f \
\( \
-name 'panxi-blog-*.tar' \
-o -name 'panxi-blog-*.zip' \
-o -name '*.upload.tmp' \
\) \
-printf '%s bytes\t%TY-%Tm-%Td %TH:%TM\t%p\n'
13.2 删除历史发布包
确认部署成功后执行:
find /www/wwwroot/zhu-blog \
-maxdepth 1 \
-type f \
\( \
-name 'panxi-blog-*.tar' \
-o -name 'panxi-blog-*.zip' \
-o -name '*.upload.tmp' \
\) \
-delete
这只会清理 /www/wwwroot/zhu-blog 根目录中的发布包,不会进入 storage。
十四、清理旧 Docker 镜像
14.1 部署刚完成时先不要清理回滚镜像
建议观察一段时间,确认网站完全正常后再删除回滚标签。
查看镜像:
docker image ls | grep panxi-blog
14.2 删除指定回滚镜像
ROLLBACK_TAG="实际回滚编号"
docker image rm \
"panxi-blog-backend:rollback-$ROLLBACK_TAG" \
"panxi-blog-frontend:rollback-$ROLLBACK_TAG"
然后清理没有标签、没有容器使用的旧镜像层:
docker image prune -f
查看 Docker 空间:
docker system df
不要随意执行:
docker system prune -a
因为它可能删除备用镜像和其他暂时未运行的镜像。
十五、下载并清理服务器备份
验证新版本稳定后,将备份下载到本地。
在本地 PowerShell 中执行:
scp -r root@服务器IP:/www/backup/zhu-blog/备份编号 "D:\code\backups\"
确认本地备份完整后,服务器上可以删除对应备份目录:
rm -rf -- "/www/backup/zhu-blog/准确的备份编号"
删除前必须确认路径包含具体备份编号,不要直接删除:
/www/backup
/www/backup/zhu-blog
/
十六、最终空间检查
检查博客目录:
du -xhd 2 /www/wwwroot/zhu-blog | sort -h
检查磁盘:
df -h /www/wwwroot/zhu-blog
检查 Docker:
docker system df
检查最终文件:
find /www/wwwroot/zhu-blog \
-maxdepth 2 \
-printf '%y\t%p\n' \
| sort
正常情况下最终主要保留:
/www/wwwroot/zhu-blog/.env
/www/wwwroot/zhu-blog/docker-compose.bt.yml
/www/wwwroot/zhu-blog/storage
/www/wwwroot/zhu-blog/storage/uploads
十七、日常更新最简流程
本地 PowerShell
$Version = "v2-$(Get-Date -Format 'yyyyMMdd-HHmm')-update"
cd D:\code\backend\blog-backend
.\scripts\package-image.ps1 -Version $Version -Platform "linux/amd64"
cd D:\code\frontend\blog-frontend
.\scripts\package-image.ps1 -Version $Version -Platform "linux/amd64"
$BackendTar = "D:\code\backend\blog-backend\release\panxi-blog-backend-$Version-linux-amd64.tar"
$FrontendTar = "D:\code\frontend\blog-frontend\release\panxi-blog-frontend-$Version-linux-amd64.tar"
scp $BackendTar root@服务器IP:/www/wwwroot/zhu-blog/
scp $FrontendTar root@服务器IP:/www/wwwroot/zhu-blog/
服务器
修改版本号后执行:
VERSION="实际版本号"
APP_DIR=/www/wwwroot/zhu-blog
cd "$APP_DIR"
docker tag panxi-blog-backend:local "panxi-blog-backend:rollback-$(date +%Y%m%d-%H%M%S)"
docker tag panxi-blog-frontend:local "panxi-blog-frontend:rollback-$(date +%Y%m%d-%H%M%S)"
docker load -i "panxi-blog-backend-${VERSION}-linux-amd64.tar"
docker load -i "panxi-blog-frontend-${VERSION}-linux-amd64.tar"
docker compose -f docker-compose.bt.yml \
up -d \
--force-recreate \
--remove-orphans
docker compose -f docker-compose.bt.yml ps
curl -fsS http://127.0.0.1:5800/api/health
curl -I http://127.0.0.1:3000
确认成功后删除本次发布包:
rm -f -- \
"/www/wwwroot/zhu-blog/panxi-blog-backend-${VERSION}-linux-amd64.tar" \
"/www/wwwroot/zhu-blog/panxi-blog-frontend-${VERSION}-linux-amd64.tar"
docker image prune -f
df -h /www/wwwroot/zhu-blog
十八、重要注意事项
- 服务器不再编译前后端源码。
- 不需要上传
src、migrations、node_modules等源码目录。 - 发布时只上传两个 Docker 镜像 TAR。
- Docker 镜像 TAR 不需要执行
tar -xf。 - 更新前必须备份
.env、Compose、上传文件和数据库。 - 不需要执行
docker compose down。 - 删除 TAR 不会删除已经加载到 Docker 中的镜像。
- 必须保留
.env、docker-compose.bt.yml和storage/uploads。 - 不要删除当前使用的
panxi-blog-backend:local和panxi-blog-frontend:local镜像。 - 不要使用
docker system prune -a进行无差别清理。

留下你的想法