# Gitea 部署指南

**适用范围**: 企微 IT 智能服务台项目
**维护人**: 宋献 + Claude 协作
**最后更新**: 2026-06-14(卸载清空事件后)
**关联**: [[风险跟踪表]] 第十二节 / [[CONTRIBUTING]] / [[scripts/backup-gitea.sh]]

---

## 📌 1. 部署环境

### 1.1 推荐方案:Synology 套件版

| 项 | 值 | 备注 |
|---|---|---|
| NAS | Synology DS923+ | DSM 7.2+ |
| 套件 | Gitea 1.22+ | 套件中心搜 "Gitea" |
| 端口 | 8418 (HTTP) | 避开 3000(被占) |
| 数据库 | SQLite3 | 单机够用,避免 MySQL 配置坑 |
| Tailscale | tail58d872.ts.net | Funnel 暴露给 workbuddy 沙箱 |
| 备份 | `scripts/backup-gitea.sh` | 每天 cron 3 点 |

### 1.2 备选方案:Docker 容器版

```bash
sudo mkdir -p /volume1/docker/gitea/{data,config,repos}
sudo chown -R 1000:1000 /volume1/docker/gitea

docker run -d \
  --name gitea \
  --restart always \
  -p 8418:3000 \
  -p 2222:22 \
  -v /volume1/docker/gitea/data:/data \
  -v /volume1/docker/gitea/config:/etc/gitea \
  -v /volume1/docker/gitea/repos:/data/git/repositories \
  gitea/gitea:1.22
```

**优势**:升级/迁移灵活
**劣势**:需要 Container Manager 知识,SSL/反向代理需手配

---

## 📌 2. 初始化(首次安装)

### 2.1 创管理员

1. 浏览器 `http://<NAS_IP>:8418/`
2. 看到 **"首次安装,请注册管理员账号"**
3. 填:
   - **管理员用户名**: `simon`(项目负责人)
   - **邮箱**: 你常用邮箱
   - **密码**: 强密码(≥16 位,大小写+数字+特殊)
4. **立即登录**

### 2.2 创仓

1. 右上角 `+` → **创建新的仓库**
2. 填:
   - **所有者**: `simon`
   - **仓库名**: `wecom_it_smart_desk`
   - **可见性**: 私有(Private)
   - **⚠️ 不勾** "使用 README 初始化"
   - **⚠️ 不勾** "使用 .gitignore"
   - **⚠️ 不勾** "使用 License"
3. **创建仓库**

### 2.3 创 Access Token(workbuddy-claude 协作)

1. 创 **workbuddy-claude** 普通用户(站点管理 → 用户)
2. 用 workbuddy-claude 登录
3. 头像 → **设置** → **应用** → **管理 Access Token**
4. 创:
   - 令牌名: `claude-push`
   - 权限: ✅ `repository` ✅ `issue` ✅ `user`

---

## 📌 3. 本地仓接入

### 3.1 配 remote(走 wincred,不嵌 token)

```bash
cd D:\资料\03-项目开发\wecom_it_smart_desk
git remote add origin https://simon@ds923plus.tail58d872.ts.net/simon/wecom_it_smart_desk.git
```

### 3.2 首次推 main

```bash
# 在 PowerShell 跑(会弹窗输 token)
git push -u origin main
```

**弹窗时**:
- **Username**: 留空
- **Password**: 粘 access token

**wincred 自动缓存**,后续 push 不弹窗。

**换 token**:
```bash
# 清旧缓存
printf "protocol=https\nhost=ds923plus.tail58d872.ts.net\nusername=simon\n" | git credential reject

# 存新缓存(在 bash 跑,token 在 heredoc)
printf "protocol=https\nhost=ds923plus.tail58d872.ts.net\nusername=simon\npassword=NEW_TOKEN\n" | git credential approve
```

---

## 📌 4. Tailscale Funnel 暴露(给 workbuddy 沙箱)

### 4.1 配 Funnel

```bash
ssh simon@100.85.152.112
sudo tailscale funnel --bg 8418
```

### 4.2 验证

- 浏览器(任何网络)打开 `https://ds923plus.tail58d872.ts.net/`
- 应看到 Gitea 登录页

### 4.3 故障排查

| 现象 | 原因 | 解决 |
|---|---|---|
| Funnel 域名打不开 | tailscaled 停 | `sudo systemctl restart tailscaled` |
| 8418 connection refused | Gitea 套件停 | 套件中心 → Gitea → 启动 |
| TLS 证书报错 | Funnel HTTPS 证书未自动签 | 等 30 秒自动签,或 `sudo tailscale funnel reset` |

---

## 📌 5. 分支保护(main 必须保护)

### 5.1 用 simon admin token 跑 API

```bash
TOKEN="simon的admin token"

# 删旧保护
curl -X DELETE \
  -H "Authorization: token $TOKEN" \
  "http://100.85.152.112:8418/api/v1/repos/simon/wecom_it_smart_desk/branch_protections/main"

# 重建保护
curl -X POST \
  -H "Authorization: token $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "branch_name": "main",
    "enable_push": false,
    "enable_pull_request": true,
    "required_approvals": 1,
    "dismiss_stale_approvals": true,
    "block_admin_merge": false
  }' \
  "http://100.85.152.112:8418/api/v1/repos/simon/wecom_it_smart_desk/branch_protections"
```

### 5.2 关键参数解释

| 参数 | 值 | 说明 |
|---|---|---|
| `enable_push` | `false` | 禁止直推 main |
| `enable_pull_request` | `true` | 需走 PR |
| `required_approvals` | `1` | 需 1 个 reviewer |
| `block_admin_merge` | `false` | simon 可强推(临时,等 workbuddy 接入改 true) |

### 5.3 升级路径(workbuddy 接入后改严)

- 创 `workbuddy-claude` 普通 user ✅
- 创 workbuddy-claude token ✅
- `block_admin_merge` 改 `true`(评审员有 ≥2 个 user)
- 加 `enable_status_check: true` + 配 Gitea Actions CI

---

## 📌 6. 备份策略(必做!)

### 6.1 首次部署备份脚本

```bash
# 本地仓 → NAS
scp scripts/backup-gitea.sh simon@100.85.152.112:/volume1/docker/wecom-it-desk/scripts/

# NAS 跑首次备份
ssh simon@100.85.152.112
sudo bash /volume1/docker/wecom-it-desk/scripts/backup-gitea.sh
```

### 6.2 配 cron(每天 3 点)

```bash
# 编辑 crontab
sudo crontab -e

# 加一行
0 3 * * * /volume1/docker/wecom-it-desk/scripts/backup-gitea.sh >> /var/log/gitea-backup.log 2>&1
```

### 6.3 验证 cron

```bash
# 列出当前 cron
sudo crontab -l

# 看下次执行时间
systemctl list-timers | grep cron
```

### 6.4 备份内容

- ✅ 配置文件 `app.ini`
- ✅ SQLite 数据库(热备,`sqlite3 .backup`)
- ✅ 仓裸仓库 `repos/`(tar.gz 压缩)
- ✅ LFS 数据
- ✅ 头像 / 附件
- ✅ 元信息 `backup.meta`

保留 **7 天**(`--keep 30` 改 30 天)

### 6.5 异地备份(强烈建议)

3 个方案:

| 方案 | 成本 | 复杂度 | 推荐度 |
|---|---|---|---|
| A. 本机 D 盘 | 0 | 低 | ⭐⭐ |
| B. 阿里云 OSS / 腾讯云 COS | ~5 元/月 | 中 | ⭐⭐⭐ |
| C. NAS2 + OSS 双备 | ~10 元/月 | 高 | ⭐⭐⭐⭐ |

**推荐 B**:在 NAS 装 `rclone`,cron 推 OSS。

---

## 📌 7. 恢复流程

### 7.1 列出可用备份

```bash
ls -lh /volume1/backups/gitea/
# gitea-backup-20260614-180000.tar.gz
# gitea-backup-20260613-180000.tar.gz
# ...
```

### 7.2 恢复到 latest

```bash
sudo bash /volume1/docker/wecom-it-desk/scripts/backup-gitea.sh --restore latest
```

⚠️ **会自动停 Gitea → 覆盖数据 → 启动 Gitea**

### 7.3 恢复到指定时间

```bash
sudo bash /volume1/docker/wecom-it-desk/scripts/backup-gitea.sh --restore 20260614-180000
```

### 7.4 验证恢复

1. 浏览器 `http://<NAS_IP>:8418/` → 应看到 Gitea 登录页
2. 登录 simon → 应看到所有仓
3. 选仓 → 应看到 commit 历史

---

## 📌 8. 卸载注意事项(血泪教训!)

### 🛑 8.1 **卸载前必做**

1. ✅ 跑 `scripts/backup-gitea.sh` 取最新备份
2. ✅ scp 备份到本地 + OSS 异地
3. ✅ 记下当前 Gitea 版本(套件中心看)
4. ✅ 记下当前端口(默认 3000 / 容器 8418 / 套件 8418)

### 🛑 8.2 卸载"清空" vs "保留"

| 选项 | 清什么 | 不清什么 | 适用 |
|---|---|---|---|
| **仅卸载** | 套件 app | app.ini / DB / repos / LFS | 临时停用 |
| **卸载并清空** ⚠️ | 套件 app + app.ini + DB | ⚠️ **可能**保留 repos / LFS(套件机制) | 永久删除 |

### 🛑 8.3 卸载"清空"后仓还在硬盘

**2026-06-14 实战**:卸载清空后,`/volume1/@appdata/gitea/gitea/repos/` 仓裸仓库**还在**。

**恢复路径**:
1. 重装 Gitea 套件
2. 初始化(simon's admin)
3. **不要** Web 创仓(会报"已存在文件")
4. SSH 删残留仓目录:
   ```bash
   sudo rm -rf /volume1/@appdata/gitea/gitea/repos/simon/wecom_it_smart_desk.git
   sudo rm -rf /volume1/@appdata/gitea/gitea/lfs/simon/wecom_it_smart_desk.git
   ```
5. Web 创仓(空)
6. 本地推 main(本地仓有完整 11 commit)

### 🛑 8.4 卸载"清空"后仓真的没了

**走备份恢复**:
```bash
sudo bash /volume1/docker/wecom-it-desk/scripts/backup-gitea.sh --restore latest
```

---

## 📌 9. 故障排查

### 9.1 套件启动失败

```bash
# 看套件日志
sudo cat /var/log/packages/Gitea.log

# 重启套件
sudo synopkg restart Gitea
```

### 9.2 端口 8418 被占

```bash
# 查谁占
sudo lsof -i :8418

# 改 Gitea 端口(套件不支持改,需 Docker 版)
```

### 9.3 Funnel 不通

```bash
# 看 tailscale 状态
sudo tailscale status

# 看 Funnel 配置
sudo tailscale funnel status

# 重置 Funnel
sudo tailscale funnel reset
sudo tailscale funnel --bg 8418
```

### 9.4 推 Gitea 401/403

```bash
# 清旧 wincred 缓存
printf "protocol=https\nhost=ds923plus.tail58d872.ts.net\nusername=USER\n" | git credential reject

# 重试 push,弹窗输新 token
git push -u origin main
```

### 9.5 推 Gitea 404

- 仓不存在 → 创仓
- remote URL 错 → `git remote -v` 检查
- workbuddy user 没访问权限 → 站点管理 → 用户 → 改权限

---

## 📌 10. 关联资源

- **风险跟踪表**: `docs/风险跟踪表.md` 第十二节(Gitea 重建复盘)
- **贡献指南**: `CONTRIBUTING.md`(commit 规范 + PR 流程)
- **备份脚本**: `scripts/backup-gitea.sh`
- **预检脚本**: `scripts/pre-commit-check.sh`
- **workbuddy 任务清单**: `.workbuddy/memory/2026-06-14-批量任务.md`
- **workbuddy 满载任务**: `.workbuddy/memory/2026-06-14-今夜-满载任务.md`
- **Tailscale 私网**: `tail58d872.ts.net`
- **Funnel 域名**: `https://ds923plus.tail58d872.ts.net`

---

## 📌 11. 紧急联系

| 场景 | 联系人 |
|---|---|
| Gitea 套件问题 | 群晖技术支持(synology.com/support) |
| Tailscale Funnel | Tailscale 文档(tailscale.com/kb) |
| Token / 推送问题 | 项目负责人 宋献 |
| 仓数据丢失 | 走备份恢复(第 7 节) |

---

*本指南是 2026-06-14 卸载清空事件的产物,目的是不再让类似事件发生*
