去年我帮一个创业团队挑自建Git服务预算和机器都紧巴巴——一台2C4G云服务器上还跑着前端构建和测试环境。GitLab一上去内存就顶不住最后我给他们装了Gogs。这个用Go写的轻量级Git仓库管理工具在CentOS上部署非常简单二进制下载解压就能跑资源占用比GitLab低一个量级10人左右的团队用起来完全没压力。这篇东西就从我实际部署过程出发把从系统准备、数据库选择、下载配置、systemd托管、Nginx反代到后面备份升级的完整路径讲一遍。无论你是刚开始接触自建Git还是想从GitLab换成更轻的解决方案都可以对照着自己走一遍。1. 为什么在CentOS上自建Git服务时我选了Gogs1.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更“克制”。对比项GogsGiteaGitLab开发语言GoGo以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远程管理按需开放2222Gogs内置SSH服务对外开放80/443Nginx反向代理HTTP/HTTPS对外开放3000Gogs内部HTTP端口不对外开放CentOS 7以上的防火墙默认是firewalld直接操作它sudo firewall-cmd --permanent --add-servicehttp sudo firewall-cmd --permanent --add-port2222/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起步还是直接上MySQL3.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 gogslocalhost IDENTIFIED BY 替换成强密码; GRANT ALL PRIVILEGES ON gogs.* TO gogslocalhost; FLUSH PRIVILEGES;这里有几个细节值得说一下。数据库字符集我用的是utf8mb4因为Git仓库的一些提交信息、Issue内容里可能包含emoji老版utf8字符集会报错或者存成乱码。账号只允许从localhost连接也就是本机访问这是安全底线。Gogs和数据库都部署在同一台服务器上完全不需要开放远程数据库连接。3.3 为什么我不推荐装全新的单独PostgreSQLPostgreSQL确实是好数据库但我见过不少人为了Gogs单独装一个PostgreSQL然后又多踩了一堆坑。这里不是黑它而是从“Gogs要干的事”来算账一个容纳几十个仓库的小型Git平台MySQL/MariaDB完全够用配置和维护成本都更低。PostgreSQL的优势在复杂查询、大数据量、高并发分析场景恰恰是Git平台用不太到的。如果你的公司已经有现成的PostgreSQL服务团队习惯也成熟那就直接复用别浪费。但如果是为了装Gogs而专门另起一个数据库服务我建议省掉这一步一台轻量服务器没必要同时养两个重量级数据库。4. 下载Gogs二进制并完成首次配置4.1 下载、解压与目录结构Gogs安装最让人舒服的地方就是没有编译、没有一堆依赖下载一个tar包解压就能跑。到GitHub Releases页面找到最新版本把版本号替换成实际的。cd /home/git GOGS_VERSIONv0.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设置端口3000HTTP地址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] DescriptionGogs git server Afternetwork.target Wantsnetwork-online.target [Service] Typesimple Usergit Groupgit WorkingDirectory/home/git/gogs ExecStart/home/git/gogs/gogs web Restartalways RestartSec5 EnvironmentUSERgit HOME/home/git [Install] WantedBymulti-user.target解释几个容易出问题的点Usergit和Groupgit是权限隔离和之前创建的系统账号对应。EnvironmentUSERgit HOME/home/git也很重要很多Git钩子和SSH操作都要读取用户家目录不设置的话Gogs进程拿到的HOME可能不对导致钩子执行报找不到路径。Restartalways保证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、限流、日志以后改任何服务都更灵活。先安装Nginxsudo 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:3000Header按上面这套规则填就行思路完全一致。配置好后做语法检查并重载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 gitgit.example.com如果一切正常会看到Gogs的欢迎信息类似Hi there, username! Youve successfully authenticated, but Gogs does not provide shell access.看到这句话就说明SSH链路通了。接着在Gogs网页上创建一个测试仓库复制页面显示的SSH克隆地址。因为SSH端口不是22而是2222地址会类似ssh://gitgit.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创建账号时用的是gogslocalhost但Gogs连接时把主机解析成localhost还是127.0.0.1MySQL对这两者的授权记录可能不一样。最稳妥的办法是在创建账号时同时保留gogslocalhost和gogs127.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重启Gogssudo systemctl restart gogs ss -tlnp | grep 2222确认2222端口处于LISTEN状态即可。另一个坑是权限问题。很多教程会让你把/home/git权限改成777这是大忌。虽然Gogs内置SSH服务不直接依赖系统的authorized_keys文件但/home/git目录权限过宽会引发安全告警严重时SSH直接拒绝认证。正确权限是目录755、文件644所有者和组是gitsudo 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 21代码、数据库、配置三样都备份到了才算一套完整备份。千万不要只备份仓库目录不备份数据库否则仓库还在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、再从各种坑里爬出来的全过程后最大的感受是轻量工具如果从一开始就把备份、权限和端口规划想清楚后面能省下大量运维时间。希望这篇从实际部署中整理出来的教程能让你绕开我踩过的那些坑。