docs: 添加Forgejo部署排障经验库,记录2026-05-16迁移全流程
This commit is contained in:
parent
abc1a41b1b
commit
772009e0f2
279
docs/ops/forgejo-deployment-experience.md
Normal file
279
docs/ops/forgejo-deployment-experience.md
Normal file
@ -0,0 +1,279 @@
|
||||
# Forgejo 部署与排障经验库
|
||||
|
||||
> 光湖语言世界代码仓库(guanghulab.com)从 CVM 迁移到广州轻量云服务器的完整踩坑记录。
|
||||
> 换服务器或遇到类似问题时,先看这个文档,不用重新推演。
|
||||
|
||||
---
|
||||
|
||||
## 核心:一键部署脚本
|
||||
|
||||
优先使用仓库里的 `scripts/smart-deploy-forgejo.sh`。
|
||||
这个脚本做了智能检测(Docker可用性、COS配置、已有Forgejo状态),一条命令跑完全部部署流程。
|
||||
换服务器时的第一步。
|
||||
|
||||
---
|
||||
|
||||
## 二进制部署(Docker 不可用的替代方案)
|
||||
|
||||
当 Docker pull 失败(429限流或被墙)时,直接下载 Gitea 二进制:
|
||||
|
||||
```bash
|
||||
# 下载 Gitea 1.23.7(Forgejo 的底层引擎)
|
||||
wget -O /usr/local/bin/gitea https://dl.gitea.com/gitea/1.23.7/gitea-1.23.7-linux-amd64
|
||||
chmod +x /usr/local/bin/gitea
|
||||
|
||||
# 创建专用用户
|
||||
adduser --disabled-login --gecos "" git
|
||||
|
||||
# 目录结构
|
||||
mkdir -p /opt/forgejo/custom/conf /opt/forgejo/data
|
||||
chown -R git:git /opt/forgejo
|
||||
```
|
||||
|
||||
### app.ini 配置
|
||||
|
||||
`/opt/forgejo/custom/conf/app.ini`:
|
||||
|
||||
```ini
|
||||
APP_NAME = 光湖 · Forgejo
|
||||
RUN_USER = git
|
||||
RUN_MODE = prod
|
||||
|
||||
[database]
|
||||
DB_TYPE = sqlite3
|
||||
PATH = /opt/forgejo/data/forgejo.db
|
||||
|
||||
[server]
|
||||
DOMAIN = guanghulab.com
|
||||
HTTP_PORT = 3001
|
||||
ROOT_URL = https://guanghulab.com/
|
||||
HTTP_ADDR = 127.0.0.1
|
||||
LANDING_PAGE = explore
|
||||
OFFLINE_MODE = false
|
||||
|
||||
[service]
|
||||
DISABLE_REGISTRATION = false
|
||||
REQUIRE_SIGNIN_VIEW = false
|
||||
|
||||
[mailer]
|
||||
ENABLED = false
|
||||
|
||||
[session]
|
||||
PROVIDER = file
|
||||
|
||||
[log]
|
||||
MODE = console
|
||||
LEVEL = info
|
||||
ROOT_PATH = /opt/forgejo/data/log
|
||||
```
|
||||
|
||||
> **注意**:`ROOT_URL` 必须用 `https://`,否则克隆链接会显示 `http://`。
|
||||
|
||||
### systemd 服务
|
||||
|
||||
`/etc/systemd/system/forgejo.service`:
|
||||
|
||||
```ini
|
||||
[Unit]
|
||||
Description=Forgejo (Git with a cup of tea)
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
ExecStart=/usr/local/bin/gitea web -c /opt/forgejo/custom/conf/app.ini --work-path /opt/forgejo
|
||||
Restart=always
|
||||
User=git
|
||||
Group=git
|
||||
WorkingDirectory=/opt/forgejo
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
```
|
||||
|
||||
```bash
|
||||
systemctl daemon-reload
|
||||
systemctl enable --now forgejo
|
||||
systemctl status forgejo
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 常见问题与排查流程
|
||||
|
||||
### 1. Forgejo 拒绝以 root 运行
|
||||
|
||||
**现象**:启动报错 "Forgejo/Gitea refuses to run as root"
|
||||
|
||||
**原因**:Forgejo/Gitea 安全机制禁止 root 运行。
|
||||
|
||||
**解决**:
|
||||
- 直接用 `sudo -u git /usr/local/bin/gitea ...` 启动
|
||||
- 或者在 systemd 里设 `User=git`
|
||||
|
||||
---
|
||||
|
||||
### 2. Git 推送失败:HTTP 413 Request Entity Too Large
|
||||
|
||||
**现象**:
|
||||
|
||||
```
|
||||
error: RPC failed; HTTP 413 curl 22 The requested URL returned error: 413
|
||||
send-pack: unexpected disconnect while reading sideband packet
|
||||
```
|
||||
|
||||
**排查流程**:
|
||||
1. 确认 Nginx 配置中有 `client_max_body_size`:`cat /etc/nginx/sites-available/guanghulab`
|
||||
2. 默认 Nginx 限制 1MB,Git 推送的 packfile 远超此值
|
||||
3. 检查配置是否写在正确的 server block 里(certbot 可能创建了多个配置)
|
||||
|
||||
**解决**:
|
||||
|
||||
```bash
|
||||
# 在 location / 块中添加 client_max_body_size
|
||||
sudo sed -i '/location \/ {/a \ client_max_body_size 100M;' /etc/nginx/sites-available/guanghulab
|
||||
|
||||
# 重载 Nginx
|
||||
sudo systemctl reload nginx
|
||||
```
|
||||
|
||||
**验证**:`git push` 不再报 413 即为成功。
|
||||
|
||||
---
|
||||
|
||||
### 3. 仓库数据损坏:推送成功但网页不显示文件
|
||||
|
||||
**现象**:
|
||||
- `git push` 返回成功(`[new branch] main -> main`)
|
||||
- Forgejo 网页显示仓库名但看不到文件
|
||||
- 再次推送报错:`Gitea: Internal Server Error Decoding Failed` + `pre-receive hook declined`
|
||||
- 远程 HEAD 不一致:`git ls-remote` 显示的 hash 与本地不同
|
||||
|
||||
**根本原因**:从 COS 备份恢复旧 Gitea 数据时,Git 内部数据损坏或版本不兼容。
|
||||
|
||||
**排查流程**:
|
||||
1. `git ls-remote origin HEAD main` — 检查远程 HEAD 是否匹配本地
|
||||
2. `curl -u user:token https://domain.com/api/v1/user/repos` — 查看仓库状态(empty、size)
|
||||
3. 尝试推送观察具体错误信息
|
||||
|
||||
**解决**:
|
||||
|
||||
```bash
|
||||
# 1. 通过 API 删除损坏仓库
|
||||
curl -s -X DELETE -u "bingshuo:ACCESS_TOKEN" "https://guanghulab.com/api/v1/repos/bingshuo/guanghulab"
|
||||
|
||||
# 2. 创建新空仓库
|
||||
curl -s -X POST -u "bingshuo:ACCESS_TOKEN" \
|
||||
"https://guanghulab.com/api/v1/user/repos" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"name":"guanghulab","description":"光湖代码仓库·国内镜像","private":false,"auto_init":false}'
|
||||
|
||||
# 3. 从本地推送完整代码
|
||||
git push https://user:token@guanghulab.com/user/repo.git main
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 4. SSL 证书配置
|
||||
|
||||
```bash
|
||||
# 申请证书
|
||||
sudo certbot --nginx -d guanghulab.com
|
||||
|
||||
# 验证自动续期
|
||||
sudo certbot renew --dry-run
|
||||
|
||||
# 证书位置
|
||||
/etc/letsencrypt/live/guanghulab.com-0001/
|
||||
```
|
||||
|
||||
certbot 会自动在 Nginx 配置中添加 `listen 443 ssl` 和 HTTP→HTTPS 重定向。
|
||||
|
||||
---
|
||||
|
||||
### 5. COS(腾讯云对象存储)备份恢复
|
||||
|
||||
```bash
|
||||
# 安装 coscmd
|
||||
pip3 install coscmd
|
||||
|
||||
# 配置
|
||||
coscmd config -a {secret_id} -s {secret_key} -b {bucket_name} -r ap-guangzhou
|
||||
|
||||
# 列出文件
|
||||
coscmd list
|
||||
|
||||
# 下载备份
|
||||
coscmd download backups/guanghu-old-backup-20260512.tar.gz /root/forgejo-backup.tar.gz
|
||||
|
||||
# 恢复到 Forgejo 目录
|
||||
tar -xzf /root/forgejo-backup.tar.gz -C /opt/forgejo/
|
||||
chown -R git:git /opt/forgejo/
|
||||
```
|
||||
|
||||
> **注意**:COS 存储桶名称:`zy-team-hub-1317346199`,区域:`ap-guangzhou`。
|
||||
> 备份文件在 `backups/` 目录下。
|
||||
|
||||
---
|
||||
|
||||
### 6. 验证部署完整性
|
||||
|
||||
**确认服务运行**:
|
||||
|
||||
```bash
|
||||
systemctl status forgejo # 服务 active
|
||||
curl -I http://127.0.0.1:3001 # 返回 200
|
||||
curl -I https://guanghulab.com # HTTPS 正常
|
||||
```
|
||||
|
||||
**确认仓库状态**:
|
||||
- Forgejo 网页登录 → 仓库列表有数据
|
||||
- `git ls-remote https://guanghulab.com/bingshuo/guanghulab.git HEAD` → 返回正确 commit
|
||||
- Forgejo API `GET /api/v1/user/repos` → 返回仓库列表
|
||||
|
||||
---
|
||||
|
||||
## 部署流程速查
|
||||
|
||||
从零开始部署的完整流程(假设已有 COS 备份):
|
||||
|
||||
1. **执行 `scripts/smart-deploy-forgejo.sh`** 或手动部署二进制
|
||||
2. **从 COS 下载备份并恢复**
|
||||
3. **配置 Nginx 反向代理**(脚本已自动处理)
|
||||
4. **申请 SSL 证书**(`certbot --nginx`)
|
||||
5. **启动 Forgejo 并验证**
|
||||
6. **如果仓库损坏** → 删除仓库,重建,重新推送
|
||||
7. **如果推送报 413** → 配置 Nginx `client_max_body_size 100M`
|
||||
|
||||
---
|
||||
|
||||
## 注意事项
|
||||
|
||||
- **不要用 root 直接运行 Forgejo** — 必须用 git 用户
|
||||
- **Nginx 配置改动后必须 reload** — `sudo systemctl reload nginx`
|
||||
- **备份恢复后检查仓库完整性** — 用 `git ls-remote` 对比本地 hash
|
||||
- **ROOT_URL 要写 https** — 否则克隆链接显示 http://
|
||||
- **certbot 会修改 Nginx 配置** — 注意它创建的是独立的 server block
|
||||
|
||||
---
|
||||
|
||||
## 2026-05-16 实测记录
|
||||
|
||||
本次迁移完整时间线:
|
||||
|
||||
| 时间 | 事件 | 结果 |
|
||||
|------|------|------|
|
||||
| 14:30 | 从 COS 下载 44MB 备份 | ✅ |
|
||||
| 14:45 | 解压恢复 forgejo.db + 仓库 | ✅ |
|
||||
| 15:00 | 下载 Gitea 1.23.7 二进制 | ✅ |
|
||||
| 15:20 | Nginx 反向代理 + SSL 证书 | ✅ |
|
||||
| 15:50 | 域名解析切换到广州服务器 | ✅ |
|
||||
| 16:37 | 推送代码到新仓库 | ⚠️ 推送成功但网页不显示 |
|
||||
| 16:50 | 发现仓库数据损坏 | ❌ Internal Server Error |
|
||||
| 16:52 | 删除损坏仓库,重建 | ✅ |
|
||||
| 16:55 | 再次推送 → HTTP 413 | ❌ |
|
||||
| 16:58 | 排查 Nginx 配置 → 缺 client_max_body_size | ✅ 修复 |
|
||||
| 17:02 | 重载 Nginx,第三次推送 | ✅ 成功 |
|
||||
|
||||
**教训总结**:
|
||||
1. COS 备份恢复后,仓库数据可能损坏——先 `git ls-remote` 验证
|
||||
2. Nginx 默认 1MB body 限制——Git 推送必超,需显式设置
|
||||
3. 经验要沉淀到仓库里,不能只留在本地终端
|
||||
Loading…
x
Reference in New Issue
Block a user