去年我帮一个创业团队挑自建Git服务,预算和机器都紧巴巴——一台2C4G云服务器上还跑着前端构建和测试环境。GitLab一上去内存就顶不住,最后我给他们装了Gogs。这个用Go写的轻量级Git仓库管理工具,在CentOS上部署非常简单,二进制下载解压就能跑,资源占用比GitLab低一个量级,10人左右的团队用起来完全没压力。这篇东西就从我实际部署过程出发,把从系统准备、数据库选择、下载配置、systemd托管、Nginx反代到后面备份升级的完整路径讲一遍。无论你是刚开始接触自建Git,还是想从GitLab换成更轻的解决方案,都可以对照着自己走一遍。
1. 为什么在CentOS上自建Git服务时我选了Gogs
1.1 它解决的痛点和适合的场景
本着“能跑就行”的原则,自建Git服务首先要回答一个问题:你到底需要多大体量的代码托管平台。个人开发者、小团队、内部项目,其实大多数时候只需要一个能创建仓库、管理成员、看看提交历史的工具,并不需要GitLab那一整套DevOps流水线。Gogs正好卡在这个位置上。
我当时给那支团队算过一笔账。GitLab Community Edition官方推荐最低配置其实是2核4G,实际跑起来,Prometheus监控、Sidekiq后台任务、Gitaly这些组件一起工作,内存占用经常奔着3G去。如果这台服务器上还要跑CI、跑测试、跑一些乱七八糟的内部工具,很快就卡成幻灯片。Gogs不一样,它只提供一个核心:Git仓库托管。Wiki、Issue、WebHook这些基础协作功能都有,但没有那么多常驻后台服务。我实测过一台1G内存的云服务器跑Gogs,进程稳定之后占用大概在100多MB到200MB之间,剩余内存还能干点别的。
所以Gogs适合的场景非常明确:个人代码仓库、三五人小团队、公司内部工具项目、教学环境,或者你只是想把自己散落各处的项目集中管理起来。它不适合的场景也很明确:需要完整CI/CD、需要复杂的代码评审流程、需要大规模多人协作的大型团队,那还是老老实实上GitLab或Gitea。
1.2 Gogs、GitLab、Gitea 到底怎么选
很多人会问,现在明明有Gitea,还挑了更古早的Gogs,是不是有点老古董。我理解这个疑问,但实际用下来,Gogs的核心定位比Gitea更“克制”。
| 对比项 | Gogs | Gitea | GitLab |
|---|---|---|---|
| 开发语言 | Go | Go | 以Ruby为主 |
| 安装复杂度 | 极低,单二进制 | 低,单二进制 | 高,多组件 |
| 内存占用 | 很低 | 较低 | 高 |
| 内置CI/CD | 无 | 轻量CI | 完整CI/CD |
| 适合规模 | 十人以内小团队 | 中小团队 | 中大型团队 |
| 迭代速度 | 偏保守 | 较快 | 最快 |
Gitea本身是从Gogs分叉出去的项目,功能更多,跟手程度也更好,社区活跃度也更高。如果你希望以后能长成一个大点的平台,选Gitea没毛病。但我个人选Gogs的原因很朴素:功能少意味着攻击面小、维护成本低、升级风险小。很多时候我们用代码托管平台,只想安安静静存代码,不想被一堆用不着的功能页面包围。
GitLab不是不好,它在代码评审、DevOps、权限管理上的能力很强,但代价是部署和维护成本直线上升。对于一个CentOS上自建、不希望搭进去太多运维精力的小团队来说,Gogs是性价比最高的选择。
2. 装之前的系统准备:依赖、用户和网络环境
2.1 确认系统版本与基础软件
部署第一步不是下载Gogs,而是先把系统的底子摸清楚。登录服务器后先看两个东西:系统版本和CPU架构。
cat /etc/redhat-release uname -m理论上Gogs支持大多数Linux发行版,我下面的操作默认你用的是CentOS 7.9或CentOS 8/9系。如果你手里还有一台老一点CentOS 7.9,安装步骤差别不大,但要注意老版本系统的安全补丁和软件源已经逐渐收缩,能升级尽量升级到新版本。
然后是装基础软件。Gogs依赖Git做底层仓库操作,所以先把Git装好:
sudo yum install -y git curl wget git --versionCentOS默认仓库里的Git版本一般够用,版本不需要太新。安装完Git后顺手把系统更新一下,避免装到一半被安全补丁拦住:
sudo yum update -y这一步看起来啰嗦,但在生产服务器上非常有必要。很多人在装Gogs时遇到莫名其妙的编译错误或连接错误,后来一查都是系统缺了基础依赖或者有版本漏洞。
2.2 创建运行Gogs的专用账号
Gogs不建议用root用户跑,这也是绝大多数自建服务的基本规矩。单独创建一个系统账号,把Gogs进程隔离在普通用户权限下,即使被拿下,攻击者也拿不到root权限。
sudo mkdir -p /home/git sudo useradd --system --home /home/git --shell /bin/bash git sudo chown git:git /home/git注意这里的--system参数,创建的是一个系统账号,不会出现在登录欢迎列表里,也不会有正常密码登录能力。--home指定它的家目录为/home/git,后续Gogs的数据、配置都放这里。
很多教程会让你用git这个普通用户,但我更建议用系统账号配合sudo执行管理命令。这样既能保证权限隔离,又不会让其他业务用户随随便便切到这个账号。
做完之后检查一下目录归属:
ls -ld /home/git正常情况下输出应该是drwxr-xr-x 2 git git 6 ... /home/git,如果不是这个归属,后面Gogs写配置和仓库目录的时候会拿不到权限。
2.3 防火墙、SELinux和端口规划
Gogs默认的HTTP端口是3000,内置SSH服务端口默认是22。但服务器上通常已经有系统sshd在监听22了,所以实操中我建议把Gogs的SSH端口改到2222。
先规划好端口,免得后面乱:
| 端口 | 用途 | 是否对外开放 |
|---|---|---|
| 22 | 系统SSH远程管理 | 按需开放 |
| 2222 | Gogs内置SSH服务 | 对外开放 |
| 80/443 | Nginx反向代理HTTP/HTTPS | 对外开放 |
| 3000 | Gogs内部HTTP端口 | 不对外开放 |
CentOS 7以上的防火墙默认是firewalld,直接操作它:
sudo firewall-cmd --permanent --add-service=http sudo firewall-cmd --permanent --add-port=2222/tcp sudo firewall-cmd --reload firewall-cmd --list-all如果服务器之前用的是iptables或者干脆没开防火墙,也别跳过这步。很多人在外网访问Gogs时发现连接超时,十有八九是防火墙没放行。
接着是SELinux。CentOS默认开启SELinux,这个安全模块经常被忽略,但坑起来要命。特别是你用Nginx反向代理访问本机3000端口时,如果SELinux处于 enforcing 状态,Nginx默认是不允许访问非标准端口的,浏览器就会看到一个502 Bad Gateway。
解决办法是保持SELinux开启,只放开Nginx到本机网络的连接权限:
sudo setsebool -P httpd_can_network_connect 1这一条不加,后面配完Nginx大概率要回头排查半天。先在这里处理掉,后面少踩一个大坑。
3. 数据库层选择:从SQLite起步还是直接上MySQL
3.1 SQLite和MySQL的分界线
Gogs支持SQLite3、MySQL和PostgreSQL三种数据库。第一次安装的人经常纠结选哪个,其实答案取决于团队规模。
如果你只是个人用、或者团队成员不超过10人,直接用SQLite最简单。SQLite是一个文件数据库,Gogs会把数据写进custom/data/gogs.db这个文件里,备份的时候把这个文件复制走就行,完全不用安装额外的数据库服务,部署和运维成本几乎为零。
但SQLite也有自己的极限。它适合并发读,不适合并发写。当多个成员同时发起Issue、操作WebHook、做大量写入时,SQLite会随着连接增多而出现database is locked的错误。这时候就该MySQL上场了。
我个人的判断线是:预计团队人数超过10人、仓库数超过几十个、或者你本来就有MySQL/MariaDB在跑,那就不要纠结,直接用MySQL。多花十几分钟装一个数据库,后面省心很多。
这一节后面默认你选择的是MySQL/MariaDB。如果你确定用SQLite,可以跳过数据库初始化,直接到下一章的下载步骤。
3.2 MySQL数据库与账号的初始化
CentOS 9和8系统源里都有MariaDB,直接安装:
sudo yum install -y mariadb-server sudo systemctl enable --now mariadb装完先跑一下安全初始化脚本:
mysql_secure_installation这个脚本会帮你设置root密码、删除匿名用户、禁止root远程登录。别嫌麻烦,生产环境这一步必须做。
接下来登录MySQL,创建Gogs要用的数据库和账号:
mysql -uroot -p在MySQL命令行里执行:
CREATE DATABASE gogs CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; CREATE USER 'gogs'@'localhost' IDENTIFIED BY '替换成强密码'; GRANT ALL PRIVILEGES ON gogs.* TO 'gogs'@'localhost'; FLUSH PRIVILEGES;这里有几个细节值得说一下。数据库字符集我用的是utf8mb4,因为Git仓库的一些提交信息、Issue内容里可能包含emoji,老版utf8字符集会报错或者存成乱码。账号只允许从localhost连接,也就是本机访问,这是安全底线。Gogs和数据库都部署在同一台服务器上,完全不需要开放远程数据库连接。
3.3 为什么我不推荐装全新的单独PostgreSQL
PostgreSQL确实是好数据库,但我见过不少人为了Gogs单独装一个PostgreSQL,然后又多踩了一堆坑。这里不是黑它,而是从“Gogs要干的事”来算账:一个容纳几十个仓库的小型Git平台,MySQL/MariaDB完全够用,配置和维护成本都更低。PostgreSQL的优势在复杂查询、大数据量、高并发分析场景,恰恰是Git平台用不太到的。
如果你的公司已经有现成的PostgreSQL服务,团队习惯也成熟,那就直接复用,别浪费。但如果是为了装Gogs而专门另起一个数据库服务,我建议省掉这一步,一台轻量服务器没必要同时养两个重量级数据库。
4. 下载Gogs二进制并完成首次配置
4.1 下载、解压与目录结构
Gogs安装最让人舒服的地方就是没有编译、没有一堆依赖,下载一个tar包解压就能跑。到GitHub Releases页面找到最新版本,把版本号替换成实际的。
cd /home/git GOGS_VERSION="v0.14.0" curl -sL -o /tmp/gogs.tar.gz \ "https://github.com/gogs/gogs/releases/download/${GOGS_VERSION}/gogs_${GOGS_VERSION#v}_linux_amd64.tar.gz" tar -xzf /tmp/gogs.tar.gz -C /home/git解压之后/home/git下面会出现一个gogs目录,里面有这些内容:
gogs # 可执行文件 custom/ # 自定义配置目录 public/ # 前端静态资源 templates/ # 页面模板 scripts/ # 服务脚本和工具脚本务必把整个目录的归属改成git用户,不然后面写配置、创建仓库都没权限:
sudo chown -R git:git /home/git/gogs这一步别省。我见过有人忘了改归属,Gogs网页配置写完一提交,页面直接报错写不了app.ini,看着像安装环境问题,结果就是目录权限问题。
Gogs的仓库数据默认不放在gogs目录里面,而是默认放在/home/git/gogs-repositories,这点先有个印象,后面备份会用到。
4.2 通过Web向导完成首次配置
先启动一下Gogs,完成Web安装界面:
cd /home/git/gogs sudo -u git ./gogs web终端会打印监听地址,一般是[::]:3000。浏览器访问http://服务器IP:3000/install,就能看到安装页面。
这个页面字段比较多,我按实际填写顺序拆一下:
- 数据库设置:类型选
MySQL,主机填127.0.0.1:3306,用户填gogs,密码填刚才设的强密码,数据库名填gogs。 - 应用基本设置:应用名称可以填
Gogs、我的代码仓库之类;仓库根目录保持/home/git/gogs-repositories,不用改。 - SSH设置:必须勾选“内置SSH服务器”,端口填
2222。这一步很多人漏了,默认端口是22,如果你没改就直接和系统sshd冲突。 - HTTP设置:端口
3000,HTTP地址0.0.0.0,应用URL填你最终对外访问的地址。如果有域名并且打算上HTTPS,直接填https://git.example.com/,不要填http://IP:3000。这个URL会显示在仓库克隆地址上,后面再改会有很多旧地址对不上。 - 管理员账号:建议直接创建一个,比如
admin,后面管理后台和普通用户权限区分很清楚。
填完提交,Gogs会自动生成custom/conf/app.ini并写入刚才的配置。如果页面提示成功,那安装过程就算走完一半了。
4.3 手动确认app.ini里的关键项
Web向导生成配置后,我还是建议打开custom/conf/app.ini看一眼关键项,尤其是从模板复制来的机器上,有些默认值不一定符合我们的规划:
cat /home/git/gogs/custom/conf/app.ini重点核对三段。
[server]段:
[server] HTTP_PORT = 3000 DOMAIN = git.example.com ROOT_URL = https://git.example.com/ SSH_PORT = 2222 START_SSH_SERVER = true[database]段:
[database] DB_TYPE = mysql HOST = 127.0.0.1:3306 NAME = gogs USER = gogs PASSWD = 你的强密码[repository]段:
[repository] ROOT = /home/git/gogs-repositories如果哪个字段不对,直接改文件然后重启Gogs。注意PASSWD如果密码里有特殊字符,比如#、;,最好用双引号包起来,否则配置解析会出问题。
5. 让它开机自启:systemd服务与Nginx反向代理
5.1 用systemd托管Gogs进程
刚才用sudo -u git ./gogs web启动只是前台运行,一旦关掉终端Gogs就停了。生产环境必须用systemd把它托管起来。
新建服务文件/etc/systemd/system/gogs.service:
[Unit] Description=Gogs git server After=network.target Wants=network-online.target [Service] Type=simple User=git Group=git WorkingDirectory=/home/git/gogs ExecStart=/home/git/gogs/gogs web Restart=always RestartSec=5 Environment=USER=git HOME=/home/git [Install] WantedBy=multi-user.target解释几个容易出问题的点:
User=git和Group=git是权限隔离,和之前创建的系统账号对应。Environment=USER=git HOME=/home/git也很重要,很多Git钩子和SSH操作都要读取用户家目录,不设置的话Gogs进程拿到的HOME可能不对,导致钩子执行报找不到路径。Restart=always保证Gogs挂掉之后自动拉起,省得半夜接到告警电话。
然后加载并启动:
sudo systemctl daemon-reload sudo systemctl enable --now gogs sudo systemctl status gogs看到active (running)就说明托管成功。以后重启服务器,Gogs也会自动起来。
5.2 Nginx反向代理配置与端口收敛
Gogs自带的HTTP服务跑在3000端口,但实际对外不应该直接暴露3000,原因很简单:Nginx做代理层可以统一控制域名、HTTPS、限流、日志,以后改任何服务都更灵活。
先安装Nginx:
sudo yum install -y nginx sudo systemctl enable --now nginx在/etc/nginx/conf.d/gogs.conf里写入反向代理配置:
server { listen 80; server_name git.example.com; client_max_body_size 512m; proxy_read_timeout 1200s; proxy_send_timeout 1200s; 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; } }这里client_max_body_size 512m非常关键。默认值是1m,如果团队里有推大文件、二进制包、安装镜像的情况,就会得到413 Request Entity Too Large错误。我第一次部署时没加这个参数,同事往仓库推一个200M的打包文件直接失败,日志里一片红色。
如果要用HTTPS,建议直接配合certbot申请证书:
sudo yum install -y certbot python3-certbot-nginx sudo certbot --nginx -d git.example.com证书搞定后,回到Gogs的app.ini把ROOT_URL改成https://git.example.com/,这样页面克隆地址和WebHook回调都是HTTPS链接。
如果你平时习惯用宝塔面板,本质也是填一个反向代理目标http://127.0.0.1:3000,Header按上面这套规则填就行,思路完全一致。
配置好后做语法检查并重载:
sudo nginx -t sudo systemctl reload nginx然后本地验证:
curl -I http://127.0.0.1/能拿到HTTP/1.1 200或302,说明Nginx和Gogs已经串起来了。此时记得回到防火墙把3000端口关掉,只留80/443和2222对公网开放。
5.3 最后跑通SSH克隆的验证步骤
Web界面能访问不代表整套部署就绪,SSH克隆才是开发人员天天用的核心路径。
先在Gogs页面注册一个普通用户,然后在“个人设置 -> SSH公钥”里粘贴本机生成的公钥:
ssh-keygen -t ed25519 -C "你的备注" cat ~/.ssh/id_ed25519.pub公钥粘贴保存后,在客户端机器上测试:
ssh -T -p 2222 git@git.example.com如果一切正常,会看到Gogs的欢迎信息,类似:
Hi there, username! You've successfully authenticated, but Gogs does not provide shell access.看到这句话就说明SSH链路通了。接着在Gogs网页上创建一个测试仓库,复制页面显示的SSH克隆地址。因为SSH端口不是22而是2222,地址会类似:
ssh://git@git.example.com:2222/username/test.git正常克隆、提交一次,整个部署链路就彻底打通了。
6. 部署过程中最容易被绊倒的几个坑
6.1 数据库连接失败的完整排查链路
第一次在页面安装Gogs时,最常见的报错就是数据库连接失败,红字一闪而过,让人摸不着头脑。
我之前帮人排查过一次,报错信息是dial tcp 127.0.0.1:3306: connect: connection refused。这种问题按下面顺序排查,基本都能定位:
先确认数据库服务真的在跑:
systemctl status mariadb再确认Gogs服务器能否用TCP方式连上数据库。注意Gogs用的是TCP连接,不是Unix socket,所以不能用mysql命令直接登录成功就完事,要指定主机名和端口:
mysql -h127.0.0.1 -P3306 -ugogs -p -D gogs如果这一步登录成功,说明数据库服务和账号权限没问题。如果登录不了,可能是密码特殊字符问题,也可能是MySQL的skip-networking设置被打开了。检查MySQL配置文件:
grep skip-networking /etc/my.cnfskip-networking如果有值,MySQL会拒绝TCP连接,Gogs当然连不上。
还有一种情况比较隐蔽:你给Gogs创建账号时用的是gogs'@'localhost,但Gogs连接时把主机解析成localhost还是127.0.0.1,MySQL对这两者的授权记录可能不一样。最稳妥的办法是在创建账号时同时保留'gogs'@'localhost'和'gogs'@'127.0.0.1'两种匹配,或者直接把主机部分写成%。当然写%意味着任何主机都能用该账号连数据库,如果只在本机用,localhost更安全。
最后再查Gogs日志:
tail -100 /home/git/gogs/log/gogs.logGogs日志一般会给出比较明确的报错原因,比页面上的红字信息丰富得多。很多时候错误原因就藏在日志最后几行。
6.2 SSH端口冲突与目录权限
Gogs内置SSH服务最常见的故障是端口被占用。系统sshd默认占用22端口,如果你没在安装页面把Gogs的SSH端口改成2222,就会发现Gogs日志里报listen tcp :22: bind: address already in use,但表面上看Gogs进程还活着,页面也能访问,就是SSH命令连不上。
解决方式很简单,修改app.ini里的SSH_PORT = 2222,重启Gogs:
sudo systemctl restart gogs ss -tlnp | grep 2222确认2222端口处于LISTEN状态即可。
另一个坑是权限问题。很多教程会让你把/home/git权限改成777,这是大忌。虽然Gogs内置SSH服务不直接依赖系统的authorized_keys文件,但/home/git目录权限过宽会引发安全告警,严重时SSH直接拒绝认证。正确权限是目录755、文件644,所有者和组是git:
sudo chown -R git:git /home/git sudo chmod 755 /home/git如果修改过RUN_USER或者把Gogs目录从别处复制过来,一定要重新chown一次,不然Gogs很多写操作会悄悄失败。
6.3 低配机器上的卡顿与启动异常
如果你的机器内存小于等于1G,同时装了MySQL,很容易出现一个现象:页面能访问,但提交代码或者创建Issue的时候很慢,甚至直接OOM把进程杀掉。原因是MySQL默认的innodb_buffer_pool_size偏高,挤占了系统内存。
可以调低MySQL内存占用,编辑/etc/my.cnf加入:
[mysqld] performance_schema = OFF innodb_buffer_pool_size = 64M innodb_log_buffer_size = 1M max_connections = 50改完重启MariaDB。这组参数适合小型应用,如果机器内存超过4G就没必要这么保守。
还有一个启动异常的坑是3000端口被别的进程占用,比如有些服务器上会跑其他Web服务。遇到监听失败先排查端口:
ss -lntp | grep 3000找到占用进程后,要么改Gogs的端口,要么停掉冲突服务,别硬来。
7. 部署之后的日常:备份、升级和权限回收
7.1 最简备份方案
很多人把Gogs部署完扔到服务器上就不管了,直到一次误删或磁盘损坏才开始拍大腿。Gogs的备份其实非常清晰,只有两样东西:仓库数据和数据库。
如果是MySQL,备份命令示例:
mysqldump -h127.0.0.1 -ugogs -p gogs > /backup/gogs-$(date +%F).sql tar czf /backup/gogs-repos-$(date +%F).tar.gz -C /home/git gogs-repositories cp /home/git/gogs/custom/conf/app.ini /backup/gogs-app.ini.bak如果是SQLite,除了仓库目录,还要备份custom/data/gogs.db。注意SQLite在运行中直接复制文件可能产生损坏备份,稳妥做法是停一下Gogs再复制:
sudo systemctl stop gogs cp /home/git/gogs/custom/data/gogs.db /backup/ sudo systemctl start gogs备份脚本建议放到cron里跑:
0 3 * * * /usr/local/bin/gogs-backup.sh >/dev/null 2>&1代码、数据库、配置三样都备份到了,才算一套完整备份。千万不要只备份仓库目录不备份数据库,否则仓库还在,Issue、用户、WebHook设置全都没了。
7.2 升级新版本的保守操作
Gogs本身升级不算频繁,但代码托管平台涉及数据安全,我升级时习惯用最保守的一套流程,宁可慢一点也不想翻车:
先做完整备份,然后停服务:
sudo systemctl stop gogs把新版tar包解压到临时目录:
mkdir -p /tmp/gogs-new tar -xzf gogs_new.tar.gz -C /tmp/gogs-new用rsync同步覆盖,保留custom和log目录:
sudo rsync -av /tmp/gogs-new/gogs/ /home/git/gogs/ \ --exclude custom --exclude log --exclude repositories sudo chown -R git:git /home/git/gogs sudo systemctl start gogs为什么不直接删掉旧目录再放新的?因为custom/conf/app.ini里保存了你所有配置,log里可能有历史审计信息,直接覆盖容易出事。用rsync排除这几个目录,升级完配置还是原样。
启动后马上看日志和页面,确认没有500、数据库迁移报错等问题。大版本升级前,一定先看一眼官方Changelog,如果有重大数据库结构变更,要按官方指引手动跑迁移操作。
7.3 给团队用之前先做好的几条安全设置
正式开放给团队成员之前,有几件事我强烈建议先做掉。
第一,确认安装锁已启用。打开app.ini,看[security]段有没有INSTALL_LOCK = true。如果有,说明安装向导已经被锁定,其他人不能再访问/install重置整个站点。没加的话手动加上:
[security] INSTALL_LOCK = true第二,关闭开放注册。Gogs默认允许任何人注册账号,如果暴露在公网,很快就会有一堆垃圾账号进来。登录管理员后台,在“用户”设置里把“禁用自动注册”打开。
第三,强制团队成员启用两步验证。这个功能对个人仓库可能觉得麻烦,但对公司内部代码托管平台非常值得。代码泄露的成本远比多用一次验证码高得多。
第四,SSH公钥和邮箱验证。后台可以设置用户必须验证邮箱后才能操作,避免有人乱填邮箱获得推送权限。
这些设置做完,Gogs才算是从“个人玩具”变成了一个能放心给团队使用的内部服务。我自己经历了从GitLab迁移到Gogs、再从各种坑里爬出来的全过程后,最大的感受是:轻量工具如果从一开始就把备份、权限和端口规划想清楚,后面能省下大量运维时间。希望这篇从实际部署中整理出来的教程,能让你绕开我踩过的那些坑。