备份、恢复和升级 Gitea 实例
本文合并翻译整理 Gitea 官方文档的 Backup and Restore 与 Upgrade from an old Gitea,作者归属 Gitea 文档贡献者。核对日期为 2026 年 10 月 5 日。两个来源都是会更新的文档 URL;文中的 2016 年日志、2021 年归档名和 1.4/1.5 升降级表是历史示例,不代表当前推荐版本。
Gitea 的一次操作可能同时改数据库、文件和 Git 仓库。备份只成功导出 SQL,或只压缩了仓库目录,都不足以证明整个实例可以恢复。可靠的运维过程应先停止写入,保存相互一致的数据库、配置、仓库和附件,再在隔离环境中恢复验证;升级失败时,要能回到配套的旧程序和旧数据。

为什么备份时要关闭实例
官方明确要求在备份期间关闭 Gitea,以确保一致性。例如迁移仓库时,数据库里已经创建了记录,但仓库文件仍在复制;如果在复制中途打包仓库,稍后才导出数据库,SQL 会声称仓库存在,归档里的仓库却可能不完整。这是跨数据库和文件系统的竞争条件,单独导出数据库并不能消除。
因此要先安排维护窗口、停止实例和相关写入,再保存数据。原文并没有提供“在线 dump 等于原子快照”的保证。云服务或文件系统快照可以让备份更方便,但必须覆盖相互依赖的数据卷和对象存储,保证它们的时间点及写入边界一致。
使用 dump 生成归档
Gitea 提供 dump 命令,将安装数据保存为 ZIP。用运行 Gitea 的系统账号执行,例如原文的 su git,然后进入 Gitea 安装目录并指定真实的配置文件:
./gitea dump -c /path/to/app.ini
这是一条文档参数示例,/path/to/app.ini 必须替换为经确认的路径。它会创建临时工作目录、导出本地仓库及数据库,打包为 gitea-dump-时间戳.zip 并清理临时目录。原文的成功日志来自 2016 年,本文没有运行 dump,不能把那份日志当作本次成功证据。
临时文件可通过 --tempdir 指定位置,或由进程的 TMPDIR 环境变量控制。临时目录需要足够空间,并且只有适当用户能访问。备份包、临时文件和 SQL 可能包含私人仓库、令牌、密码及密钥,应限制权限并对存储和传输采取保护措施。
| 归档内容 | 说明 |
|---|---|
app.ini |
配置原本位于默认 custom 目录之外时,可额外包含一份配置文件。 |
custom/ |
custom 目录中的配置和自定义内容。 |
data/ |
APP_DATA_PATH 数据;不包含使用文件会话时的 sessions。可包括 attachments、avatars、lfs、indexers,以及使用 SQLite 时的数据库文件。 |
repos/ |
仓库目录的完整副本。 |
gitea-db.sql |
数据库 SQL 导出。 |
log/ |
日志;恢复或迁移本身不要求这些日志,但其中可能有敏感信息。 |
是否完整仍取决于实际配置。外部 S3、MinIO 或其他对象存储不应被想当然地算进 ZIP。升级指南明确把它们列为独立备份项。还应记录程序版本、部署方式、实际目录、存储配置和账号映射;仅保存归档文件名不够。
数据库导出:认识 XORM 的恢复限制
gitea dump 通过 XORM 生成 SQL。官方说明此导出路径仍有可能影响恢复的问题,因此管理员可以选择 MySQL 或 PostgreSQL 原生导出工具。原文示例把 MySQL 密码写成 -p$PASS;这样可能使密码进入进程参数、脚本或历史记录。下面是编辑调整后的命令结构:MySQL 使用受限配置文件,PostgreSQL 使用其标准认证机制,而不在命令行嵌入密码。
# 示例库名 gitea;路径与账号须按隔离验证环境调整。
# MySQL 的 defaults-extra-file 应是仅运行账号可读的客户端配置。
mysqldump --defaults-extra-file=/secure/backup-client.cnf --databases gitea > gitea-db.sql
# PostgreSQL 使用交互式认证或妥善保护的标准凭据文件。
pg_dump --username=gitea --dbname=gitea --file=gitea-db.sql
受限配置文件也会含秘密,不能随文章、工单或公共备份暴露。原生数据库导出必须与仓库和文件处于同一停写窗口;只换导出工具并不会自动解决跨组件一致性。恢复前检查 SQL 是针对单库、包含建库语句,还是包含切换数据库语句;尤其 MySQL 的 --databases 导出可能包含 CREATE DATABASE/USE,不能只在导入命令里改个库名,就假定所有语句会进入新库。
Docker 中执行 dump 的两个路径
容器内的运行用户必须与 app.ini 中 RUN_USER 相符。原文还要求 docker exec 的工作目录与 dump 的临时目录匹配,否则打包阶段可能遇到权限错误。这里的路径是容器内部路径,并不是宿主机的临时目录。
原文命令使用 $(docker ps -qf ...) 动态选择容器。为避免匹配结果为空或多个容器时执行到错误目标,下面编辑版直接要求一个已确认的容器名,并显式指定临时目录:
# 仅示例;gitea-example、git、配置路径和临时目录均需核对。
docker exec --user git --workdir /tmp gitea-example /usr/local/bin/gitea dump -c /data/gitea/conf/app.ini --tempdir /tmp
如果主容器已经完全停止,docker exec 不能在它上面运行。实际维护流程需要停止 Gitea 写入进程而保留合适的容器执行环境,或使用同版本的一次性维护容器挂载备份所需卷;具体方式由部署决定,不能为了运行 exec 而重新开放业务写入。此处是为满足官方“停机一致性”要求增加的编辑说明。
未自定义临时目录时,原文使用容器的 /tmp 或 TMPDIR。完成后确认 ZIP 真实位置、大小和内容,再把归档带出临时容器并安全保存。容器删除不应带走唯一备份。
恢复是手工过程,标题不是 restore 命令
虽然官方章节标题写着 Restore Command (restore),正文明确说明当前没有自动恢复命令。流程是把归档中的文件放回正确位置,再恢复数据库。恢复应先在隔离目标进行,使用备份时的兼容版本;确认目录、数据库和权限都符合预期后再切换服务。
- 先保留现有实例和数据的独立副本,确保服务停写。准备空的恢复目标,核实归档来源与完整性。
- 检查 ZIP 文件清单,在专用暂存目录解压。对于不可信归档,还要检查路径穿越和绝对路径;本篇只使用已授权、来源明确的备份。
- 根据配置映射 app.ini、custom、data、repos 等内容;不要照搬示例路径。原文用
mv data/*等命令,可能覆盖目标,也可能漏掉隐藏项。编辑版用明确的目录映射和逐项核对说明,避免把这组命令当成通用恢复脚本。 - 核对导入 SQL 的数据库类型、编码、账号和目标库,确认不会改写源生产库。按所选数据库工具恢复。
- 核对运行用户、组、文件权限与存储挂载,再启动 Gitea,检查日志及实际功能。
只查看和解压归档的示例结构如下;文件名沿用原文历史示例,不表示该备份已存在于你的机器。
unzip -l gitea-dump-1610949662.zip
unzip gitea-dump-1610949662.zip -d ./gitea-restore-staging
| 部署形态 | 原文示例目标位置 |
|---|---|
| 二进制/服务安装 | 配置 /etc/gitea/conf/app.ini;数据 /var/lib/gitea/data/;仓库 /var/lib/gitea/data/repositories/;日志 /var/lib/gitea/log/。 |
| 普通 Docker | 数据 /data/gitea;仓库 /data/git/repositories/;配置通常 /data/gitea/conf/app.ini。 |
| Docker rootless | 配置 /etc/gitea/app.ini;数据 /var/lib/gitea;仓库 /var/lib/gitea/git/repositories。 |
原文的普通容器默认账号是 git、UID:GID 为 1000:1000;这是该镜像示例的默认值,不能覆盖实际部署的自定义账号映射。rootless 还可能涉及宿主机用户命名空间映射。递归 chown 前必须确认解析后的绝对路径、挂载内容和当前拥有者,不能盲目对宽泛目录操作。本文没有运行任何权限修改或覆盖命令。
数据库恢复与错误处理
原文分别给出 MySQL、SQLite 和 PostgreSQL 的导入形式。以下保留其用途,同时把 MySQL 密码改为交互提示,把 PostgreSQL 的“出错就停”设为客户端参数。gitea_restore 是隔离演练用示例名;是否适用于实际 SQL,须先按上一节检查建库和切库语句。
# MySQL:--password 不带值,交互提示密码。
mysql --default-character-set=utf8mb4 --user=gitea --password gitea_restore < gitea-db.sql
# SQLite:目标是专用恢复文件;导入前确认文件与语句兼容。
sqlite3 /isolated/restore/gitea.db < gitea-db.sql
# PostgreSQL:ON_ERROR_STOP 是 psql 客户端设置。
psql --set=ON_ERROR_STOP=on --username=gitea --dbname=gitea_restore --file=gitea-db.sql
这些只是不同工具的命令形态,不能混用三种数据库的 SQL,也不能假定中途失败会自动撤销所有已执行语句。失败时保留日志并重建干净的隔离目标再排查,避免在不确定的半恢复状态上继续叠加导入。原文最后用 service gitea restart 重启;实际服务管理器、容器入口和配置路径要与部署一致。
更换路径或部署方式后,重建 Git hooks
从二进制切到 Docker,或更改安装目录后,仓库 hooks 内的程序和配置路径可能仍指向旧位置,导致 push 失败。官方建议在 Gitea 运行时,从程序所在目录执行重建:
./gitea admin regenerate hooks
# 普通 Docker 示例对应的配置路径:
/usr/local/bin/gitea -c /data/gitea/conf/app.ini admin regenerate hooks
# rootless 示例对应的配置路径:
/usr/local/bin/gitea -c /etc/gitea/app.ini admin regenerate hooks
三条是不同部署情形的选项,不是依次执行的步骤。重建前应备份并核对自定义 hooks,避免自动生成内容覆盖本地定制;命令需以适当账号、正确配置指向恢复目标。仍有问题时可用 gitea doctor check 检查。原文提到 --fix,但它会修改数据,不应在未审阅诊断与备份状态时盲目执行。
跨数据库类型转换:保留为实验性附录
gitea dump --database postgres 能生成目标数据库格式的 SQL,官方明确说此转换流程没有充分测试,建议初次安装就选定最终数据库类型。它不应和常规备份恢复、版本升级混成一次不可分辨的变更。
原文步骤是:停止服务,完整备份原库;用 doctor 修复常见问题,包括 doctor check --all --fix 和 doctor recreate-table;生成目标格式 dump,提取 SQL;创建 PostgreSQL 用户与数据库;导入后修改 Gitea 数据库配置并启动。
这些 doctor 命令及转换都会改数据,本文仅解释,不执行。先在副本上检查具体诊断、约束、索引、编码和行数等差异,不能把“导入命令退出”当成转换正确的证明。
原文命令有一处需要纠正:SET on_error_stop TO on 不是设置 psql 客户端错误处理的正确 SQL。应使用 psql 的 \set ON_ERROR_STOP on 或上文的 --set=ON_ERROR_STOP=on。原文还为加速导入建议 SET synchronous_commit TO off;它会降低崩溃时的提交持久性,本文没有把它纳入默认恢复命令,也没有声称加速幅度或可靠性已验证。
升级之前,检查改变与回退条件
先读目标版本的 Gitea changelog,特别是重大版本的 breaking changes,再检查管理界面的弃用配置警告。官方说明这类警告通常至少提前一个发布周期显示;如果一直不处理,下个版本可能拒绝启动。
数据库结构决定能否降级。原文用 a.b.x → a.b.y 表示同一小版本系列的补丁升级,数据库结构通常兼容;但即使补丁降级可能可行,也不推荐没有备份就冒险。跨 a.b → a.c 升级可能进行数据库结构迁移,迁移后的数据库不能直接交给旧程序使用。
| 原文历史示例 | 含义 |
|---|---|
1.4.0 → 1.4.1 |
补丁升级示例。 |
1.4.1 → 1.4.0 |
即使结构没变也不推荐无备份降级。 |
1.4.x → 1.5.y |
升级时数据库会迁移。 |
1.5.y → 1.4.x |
不能直接使用已经升级的数据库,需恢复旧备份。 |
这些数字只用于解释兼容边界,不建议部署这些历史版本,也不承诺任意跨多个大版本都能一步升级。生产实例无论补丁升级还是跨系列升级,都应先做一致性备份。
官方升级备份清单包含:停止实例、数据库、Gitea 配置、APP_DATA_PATH 文件,以及外部 S3/MinIO 等存储。仓库必须按真实配置纳入;还应保存旧二进制或固定镜像版本及部署配置,才能恢复成相互匹配的一套系统。
按部署方式完成升级
- Docker:提前拉取确定的目标发布镜像;停止运行实例、完成备份;用原部署方式启动新版本容器。原文写的是拉取最新发布,本文编辑建议固定已评估的版本/镜像身份,避免移动标签使维护窗口中的目标改变。
- 软件包:停止并备份后,通过当前系统包管理器升级,再启动服务。注意分发包的维护脚本及服务自动重启行为,要与停写计划一致。
- 二进制:将目标程序下载到临时目录,核对来源;停止旧服务并完成备份,然后替换程序并启动。原文链接 contrib/upgrade.sh 作为自动化参考,本文未审查或执行该外部脚本,不将它计入本次经过静态审核的代码。
Gitea 每次启动都会检查数据库版本,并自动执行需要的迁移。第一次启动可能因库大小而更慢,迁移期间服务不可用;不要仅因为启动时间变长就反复强杀和重启。应监控迁移日志,并按预先演练的恢复流程处理失败。
自定义模板和升级后的检查
版本之间模板结构与变量可能改变。不兼容的自定义模板会导致 50x 错误、组件缺失、交互异常或布局错乱。应按目标版本更新或撤下不兼容模板,保留旧版本副本以便分析。
编辑补充的验收范围包括登录、仓库列表、clone/fetch/push、权限、issue 与附件、LFS、对象存储、webhook/任务集成和自定义页面。按实例实际启用功能选择检查;本次没有执行这些验收,也没有宣称备份可用或升级成功。若需回退,恢复旧程序、旧数据库及同一备份时点的配套文件,而不是简单把二进制换旧。
来源、许可与本次验证
本文覆盖两篇官方文档的所有主题:停机一致性、dump 内容、原生数据库备份、Docker、三类手工恢复路径、hooks、doctor、数据库转换、升级兼容、各安装方式以及模板变化。原文可能覆盖目标目录的命令改为逐项映射说明;密码参数、容器选择、psql 错误处理和同步提交策略的差异均已明确标注。
Gitea 文档仓库 LICENSE 采用 Apache License 2.0;完整许可证文本随稿提供。保留 Gitea 文档贡献者归属;本文是中文翻译整理,含上述编辑修改。原创图由未完纪制作。
本次只读取资料与静态审查命令,没有连接数据库、读取私人仓库、运行 dump/恢复/doctor、修改权限、升级容器或执行下载的脚本。发现并标注的风险不等于完整安全审计;没有发现其他问题也不代表没有漏洞。











暂无评论内容