Gitea
Github Repo
官方文档
Gitea 是什么
Gitea 是一个轻量的自托管代码平台,可以理解为自建版的 GitHub / GitLab 精简形态。它提供 Git 仓库托管、Issue、Pull Request、Wiki、Release、Package Registry 和 Actions 等功能。
这里的部署目标不是替代 GitHub 全生态,而是把 Gitea 作为自己的代码保险库:
- 直接 mirror GitHub 上的重要仓库。
- 当 GitHub 挂了、账号出问题或访问受限时,服务器上至少保留完整 Git 历史。
- 极少数个人私有库可以直接 push 到 Gitea。
- CI 仍然优先使用 GitHub Actions,并把计算任务交给自己的 GitHub self-hosted runner。
- Pages 不是核心需求;需要时可以继续用 GitHub Pages,或单独用 OpenResty / Nginx 托管静态站。
一句话:Gitea 在这里不是 GitHub 替身,而是 GitHub 代码资产的自主管理副本。
为什么选择 Gitea
同类选择主要有 GitLab、Forgejo、Gitea。
这套方案选择 Gitea 的原因:
- 比 GitLab 轻很多,更适合 VPS 和个人长期维护。
- 比 Forgejo 更大众,资料、教程、第三方经验更多。
- 开源核心是 MIT 许可证,同时项目有商业化团队和资金来源,长期维护能力相对清晰。
- 支持 GitHub repository mirror,适合做代码备份。
- 支持 Package Registry,偶尔放私有包或容器镜像也够用。
- Gitea Actions 存在,但不强行把 CI 从 GitHub Actions 迁走。
不选择 GitLab 的原因也很直接:GitLab 是完整 DevOps 平台,CI、Package、Pages 都强,但组件重、升级重、备份恢复复杂。对于个人代码备份,属于杀鸡用牛刀。
推荐架构
GitHub
├── 主仓库
├── GitHub Actions
└── GitHub self-hosted runner 使用自己的机器跑 CI
Gitea
├── mirror GitHub repositories
├── 保存少量个人私有库
├── SQLite
├── Docker Compose
└── /data 定时备份到另一位置这套架构的分工:
- GitHub:继续做公开协作、主仓、Actions 调度、Pages。
- Gitea:做自主管理的代码副本和私有仓库。
- GitHub self-hosted runner:只负责给 GitHub Actions 提供算力,不属于 Gitea。
注意:Gitea 不能直接调用 GitHub self-hosted runner。GitHub self-hosted runner 注册到 GitHub,只接受 GitHub Actions 调度。如果以后要在 Gitea 里跑 Actions,需要单独部署 Gitea act_runner。
部署方式选择
Gitea 官方支持 Docker Compose。个人自用建议先使用 SQLite,不额外引入 PostgreSQL / MySQL。
推荐部署结构:
/opt/gitea
├─ .env
├─ docker-compose.yml
├─ data/
└─ backups/其中:
data/是 Gitea 的核心持久化目录。- SQLite 数据库、仓库、附件、LFS、配置等都会在这个目录下。
backups/用来保存gitea dump和打包后的备份文件。
Docker Compose 模板放在这里:
前置准备
1. 准备目录
建议放在 /opt/gitea:
sudo mkdir -p /opt/gitea
cd /opt/gitea写入:
.env
docker-compose.yml2. 准备域名
建议给 Gitea 单独准备子域名:
git.example.com生产环境不建议直接暴露:
http://服务器IP:3000更合理的访问链路是:
用户 -> HTTPS 反向代理 -> 127.0.0.1:3000 -> GiteaSSH 端口可以单独暴露,例如:
服务器 2222 -> Gitea 容器 22以后 clone 地址类似:
git clone ssh://git@git.example.com:2222/用户名/仓库名.git首次初始化
启动:
cd /opt/gitea
docker compose up -d查看日志:
docker compose logs -f gitea浏览器打开:
https://git.example.com首次安装时重点检查:
Database Type: SQLite3
Site Title: 自己喜欢的名字
Server Domain: git.example.com
Gitea Base URL: https://git.example.com/
SSH Server Port: 2222第一次启动后 Gitea 会生成 /data/gitea/conf/app.ini。后续修改域名、端口、注册策略等配置时,优先改 .env 和 compose 里的 GITEA__section__KEY 环境变量,再重启容器;官方 Docker 镜像会在启动时把这些环境变量写入 app.ini。
不要随意删除 app.ini。它既是安装状态记录,也是 Gitea 的实际运行配置之一。
OpenResty 反向代理
如果使用 OpenResty,可以新建配置:
sudo nano /usr/local/openresty/nginx/conf/conf.d/gitea.confHTTP 到 HTTPS 跳转:
server {
listen 80;
server_name git.example.com;
return 301 https://$host$request_uri;
}HTTPS 反向代理:
server {
listen 443 ssl;
server_name git.example.com;
ssl_certificate /usr/local/openresty/nginx/conf/ssl/example.com.crt;
ssl_certificate_key /usr/local/openresty/nginx/conf/ssl/example.com.key;
ssl_protocols TLSv1.2 TLSv1.3;
client_max_body_size 512m;
location / {
proxy_pass http://127.0.0.1:3000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_connect_timeout 10s;
proxy_send_timeout 300s;
proxy_read_timeout 300s;
}
}检查配置:
sudo openresty -t重载:
sudo systemctl reload openrestyGitHub Mirror
Gitea 支持 repository mirror,可以把 GitHub 仓库定期拉到 Gitea。
适合本文目标的是 pull mirror:
GitHub -> Gitea创建方式:
- 右上角
+。 - 选择
New Migration。 - 选择 GitHub 或 Git。
- 填入 GitHub 仓库地址。
- 如果是私有仓库,填 GitHub Personal Access Token。
- 勾选
This repository will be a mirror。 - 创建迁移。
创建后,Gitea 会周期性从 GitHub 同步 branches、tags、commits。
注意:Gitea 官方文档明确提醒,pull mirror 只能在创建仓库时设置;仓库已经创建后,不能再直接转换成 pull mirror。
如果需要批量 mirror GitHub 个人账号下的大量仓库,可以使用 Gitea Mirror 作为 Gitea 官方 pull mirror 的 Web 管理器和 scheduler。
GitHub Token 权限
如果只 mirror public repo,可以不用 token。
如果 mirror private repo,需要 GitHub token。最小原则是:只给读取需要 mirror 的仓库所需权限,不要给过大的全局权限。
可以优先使用 Fine-grained personal access token,并限制到指定仓库。
私有仓库直接 push 到 Gitea
如果某些个人私有仓库不想放在 GitHub,或者担心 GitHub 容量限制,可以直接把 Gitea 当主 remote。
示例:
git remote add origin ssh://git@git.example.com:2222/用户名/private-repo.git
git push -u origin main也可以同时保留两个 remote:
git remote add origin git@github.com:用户名/repo.git
git remote add backup ssh://git@git.example.com:2222/用户名/repo.git平时 push GitHub:
git push origin main需要手动写入备份 remote:
git push backup mainGitHub Actions self-hosted runner
如果目标是免费使用自己的机器跑 CI,同时保持 GitHub Actions 兼容,推荐继续使用 GitHub Actions 的 self-hosted runner。
这和 Gitea 是两件事:
GitHub Actions -> GitHub self-hosted runner
Gitea Actions -> Gitea act_runner本文推荐只部署第一种。
在 GitHub 仓库或组织中添加 self-hosted runner 后,workflow 可以写:
runs-on: self-hosted更建议加自定义 label,避免误调度:
runs-on: [self-hosted, linux, x64, develata]安全建议:
- 不要让陌生 fork PR 自动跑 self-hosted runner。
- runner 上不要放长期高权限密钥。
- 公开仓库尽量使用 GitHub-hosted runner 或严格限制触发条件。
- 私有仓库和可信分支更适合使用自己的 runner。
Package Registry
Gitea 从 1.17 起支持 Package Registry,可作为 public 或 private registry 使用。
支持类型包括:
Container / OCI
Generic
Cargo
npm
PyPI
Maven
NuGet
Go
Helm
Debian
RPM
RubyGems
Terraform
Vagrant个人使用中最常见的是:
- Container Registry:保存自己构建的 Docker / OCI 镜像。
- Generic Package:保存 release 二进制、压缩包、构建产物。
- Cargo / npm / PyPI:保存少量私有包。
注意:Gitea 的 package 属于 user 或 organization,不是天然属于某个 repository;可以在 package 设置里 link 到 repository。
更新 Gitea
进入部署目录:
cd /opt/gitea拉取新镜像:
docker compose pull重建并启动:
docker compose up -d查看日志:
docker compose logs -f gitea清理旧镜像:
docker image prune -f建议不要使用 latest 做长期生产部署。可以固定到当前稳定版本,例如:
GITEA_IMAGE=docker.gitea.com/gitea:1.26.4升级前先备份 data/。
备份策略
Gitea 备份有两个层次:
- Gitea 官方
dump。 - 对整个
/opt/gitea/data做文件级备份。
官方文档说明,Gitea 当前有 dump 命令,但没有内置 restore 命令;恢复是手动过程。为了避免数据库、仓库和附件状态不一致,备份时最好停止 Gitea。
推荐脚本思路:
cd /opt/gitea
mkdir -p backups
docker compose stop gitea
tar -czf backups/gitea-data-$(date +%F-%H%M%S).tar.gz data
docker compose start gitea如果需要使用 Gitea 自带 dump:
docker compose exec --user git --workdir /tmp gitea \
gitea dump -c /data/gitea/conf/app.ini然后把容器里的 dump 文件复制出来,或在脚本中统一移动到 backups/。
最小异地备份建议:
每天备份 /opt/gitea/data
保留 7 个 daily
每周同步到另一台 VPS 或本地电脑如果仓库很重要,Gitea 服务器本身不应是唯一副本。
常见问题
1. 容器启动失败,提示权限问题
Gitea Docker 文档要求挂载目录归 USER_UID / USER_GID 对应用户所有。
本文默认:
USER_UID=1000
USER_GID=1000如果宿主机部署用户不是 1000,需要修改 .env,或者调整目录权限。
2. 网页能打开,但 SSH clone 失败
检查三件事:
ssh -T -p 2222 git@git.example.comdocker compose psdocker compose logs -f gitea确认:
- compose 里
GITEA_SSH_HOST_PORT=2222。 - 云服务器安全组放行 2222。
- Gitea 管理后台 / app.ini 里的 SSH 端口和实际端口一致。
- 用户 SSH public key 已经添加到 Gitea。
3. Mirror 私有 GitHub 仓库失败
常见原因:
- GitHub token 权限不足。
- token 没有授权到目标 private repo。
- 仓库 URL 写错。
- 目标仓库需要 SSO 授权。
- GitHub 访问被网络阻断。
先在服务器上测试:
git ls-remote https://github.com/用户名/仓库名.git私有仓库则需要带 token 的认证方式,注意不要把 token 写进 shell history 或公开文档。
4. 直接把 3000 暴露到公网可以吗
不建议。
更推荐:
HOST_IP=127.0.0.1
GITEA_HTTP_HOST_PORT=3000
OpenResty / Nginx / 1Panel 反向代理 HTTPS这样公网只看到 80/443,Gitea 后端端口只在本机访问。
5. 要不要启用 Gitea Actions
当前方案不需要。
原因:你真正需要的是 GitHub Actions 兼容,而最兼容的方式就是继续用 GitHub Actions,并把 runner 放到自己的机器上。
只有当你想让 Gitea 本身调度 CI 时,才需要部署 Gitea act_runner。
推荐配置
个人自用代码保险库建议:
HOST_IP=127.0.0.1
GITEA_HTTP_HOST_PORT=3000
GITEA_SSH_HOST_PORT=2222
GITEA_DOMAIN=git.example.com
GITEA_ROOT_URL=https://git.example.com/
GITEA_DISABLE_REGISTRATION=true
GITEA_REQUIRE_SIGNIN_VIEW=true含义:
- HTTP 只监听本机,通过反代访问。
- SSH 单独暴露 2222。
- 关闭公开注册。
- 未登录用户不能浏览私有内容。
- SQLite 作为默认数据库,减少组件。