Gitea 是一个用 Go 编写的开源 Git 服务,前端界面清爽,后端只靠一个二进制文件就能跑,特别适合放在本地服务器或者公司内网上,作为一个完全自主可控的 Git 私有服务器来用。它解决的核心问题很简单:团队代码不想交给第三方托管,又不想为了一台 Git 服务专门配置 GitLab 那种重型平台,同时还要有 Web 端能看代码、管权限、发通知。这篇文章从选型对比讲起,覆盖二进制、Docker、Windows 三种部署方式,再把初始化配置、权限管理、LFS 支持、备份恢复和常见坑一条条过一遍。不管你是刚接触自建 Git 服务的初学者,还是已经在用其他方案、想换到 Gitea 的开发者,这篇都能帮你少走不少弯路。
1. 为什么非要用 Gitea?自建 Git 服务器方案对比
先讲选型,因为很多人第一步就卡住了。市面上能自建的 Git 服务其实不少,但真正适合本地/内网场景的,Gitea 几乎是绕不开的答案。
1.1 GitLab 太重,云托管平台又不放心
GitLab 功能确实全:CI/CD、镜像仓库、Wiki、看板都有,但缺点是重。官方建议服务器至少 4GB 内存,而内网小团队共用的机器往往只有 1~2G 内存,跑起来经常把其他服务挤死。另外 GitLab 虽然是开源软件,但升级和配置复杂度比 Gitea 高一个量级,光是一个 omnibus 包更新可能就要折腾半天。如果你没有专职运维,大概率会被它耗掉大量精力。
云托管平台的特点是“零维护、开箱即用”,但代码放在别人机房,内网隔离需求就完全没法满足。很多公司对代码出境、数据主权有非常严格的要求,代码必须留在自己的内网,这时候自建是唯一选择。如果只是个人自己玩,买一台云服务器搭 Gitea 也是一个轻量又低成本的办法。还有一点,自己托管的服务器完全由你控制,不依赖第三方平台的仓库限额和访问策略。
1.2 裸 Git 仓库解决不了团队协作
在 Linux 服务器上建一个git --bare仓库,配合 SSH 也能用,这是最古老也最朴素的方案。如果你是个人存代码、或者团队只有两三个人且都能接受命令行,那裸仓库完全够用。可一旦人多起来,问题就出来了:没有 Web 界面,新人要看代码只能 clone 下来;没有权限管理,所有人进来都是能 push 全部分支;没有 code review、issue 追踪、CI 联动,协作基本靠自觉。
Gitea 把这些都补齐了,而且不需要额外安装数据库服务。默认 SQLite 就够了,想要更强的并发再切 PostgreSQL。它内置 SSH 服务,用户上传自己的公钥就能用标准的 git 协议推送,不需要给系统账号。对于内网小团队,这一套正好卡在“功能够用”和“不折腾”之间。
1.3 Gitea 的技术底子和社区生态
Gitea 用 Go 开发,这意味着它在资源消耗上有明显优势:单二进制分发、没有复杂运行时依赖,部署就是拷贝一个文件。小团队或者家用小机器比如树莓派、NAS 都能轻松跑。它兼容 Git 所有标准操作,还提供 HTTP API,可以对接内部研发流程工具。现在的社区生态里还有 Forgejo 这个分支,如果你对项目治理比较在意,可以了解一下;我身边大部分人用 Gitea 只是图稳定和顺手。从功能覆盖来看,Gitea 提供的仓库管理、用户体系、Issue、PR、Webhook、内置 CI,足够支撑一个几十人规模的研发部门。
2. 部署前要准备的几件事
别急着下载安装,先把下面四点定了,后面会少很多返工。
2.1 服务器选型和资源底限
一台 1 核 1G 内存的服务器跑 Gitea 毫无压力,十几个人同时用也够。真正的瓶颈在磁盘:Git 仓库是增量存储,但 LFS 大文件、构建产物、附件、数据库都会吃空间。建议按每人 5G-10G 的仓库空间预估,另外预留 20% 余量。数据库类型上,团队 30 人以内无脑 SQLite;如果你准备接入自动化构建、并发请求多,选 PostgreSQL 会更稳。MySQL 也行,但没太大必要特意选。
操作系统的选择不挑,Ubuntu/Debian 有现成的 systemd 模板,CentOS/Rocky 注意 SELinux 放行规则即可。更省心的是 Docker 部署,资源隔离和迁移都很方便。我见过有人在旧笔记本上跑 Gitea 给全家用,也见过在内网服务器上跑了几十个人的仓库,性能都没出过问题。
2.2 网络与端口规划
内网 Gitea 默认 Web 端口是 3000,SSH 端口默认跟随系统 SSHD 共用 22。如果你不想动系统 SSH,可以给 Gitea 单独分配一个端口,比如 2222,或者在防火墙上把 22 直接映射到 Gitea 内置 SSH 服务。我建议的做法是:Web 用 80/443 通过 Nginx 反向代理暴露,SSH 保留 22 或独立 2222,看你的网络环境。这样用户访问地址是http://git.local而不是http://git.local:3000,记忆成本低很多。
另外提前想好主机名,比如git.local。多人协作时用 hosts 文件或内网 DNS 统一解析。如果连 hosts 都没配,每个人 clone 时填 IP,后续换机器 IP 变更,所有 remote 地址都要改。别小看这个细节,我见过一个团队因为域名没提前规划,迁移服务器后手动改了几十个人的 remote 地址。
2.3 运行账号与数据目录
不要用 root 跑 Gitea。规范做法是新建一个专门账号git,并把数据目录、仓库目录、日志目录都归到该账号下。这样即便应用被攻破,也只是 git 账号权限,不会影响系统其他服务。数据目录我习惯统一放在/var/lib/gitea下,custom 放自定义配置,data 放数据库和附件,log 放日志。目录结构提前规划好,备份时就知道该拷贝哪些东西。
3. 三种安装方式,按场景选
Gitea 的安装方式很灵活,没有一种方式适合所有人,我按实际场景拆开说。
3.1 Linux 二进制安装
下载官方 release 二进制文件,授权可执行,然后放进 PATH:
apt update && apt install -y git sqlite3 useradd -m -s /bin/bash git mkdir -p /var/lib/gitea/{custom,data,log} chown -R git:git /var/lib/gitea wget https://github.com/go-gitea/gitea/releases/download/v1.22.x/gitea_1.22.x_linux_amd64 chmod +x gitea_1.22.x_linux_amd64 install -o root -g root -m 755 gitea_1.22.x_linux_amd64 /usr/local/bin/gitea注意,这一条命令里的版本号只是示例,去 releases 页面拿最新的稳定版。接着写一个 systemd service 文件,放到/etc/systemd/system/gitea.service:
[Unit] Description=Gitea(Git with a cup of tea) After=network.target [Service] User=git Group=git WorkingDirectory=/var/lib/gitea ExecStart=/usr/local/bin/gitea web --config /etc/gitea/app.ini Restart=always Environment=USER=git HOME=/home/git [Install] WantedBy=multi-user.target然后执行systemctl daemon-reload && systemctl enable --now gitea,浏览器访问http://IP:3000进入初始化页面。如果端口不通,检查防火墙:ufw allow 3000。二进制方式的好处是干净,没有多余依赖,出问题好排查,适合对服务器有洁癖的人。
3.2 Docker Compose 安装
已有 Docker 环境的话,我更喜欢容器方式。一个 docker-compose.yml 文件就能搞定:
version: "3" services: gitea: image: gitea/gitea:latest container_name: gitea restart: always environment: - USER_UID=1000 - USER_GID=1000 - GITEA__SERVER__DOMAIN=git.local - GITEA__SERVER__ROOT_URL=http://git.local/ - GITEA__SERVER__SSH_PORT=2222 - GITEA__SERVER__LFS_START_SERVER=true volumes: - ./gitea-data:/data - /home/git/.ssh:/data/git/.ssh:ro ports: - "3000:3000" - "2222:2222"执行docker compose up -d完事。关键点有两个:一是/data卷要持久化,容器删了重建数据还在;二是时区问题,最好挂载/etc/localtime,否则容器日志和 Web 界面的时间显示可能差 8 小时。USER_UID和USER_GID要和宿主机想要的文件属主一致,否则后续备份恢复时文件权限会乱。
3.3 Windows 本地运行
Windows 上跑 Gitea 最简单的方式是下载 exe,双击运行gitea web,它会自动监听 3000 端口。如果想让服务在后台常驻,用 NSSM 把它注册成 Windows 服务。现在 Windows 也能用包管理器安装:scoop install gitea。
个人本地使用或者家庭内网,Windows 这种方式完全够。注意 Windows 下路径分隔符不要混用,app.ini 里的路径建议写绝对路径,例如D:\Gitea\data。还有防火墙弹窗要允许专用网络访问,否则其他设备连不上。团队主力机如果是 Windows Server,这种部署方式的优点是图形界面操作直观,缺点是作为正式服务稳定性不如 Linux 下 systemd 管理。
4. 初始化与关键配置
第一次打开页面会进入安装向导,这里选错后面很难改,值得重点说。
4.1 安装向导里的几个选择
数据库默认是 SQLite,30 人以内直接选它,零维护。站点名称随意,仓库根目录保持默认即可。最容易被忽略的是“SSH 端口”,如果你的 Gitea 打算用 2222,这个位置填 2222,同时下面“Gitea 服务器的 SSH 端口”也保持一致,Gitea 会根据这个端口生成正确的克隆地址。SSH 端口填错,网页上复制的命令是错的,新手会反复排查 SSH 权限,实际只是端口没对上。
应用地址 ROOT_URL 一定要填最终对外访问地址。如果你计划通过 Nginx 用http://git.local对外,就写成http://git.local/,而不是http://127.0.0.1:3000/。这个值直接决定了 Web 页面生成的所有 git clone 地址、webhook 回调地址。填错了最直观的现象是:页面显示 clone 地址带 3000 端口,外部访问不通。这两个配置是新手最容易踩的坑,我每次给别人搭完都要强调一遍。
4.2 安装完成后的 app.ini 调整
安装向导结束后,配置文件一般在/etc/gitea/app.ini或/var/lib/gitea/custom/conf/app.ini。按需修改:
[server] DOMAIN = git.local ROOT_URL = http://git.local/ HTTP_PORT = 3000 SSH_PORT = 2222 SSH_DOMAIN = git.local LFS_START_SERVER = true [service] DISABLE_REGISTRATION = true REQUIRE_SIGNIN_VIEW = true DEFAULT_KEEP_EMAIL_PRIVATE = true其中DISABLE_REGISTRATION = true表示关闭开放注册。内网环境下强烈建议关掉,用户由管理员手动创建,避免无关人员注册和垃圾账号。REQUIRE_SIGNIN_VIEW = true是强制登录后才能看到任何页面,对私有化部署很有用。改完配置记得重启:systemctl restart gitea或docker compose restart gitea。
4.3 用 Nginx 反代并接上 HTTPS
内网环境自签 HTTPS 虽然浏览器会提示证书不受信任,但总比 HTTP 明文好。如果你有内部 CA 或者域名能申请证书,直接配上:
server { listen 80; server_name git.local; client_max_body_size 2G; 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_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; } }这里最核心的是client_max_body_size,默认 1M,不调大很容易出现 push 大文件直接 413 的情况。Upgrade头是为了让 WebSocket 正常,否则 Gitea 页面上的通知一直转圈。如果 app.ini 里开了 HTTPS 而 Nginx 只用了 HTTP,会形成回环问题,所以 app.ini 的 ROOT_URL 和 PROTOCOL 务必要跟 Nginx 保持一致。
5. 日常使用:用户、仓库和自动化
安装配置只是一半,真正的价值在日常管理。Gitea 的权限体系和自动化能力值得好好用起来。
5.1 用户、组织和团队的权限体系
Gitea 的权限模型是三层的:用户、组织、团队。组织对应一个业务线或子部门,团队对应具体项目成员。例如“后端组织”下建“支付项目”,把三个开发和一个测试拉进团队,分别给写权限和只读权限。这样项目成员克隆和推送便捷,测试只能看代码,不需要额外维护一堆分支权限。
管理员还可以给单个仓库设置“受保护分支”。启用后,开发不能直接 push 到 main 分支,必须提交 PR,并且可以要求至少一个评审通过才能合并。这个功能对维护稳定分支非常有用,尤其是多人协作时对 main 分支的保护。用户管理方面,内网建议由管理员统一创建账号,再让用户自己到个人设置里添加 SSH 公钥。公钥鉴权比密码方便,后续所有 Git 操作不用输密码,只要保持 SSH 密钥安全即可。
5.2 开启 LFS 支持大文件
Git 对二进制大文件并不友好,仓库会迅速膨胀。Gitea 内置了 LFS 支持,只要在 app.ini 中设置LFS_START_SERVER = true就会开启。客户端只需要装 git-lfs 插件,然后在仓库里执行git lfs track "*.psd"、git lfs install就能使用。注意 LFS 内容会单独存放在 data/lfs 目录,所以备份时不能只备份仓库目录,要把整个 data 目录一起备份。不建议把超过几百 MB 的文件直接放 Git 仓库,即使有 LFS 也会让每次 clone 变慢。
实际使用中,设计稿、安装包、数据集这类变更频繁的大文件都适合 LFS。如果不加区分把所有二进制文件都 track,反而会带来额外的维护成本。合理做法是只 track 那些确实会频繁更新的二进制文件,一次性交付物可以放到网盘或共享目录,不走 Git。
5.3 Webhook、Git 钩子和内置 CI
Gitea 的 Webhook 配置可以让你在 push、PR、issue 事件时把 payload 发到某个 HTTP 端点,最常见的场景是触发内部 Jenkins 构建、发通知到即时通讯群。也可以通过仓库的自定义 Git 钩子做自动化部署,比如在服务器端 post-receive 里写一段脚本,push 完成自动 checkout 到测试机目录。
如果你不想额外部署 CI 系统,Gitea 自带的 Actions 能跑 Go、Python、Node 等常见的流水线任务,基于.gitea/workflows下的 YAML 文件。虽然是后加的模块,但胜在零额外成本,小团队内部够用。我在实际搭建时更倾向先只开 Webhook,等确实需要持续集成再接 Actions,因为无形中少维护一套系统。自建服务最怕功能堆砌,能用够用就好。
6. 备份与恢复,一定要事前演练
Git 服务器最怕的不是日常故障,而是硬盘坏了之后发现备份是坏的。备份这章不写虚的,直接说清要备份什么、怎么恢复。
6.1 到底该备份哪些文件
如果你用的是 SQLite 加默认目录,需要备份的内容包括:app.ini 配置、data 下的gitea.db、repositories目录里所有仓库、data/lfs大文件、附件,最后还有 git 用户下的.ssh目录(内置 SSH 生成的authorized_keys)。漏掉任何一项都可能造成仓库数据丢失或用户无法 SSH。
最简单可靠的备份方式是官方命令gitea dump,这个命令会把数据库、仓库、配置、LFS、SSH 全部打包成一个 zip:
sudo -u git gitea dump --config /etc/gitea/app.ini --file /backup/gitea-$(date +%F).zip注意 dump 在服务运行状态也能执行,但会有短暂锁库,量大时建议停机或低峰执行。我建议每周全量备份一次,每天增量只备份repositories和lfs目录,积少成多。如果仓库数量大,先压缩再同步能节省不少网络带宽。
6.2 恢复步骤与版本一致性
恢复流程分两步:解压 zip 后把 app.ini 放到原路径,把gitea.db、repositories、lfs恢复到对应 data 目录,然后统一修改属主chown -R git:git /var/lib/gitea,重启服务。如果你备份时不带数据库版本,恢复时版本必须和原环境一致,直接拿低版本备份恢复到高版本 Gitea 有兼容风险。
迁移机器同理:老服务器备份导出,新机器装相同版本 Gitea,把 zip 解压到同一目录结构,改好 app.ini 里的域名和 IP 即可。这里有个痛点:如果改了域名,之前 clone 出来的仓库 remote 地址全部失效,需要让团队重新设置 remote。迁移前先把域名或 hosts 安排好,能省很多事。
6.3 自动化备份脚本参考
给个可抄的脚本框架:
#!/bin/bash BACKUP_DIR=/data/backup/gitea DATE=$(date +%F) mkdir -p "$BACKUP_DIR" sudo -u git gitea dump --config /etc/gitea/app.ini --file "$BACKUP_DIR/gitea-$DATE.zip" find "$BACKUP_DIR" -name "gitea-*.zip" -mtime +30 -delete配合 crontab 每天凌晨 2 点执行。脚本写好后至少完整恢复演练一次,确认 zip 能解开、能启动。没演练过的备份不能算有效备份,这句话是我被坑出来的。
7. 常见问题与排查实录
最后把平时最常遇到的问题和排查思路整理成速查表,方便你直接对照。
| 症状 | 常见原因 | 解决办法 |
|---|---|---|
| 网页能开,clone 报 Connection refused | SSH 端口没放开或 SSH_PORT 设置不对 | 检查防火墙,app.ini 中 SSH_PORT 与 Gitea 监听端口一致 |
| push 报 Permission denied (publickey) | 用户公钥没添加,或 clone 地址端口不对 | 用户设置里添加公钥;用网页上的正确 clone 命令重新 clone |
| push 大文件报 413 Request Entity Too Large | Nginx client_max_body_size 太小 | 调大 client_max_body_size,并开启 LFS |
| 页面一直转圈提示 WebSocket 连不上 | 反代未转发 Upgrade 头 | Nginx 配置里加 Upgrade 和 Connection upgrade |
| 忘记管理员密码 | - | 执行gitea admin user change-password --username admin --password 新密码 |
| SQLite busy 或 is locked | 并发写太多 | 低峰期 dump;长期建议迁 PostgreSQL |
| 时间显示早 8 小时 | 容器时区未设置 | 挂载 /etc/localtime 和 /etc/timezone |
几个补充排查思路:SSH 通不通,先执行ssh -p 2222 -T git@host,如果配置正常会返回一句欢迎提示;通不了就逐层检查端口、公钥、防火墙。clone 命令整条复制时要注意是 http 还是 ssh 方式,混合使用容易混淆。忘记密码命令在新版本中还能用gitea admin user change-password,但前提是你有服务器上的 shell 权限。
如果页面打开了但一直显示“连接超时”,多半是内网 DNS 或 hosts 的问题,在客户端机器 ping 一下git.local看解析对不对。还有一个小概率坑:系统 SSH 服务占用了 22,而你启动 Gitea 时也选了 22,两者冲突会导致 Gitea 起不来,日志里会明显报bind address already in use,把 Gitea SSH 端口改成 2222 就好。
最后分享一个我踩过的坑:Gitea 的备份不要等坏掉才验证。我第一次搭完,写了备份脚本跑了三周,后来测试恢复,发现 zip 里少了一类 LFS 文件,因为打包时目录权限不对。从那以后我固定每月做一次恢复演练。自建 Git 服务器本身不难,难的是把权限、备份、升级节奏都规范化。如果你打算给团队搭,建议第一天就把备份脚本写好,第二周就让几个人把日常使用流程走一遍,有问题趁早暴露。Gitea 是那种越用越顺手的工具,配置一次,后面几乎不用管。