gitea换服务器完整迁移方案

一、迁移前准备(新旧机都要看)

  1. 记录旧机信息
    • Gitea 版本:docker exec gitea gitea --version
    • 数据库连接:库名/用户/密码/Host/端口(你的是宿主机 MySQL8,比如 10.10.0.8:3306 或新机内网 IP)
    • 数据卷路径:compose 里 ./gitea-data:/data,实际在宿主机 ~/gitea/gitea-data
    • 关键配置:DOMAIN / ROOT_URL / SSH_DOMAIN / SSH_PORT / SSH_LISTEN_PORT / LFS路径 / 附件路径
    • 是否开 Actions、LFS、包仓库、Webhook、OAuth、LDAP
  2. 新机预装
    • Docker + compose
    • 宿主机 MySQL8(字符集 utf8mb4、collation 建议 utf8mb4_bin,InnoDB、DYNAMIC),或者继续用老机 MySQL 只改授权也行
    • 若新机也用宿主机 MySQL,提前建库建用户并授权来自 Gitea 容器网段
  3. 原则
    • 先装“和旧机完全相同大版本”的 Gitea 再迁数据,迁完验证后再升级;跨大版本升级容易踩 schema 坑。
    • 迁移期间旧机停 Gitea(或只读),避免 dump 后又有新提交。

二、方案 A:官方 gitea dump 全量(最省事)

1)旧机备份

cd ~/gitea
# 停服务保证一致(小实例也可不停,但建议停)
docker compose stop gitea

# 进容器用 git 用户 dump,输出在 /data/backups 或 /tmp
docker exec -u git -it gitea sh -c 'cd /data/backups && /usr/local/bin/gitea dump -c /data/gitea/conf/app.ini'
docker compose start gitea   # 如果刚才停了,现在可先起回;传完再最终停

dump 会生成 gitea-dump-时间戳.zip,里面含:

  • app.ini(配置)
  • gitea-db.sql(数据库逻辑备份;MySQL 模式可直接导回 MySQL)
  • repos/(所有仓库)
  • data/(附件、LFS、头像、配置等,视版本而定)

拷出来:

docker cp gitea:/data/backups/gitea-dump-xxxx.zip ./gitea-dump-xxxx.zip
scp ./gitea-dump-xxxx.zip newserver:~/gitea-backup/

如果你只想要数据库备份而不走 dump,也可以单独 mysqldump(见方案 B)。但仓库、附件、LFS、hooks 还是建议跟 dump 一起拿。

2)新机恢复

新机先起一个“空 Gitea”把卷结构建出来,或者直接把数据写进卷再起。

# 新机 ~/gitea 放好 docker-compose.yml(同版本镜像),先不依赖旧库
docker compose up -d gitea      # 让它生成 /data 结构,或你直接建空目录也行
docker compose stop gitea       # 恢复前停掉

# 把 zip 放进容器或解到宿主机再拷
mkdir -p /tmp/restore && cd /tmp/restore
cp ~/gitea-backup/gitea-dump-xxxx.zip .
unzip gitea-dump-xxxx.zip       # 得到 app.ini、gitea-db.sql、repos/、data/ 等

恢复数据(Docker 默认卷映射 ./gitea-data:/data,按你实际路径改):

# 配置
cp /tmp/restore/app.ini ~/gitea/gitea-data/gitea/conf/app.ini
# 通用数据(附件/LFS/头像等)
cp -r /tmp/restore/data/* ~/gitea/gitea-data/gitea/ 2>/dev/null || true
# 仓库
mkdir -p ~/gitea/gitea-data/git/repositories
cp -r /tmp/restore/repos/* ~/gitea/gitea-data/git/repositories/
# 内置SSH密钥目录(若用内置ssh)保留 .ssh
cp -r /tmp/restore/data/git/.ssh ~/gitea/gitea-data/git/.ssh 2>/dev/null || true

chown -R 1000:1000 ~/gitea/gitea-data   # 容器默认 git 1000:1000,按USER_UID/GID改

恢复 MySQL(宿主机 MySQL8):

# 新机MySQL建库
mysql -uroot -p -e "CREATE DATABASE gitea CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;"
mysql -uroot -p -e "CREATE USER 'gitea'@'172.17.0.0/255.255.0.0' IDENTIFIED BY '强密码'; GRANT ALL ON gitea.* TO 'gitea'@'172.17.0.0/255.255.0.0'; FLUSH PRIVILEGES;"

# 导入 dump 里的 sql
mysql --default-character-set=utf8mb4 -uroot -p gitea < /tmp/restore/gitea-db.sql

如果 dump 出来的是其他库类型 SQL、而你要用 MySQL,官方不推荐转库迁移,最好旧机本身就是 MySQL 再 dump。

改 app.ini 适配新内网 IP(见第四节)。

起服务并重建 hooks:

cd ~/gitea
docker compose up -d
docker compose exec --user git gitea gitea -c /data/gitea/conf/app.ini admin regenerate hooks
docker compose exec --user git gitea gitea -c /data/gitea/conf/app.ini doctor check --all --fix

regenerate hooks 是跨机迁移必做,否则 push 时 hook 路径/容器路径不对会失败。

三、方案 B:手工分件(宿主机 MySQL 独立,最清晰)

适合你这种“MySQL 不在容器里”的情况。

1)旧机导出

MySQL:

mysqldump -h127.0.0.1 -P3306 -uroot -p --single-transaction --routines --triggers --default-character-set=utf8mb4 gitea > gitea-mysql-$(date +%F).sql

Gitea 文件(按你卷路径,默认 Docker 映射 ./gitea-data:/data):

cd ~/gitea
tar czf /tmp/gitea-data.tgz gitea-data
# 重点目录:gitea-data/git/repositories、gitea-data/gitea(配置/附件/lfs/avatar)、gitea-data/git/.ssh(内置ssh)

传新机:

scp gitea-mysql-*.sql newserver:~/mig/
scp /tmp/gitea-data.tgz newserver:~/mig/

2)新机导入

MySQL:

mysql -uroot -p -e "CREATE DATABASE gitea CHARACTER SET utf8mb4 COLLATE utf8mb4_bin;"
mysql -uroot -p gitea < ~/mig/gitea-mysql-*.sql
# 按新Gitea容器源段建用户
mysql -uroot -p -e "CREATE USER 'gitea'@'172.17.0.0/255.255.0.0' IDENTIFIED BY '强密码'; GRANT ALL ON gitea.* TO 'gitea'@'172.17.0.0/255.255.0.0'; FLUSH PRIVILEGES;"

Gitea 数据:

cd ~/gitea
rm -rf gitea-data   # 若是全新空卷;要保留旧结构也可只覆盖子目录
tar xzf ~/mig/gitea-data.tgz -C ~/gitea   # 解出 gitea-data/
chown -R 1000:1000 ~/gitea/gitea-data

compose 里数据库 HOST 指向新机 MySQL 内网 IP(或 host.docker.internal+extra_hosts),启动后 regenerate hooks、doctor check。

四、改配置:内网 IP 场景

新机如果用 10.8.0.1 内网访问,恢复后改 gitea-data/gitea/conf/app.ini:

[server]
DOMAIN     = 10.8.0.1
ROOT_URL   = http://10.8.0.1:3000/
SSH_DOMAIN = 10.8.0.1
SSH_PORT   = 222
SSH_LISTEN_PORT = 22
HTTP_PORT  = 3000

[database]

DB_TYPE = mysql HOST = 10.10.0.8:3306 ; 新机MySQL内网/VPN IP,或127.0.0.1但容器要能通 NAME = gitea USER = gitea PASSWD = 强密码

[lfs]

PATH = /data/git/lfs ; 按你旧值保持,若换路径要同步移文件

用环境变量方式就把对应项改成:

- GITEA__server__DOMAIN=10.8.0.1
- GITEA__server__ROOT_URL=http://10.8.0.1:3000/
- GITEA__server__SSH_DOMAIN=10.8.0.1
- GITEA__server__SSH_PORT=222
- GITEA__server__SSH_LISTEN_PORT=22
- GITEA__database__HOST=10.10.0.8:3306

注意:环境变量会在运行时覆盖 app.ini 同名项;如果你两处都设,以环境变量优先,避免改了 ini 不生效。

五、秘钥和 SSH 不要重新生成

app.ini 里这些必须原样迁移,别换新,否则旧 token、LFS JWT、内部API、session 全废:

  • SECRET_KEY
  • INTERNAL_TOKEN
  • JWT_SECRET / LFS 相关 JWT
  • 如果用内置 SSH:/data/git/.ssh 的 host key 和 authorized_keys 一起拷;用系统 sshd 则恢复后执行 gitea admin regenerate keys 重写 authorized_keys。

六、启动后验证清单

docker compose ps
docker compose logs -f gitea

功能核查:

  • 网页打开 http://10.8.0.1:3000,管理员登录,看组织/用户/仓库数是否和旧机一致
  • 随机进几个仓库,看代码、Issues、PR、附件、头像、LFS 文件
  • SSH 克隆:git clone ssh://git@10.8.0.1:222/xxx/yyy.git,能拉能推
  • HTTP 克隆:git clone http://10.8.0.1:3000/xxx/yyy.git
  • 有 Actions:后台 Runners 重新注册(runner 不随 Gitea 数据迁移,换机要重装 act_runner 并用新 token 注册)
  • Webhook:如果旧 hook 指向旧 IP/域名,逐个改;迁移后可用 doctor 检查
  • LFS:随便 pull 一个大文件验证

七、常见翻车点

  • 只导了 MySQL 没拷 repositories → 网页能登但仓库空/报错
  • 只拷 /data 没导 MySQL → 用户/issue/配置全无
  • 版本不一致直接迁 → schema migrate 失败;先同版本,再升级
  • 用系统 sshd 但没 regenerate keys/authorized_keys → SSH 克隆报权限拒绝
  • 内置 SSH 但新机映射端口不是 222,SSH_PORT 仍写 22 → 克隆地址对但连不上
  • MySQL 只监听 127.0.0.1,容器用 10.x 连 → 改 bind-address 或走 host-gateway
  • 文件权限不是 1000:1000(或你 compose 设的 USER_UID/GID) → 容器起不来/仓库只读
  • LFS 存在对象存储/S3:只迁数据库不够,要确认 LFS_CONTENT_PATH 或 S3 凭证在新机可用

Comments

No comments yet. Why don’t you start the discussion?

发表回复