跳到正文
Joeplover
工程·2026-06-28·约 5 分钟阅读

博客运维:通过 Git 更新服务器代码与数据库的完整流程

本地开发 → Git 推送 → 服务器拉取 → 构建重启。本文记录从本地博客修改到服务器生效的完整运维流程,包括代码更新、数据库同步、常见错误处理。

Code on a laptop screen with deployment pipeline diagram

博客运维:通过 Git 更新服务器代码与数据库的完整流程

前言

博客基于 Next.js + Prisma + SQLite 搭建,部署在腾讯云 Ubuntu 22.04 上,通过 Nginx 反向代理 + PM2 进程管理提供服务。日常更新内容包括:

  • 代码修改(新功能、Bug 修复、样式调整)
  • 内容修改(新增/编辑文章、修改分类)
  • 数据库同步(本地新增文章后同步到服务器)

本文记录完整的更新流程和踩坑记录。

一、基础环境确认

服务器目录结构:

/home/ubuntu/JoeBlog       # 项目根目录
├── prisma/
│   └── dev.db             # SQLite 数据库文件(默认路径)
├── .next/                  # Next.js 构建产物
├── .env.production         # 生产环境变量
└── package.json

关键环境变量文件 .env.production:

DATABASE_URL="file:./prisma/dev.db"

二、代码更新流程

本地开发

# 修改代码...
cd /f/GitHub_project/BLOG/Joe_blog

# 测试
npm run dev

# 提交
git add .
git commit -m "feat: 添加了新功能"

本地 Git 代理注意

如果本地有 Git 代理设置,提交前需检查:

git config --global http.proxy
git config --global https.proxy

有代理的话推送可能会走代理导致失败,可以临时绕过:

git -c http.proxy= -c https.proxy= push

推送到 GitHub

git push
# 或者 bypass 代理
git -c http.proxy= -c https.proxy= push

服务器拉取

登录服务器:

ssh ubuntu@你的服务器IP
cd /home/ubuntu/JoeBlog

拉取最新代码:

# 先备份当前代码(可选)
# cp -r . ~/joeblog-backup-$(date +%Y%m%d)

git pull

如果服务器上 Git 配置了 SSH key 但推送方式变了,可能需要先切分支或处理冲突:

# 如果有冲突
git stash        # 暂存本地修改
git pull         # 拉取远程
git stash pop    # 恢复本地修改(手动解决冲突)

安装依赖

npm install

注意:如果 package.json 或 package-lock.json 没有变化,可以跳过这步。

构建

npm run build

Next.js 构建过程会:

  1. Prisma generate(如果 schema 变化)
  2. 编译 TypeScript 和 JSX
  3. 生成静态页面(ISR/SSG)
  4. 输出到 .next/ 目录

重启服务

pm2 restart joe-blog

如果 PM2 中没保存进程名,先查看:

pm2 list

确认服务正常:

curl -o /dev/null -s -w "%{http_code}" http://localhost:3000
# 返回 200 表示正常

ss -tlnp | grep 3000
# 确认 PM2 进程在监听

三、数据库同步流程

场景 1:只在本地新增了文章,数据库文件整体同步

最简单的方式:直接把本地数据库文件 scp 到服务器覆盖。

# 本地执行(在 Windows 上)
scp /f/GitHub_project/BLOG/Joe_blog/prisma/dev.db ubuntu@服务器IP:/home/ubuntu/JoeBlog/prisma/

重要:scp 前先停掉 PM2 服务,避免文件正在被写入导致损坏:

# 服务器上
pm2 stop joe-blog

# 本地 scp 上传
scp /f/GitHub_project/BLOG/Joe_blog/prisma/dev.db ubuntu@服务器IP:/home/ubuntu/JoeBlog/prisma/

# 重启
pm2 restart joe-blog

场景 2:只想同步部分数据(新增的文章)

最佳实践是只导出新增的文章 SQL 并执行。但 SQLite 是文件型数据库,对于小博客项目,直接用文件覆盖是最简单可靠的方案。

场景 3:修改了 Prisma Schema

如果改了 schema.prisma(新增字段、修改模型等),除了拉取代码外还需要:

cd /home/ubuntu/JoeBlog
npx prisma generate    # 重新生成 Prisma Client
npx prisma db push     # 同步 schema 到数据库(不会删除数据)

prisma db push 会在不丢失现有数据的前提下修改表结构。如果需要重置数据可以 prisma db push --force-reset(会清空数据)。

上传数据库文件的最佳实践

# 完整流程(服务器上执行)
pm2 stop joe-blog
cp prisma/dev.db prisma/dev.db.bak   # 先备份旧的

# 本地执行 scp
scp /f/GitHub_project/BLOG/Joe_blog/prisma/dev.db ubuntu@服务器IP:/home/ubuntu/JoeBlog/prisma/

# 重启
pm2 restart joe-blog

# 验证
curl http://localhost:3000

四、常见错误处理

1. PM2 端口冲突(EADDRINUSE)

# 现象:pm2 start 后进程显示 online 但网站无法访问
# 查看日志
pm2 logs

# 如果看到 EADDRINUSE
ss -tlnp | grep 3000  # 找到占用的 PID
kill <PID>             # 杀死旧进程
pm2 delete joe-blog && pm2 start npm --name "joe-blog" -- start
pm2 save

2. Prisma 找不到数据库

# 现象:构建或运行时 Prisma 报错
# Error: Environment variable not found: DATABASE_URL

# 检查 .env.production 文件是否存在
cat /home/ubuntu/JoeBlog/.env.production

# 缺少则创建
echo 'DATABASE_URL="file:./prisma/dev.db"' > /home/ubuntu/JoeBlog/.env.production

3. PM2 Daemon 崩溃 / 进程列表丢失

# 现象:pm2 status 显示空列表,daemon 每次都重新 spawn
# 解决方案
cd /home/ubuntu/JoeBlog
pm2 start npm --name "joe-blog" -- start
pm2 save

# 检查 systemd 自启用户是否正确
cat /etc/systemd/system/pm2-ubuntu.service | grep User
# 如果 User 和实际运行用户不匹配,需要修改

4. Git 推送被代理拦截

# 现象:git push 报代理错误
# 跳过代理直接推送
git -c http.proxy= -c https.proxy= push

五、完整更新脚本示例

以下是服务器上执行的完整更新命令序列:

#!/bin/bash
# update-blog.sh - 服务器上执行

set -e

echo "=== Step 1: 拉取代码 ==="
cd /home/ubuntu/JoeBlog
git pull

echo "=== Step 2: 安装依赖 ==="
npm install

echo "=== Step 3: 构建 ==="
npm run build

echo "=== Step 4: 重启服务 ==="
pm2 restart joe-blog

echo "=== Step 5: 验证 ==="
sleep 3
STATUS=$(curl -o /dev/null -s -w "%{http_code}" http://localhost:3000)
if [ "$STATUS" = "200" ]; then
    echo "✅ 部署成功,HTTP $STATUS"
else
    echo "❌ 部署异常,HTTP $STATUS"
fi

总结

整套运维流程并不复杂,核心就是:本地改 → git push → 服务器 git pull → npm install(如有新依赖)→ npm run build → pm2 restart。数据库同步更简单,SQLite 文件直接 scp 覆盖即可。

关键记住三点:

  1. scp 数据库前先停 PM2,避免文件损坏
  2. 每次更新后 pm2 restart,别忘记 pm2 save 持久化进程列表
  3. 端口排查用 ss 不用 lsof