Gogs这个名字,常年在自建Git服务圈子里出现。它是个用Go写的轻量级Git托管平台,整个服务就是一个可执行文件,跑起来占用的内存比GitLab小一个数量级,特别适合那种二三十人以内的小团队、内网研发环境、或者个人VPS上临时搭一个代码仓库。今天这篇就完整记录一下我在CentOS 7.9和CentOS 8.x上部署Gogs的全过程,从装依赖、选数据库、写配置到用systemd托管进程、再用Nginx反代出去,整个流程走通之后你就能得到一个正经能用的Git服务。
我一开始也被各种“一键部署”脚本坑过,后来直接改用官方二进制包手动部署,过程反而更可控。下面所有步骤都基于我实际操作的命令,CentOS 7.9和8.x通用,部分命令在9上可能会有小差异,但核心思路不变。
1. 动手之前:Gogs是什么,什么场景用它
1.1 为什么我选Gogs而不是GitLab
GitLab功能确实全,但你要知道它是个“全家桶”:Ruby写的服务,PostgreSQL、Redis、Sidekiq、Prometheus这一串全得跟着装上,普通2核4G的机器跑起来都吃力,内存动不动吃满。Gogs不一样,它本身就是一个Go编译出来的二进制文件,官方给的最低要求非常低,512MB内存的机器也能带起来。
我说的“轻量”,不是指功能砍到没法用。Gogs核心功能很完整:仓库托管、Issue、Pull Request、WebHook、组织管理、SSH和HTTP两种clone方式、内置CI集成,日常团队协作够用了。而且界面清爽,没有一堆花里胡哨的按钮,内网用户上手成本低。
所以如果你只是给一个三五人的小组搞个代码托管,或者自己折腾一个备份仓库,Gogs是性价比最高的选择。如果你需要几百上千人、复杂权限体系、流水线、Code Review规则,那直接上GitLab Enterprise或Gitea商业方案,别难为Gogs。
1.2 部署前的环境准备
Gogs官方支持的操作系统很广,CentOS 7、CentOS 8、Debian、Ubuntu都行。我这边测试环境是两个,一台CentOS 7.9,一台CentOS 8.5,都是最小化安装,没有图形界面。
先确认系统版本和架构:
cat /etc/redhat-release uname -m我实测的版本输出分别是:
CentOS Linux release 7.9.2009 (Core) x86_64再确认内存和磁盘足够。Gogs本身只占100MB左右内存,但仓库多了磁盘容易吃紧。建议至少准备20GB可用空间,如果只是放几个小项目,5GB也能跑。
CentOS 7和8都已经进入EOL阶段,默认源基本不可用了,如果遇到yum装不了包,可以先替换成国内可用的镜像源源,具体替换方法网上有很多,这里不展开。替换完再执行:
yum update -y这一步不是必须,但建议做,至少把基础安全补丁打上。
2. 基础环境安装和目录规划
2.1 安装Git和相关工具
Gogs本身虽然是用Go写的自包含程序,但它管理仓库时还是会调用系统里的git命令。所以系统里必须装git,而且版本不能太老。
CentOS 7默认的git是1.8.3,说实话有点老,但处理常见的push、pull、分支合并是够用的。CentOS 8自带的git是2.x,要好很多。如果你对git功能要求高,比如要用worktree、更完整的partial clone,那还是建议用高版本。
先装基础工具:
yum install -y git curl wget sqlite-develsqlite-devel这个包不是必须,但是如果后面要用SQLite数据库,最好装上有备无患。curl和wget用来下载Gogs安装包,git是运行时依赖。
如果你用的是CentOS 7而且真的想要新一点的git,可以用源码编译,但我不建议初次部署就把时间耗在编译git上。Gogs官网的最低要求没卡git版本,1.8在实际使用中也没碰到过兼容问题。
2.2 创建专用用户和目录结构
生产环境最大的忌讳是直接用root跑服务。Gogs官方文档里也明确说了,要用一个独立的系统用户运行。
我习惯创建一个名为git的系统用户:
useradd --system --user-group --home /home/git git参数解释一下:--system表示创建系统账户,--user-group会自动建一个同名的git组,--home指定家目录,后面存仓库目录用。
然后创建Gogs的部署目录和仓库目录:
mkdir -p /opt/gogs mkdir -p /home/git/gogs-repositories chown -R git:git /opt/gogs /home/git为什么仓库目录单独放在/home/git/gogs-repositories而不是放在/opt/gogs里面?因为我习惯把“程序二进制”和“数据”分开。升级的时候只需要替换程序目录,仓库数据不动,备份也更清晰。
如果你希望仓库放在数据盘,也可以把家目录或仓库目录指到数据盘挂载点,比如/data/git/repos,以后扩容更方便。
3. 数据库选型:SQLite还是MySQL
3.1 两种方案的取舍
Gogs支持SQLite、MySQL、PostgreSQL、MSSQL等数据库。对小团队来说,最常见的选择就是SQLite和MySQL/MariaDB,我把区别整理成一张表:
| 对比项 | SQLite | MySQL/MariaDB |
|---|---|---|
| 部署成本 | 零配置,直接用 | 需要额外装数据库服务 |
| 内存占用 | 最低 | 多占用200~300MB |
| 并发能力 | 弱,适合低并发 | 强,适合多人同时操作 |
| 备份复杂度 | 直接复制文件 | mysqldump或物理备份 |
| 适合场景 | 个人、三五人小团队 | 正式团队,有运维能力 |
我的建议很直接:如果只是个人用,或者小组不超过5个人,直接用SQLite,省心。如果团队有二三十人,或者你希望以后数据好迁移、备份好管理,就上MySQL或MariaDB。
3.2 用MariaDB初始化数据库
我这里用MariaDB举例,因为CentOS 7自带MariaDB,安装简单,兼容MySQL协议。
yum install -y mariadb-server systemctl enable --now mariadb然后执行安全初始化:
mysql_secure_installation按提示设置root密码,关掉匿名用户,关掉测试库,基本都选y就行。
接着登录数据库,创建Gogs专用的库和账号:
mysql -u root -p执行SQL:
CREATE DATABASE IF NOT EXISTS gogs DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; CREATE USER 'gogs'@'127.0.0.1' IDENTIFIED BY '这里换成你自己的强密码'; GRANT ALL PRIVILEGES ON gogs.* TO 'gogs'@'127.0.0.1'; FLUSH PRIVILEGES; EXIT;这里有个细节:创建用户时我用的host是127.0.0.1而不是localhost,因为Java/Go的数据库驱动走TCP连接时,如果用localhost可能会走socket文件,权限匹配容易踩坑。之前我就因为这个问题被坑过一次,后来统一用127.0.0.1,一次过。
用utf8mb4而不是utf8,是为了兼容emoji和部分生僻字。虽然代码提交信息里出现emoji的概率不高,但万一有呢,别给自己埋坑。
3.3 直接用SQLite的零配置方案
如果你决定用SQLite,那数据库这步直接跳过,Gogs安装向导里选SQLite3,程序会在指定目录下生成gogs.db文件。
唯一的注意事项是:这个db文件所在目录必须对运行用户git可写。否则安装页面会报unable to open database file。
我部署时习惯把SQLite文件放在/opt/gogs/data目录下,在后面的配置里设置好PATH路径就行。
4. 下载Gogs并完成基础配置
4.1 下载Gogs二进制包
到Gogs的GitHub Releases页面找最新版Linux amd64的压缩包。为了避免我写死版本号导致你复制的时候失效,这里直接给通用下载思路:
cd /tmp wget https://github.com/gogs/gogs/releases/download/v0.13.0/gogs_0.13.0_linux_amd64.tar.gz如果下载慢,可以去找国内加速镜像,把下载地址换成镜像地址。理论上只要拿到相同的tar.gz包即可。
解压:
tar -xzvf gogs_0.13.0_linux_amd64.tar.gz -C /opt/解压出来会多一个/opt/gogs目录,里面结构大概是:
/opt/gogs/gogs /opt/gogs/custom/ /opt/gogs/log/ /opt/gogs/scripts/给gogs文件加执行权限,并把整个目录归属给git用户:
chown -R git:git /opt/gogs chmod +x /opt/gogs/gogs4.2 手工写配置文件app.ini
Gogs支持通过浏览器安装向导生成配置,也支持提前手工写好custom/conf/app.ini。我的习惯是手工写,因为用脚本自动化部署时更方便,而且不会因为填错表单反复重启。
先创建目录:
mkdir -p /opt/gogs/custom/conf然后编辑/opt/gogs/custom/conf/app.ini:
APP_NAME = Gogs RUN_USER = git RUN_MODE = prod [server] PROTOCOL = http DOMAIN = git.example.com HTTP_ADDR = 127.0.0.1 HTTP_PORT = 3000 ROOT_URL = http://git.example.com/ DISABLE_SSH = false SSH_PORT = 2222 START_SSH_SERVER = false [database] TYPE = mysql HOST = 127.0.0.1:3306 NAME = gogs USER = gogs PASSWD = 你的数据库密码 SSL_MODE = disable PATH = /opt/gogs/data/gogs.db [repository] ROOT = /home/git/gogs-repositories DEFAULT_BRANCH = main [service] DISABLE_REGISTRATION = true REQUIRE_SIGNIN_VIEW = true几个关键点:
RUN_USER = git这个必须和运行用户一致,别用root。HTTP_ADDR = 127.0.0.1表示Gogs只在本机监听,后续靠Nginx转发,安全一些。如果你不想用Nginx,想直接IP:3000访问,就把HTTP_ADDR改成0.0.0.0,同时防火墙放行3000端口。
DOMAIN和ROOT_URL一定要填对外访问的域名或IP,不然页面上生成的仓库clone地址会是127.0.0.1,别人根本连不上。
SSH_PORT = 2222这里我用的是自定义SSH端口,如果你服务器SSH就是22,就写22。这个配置会直接影响Gogs页面上显示的SSH clone地址,必须写对。
4.3 第一次启动验证
配置写完后,先别急着配systemd,用前台方式启动一次,看看日志有没有报错:
cd /opt/gogs sudo -u git /opt/gogs/gogs web如果一切正常,会看到类似监听127.0.0.1:3000的日志。这时浏览器访问http://服务器IP:3000,能打开页面。
注意cd /opt/gogs这步很重要,因为Gogs默认会找当前目录下的custom/conf/app.ini。如果你在别的目录执行/opt/gogs/gogs web,它可能根本读不到你的配置。到时候service文件里也要把WorkingDirectory设置成/opt/gogs。
确认正常后,Ctrl+C停掉进程,继续下一步。
5. 用systemd守护Gogs进程
5.1 编写service文件
裸跑Gogs关了终端它就没了,生产环境必须交给systemd托管。创建一个service文件:
vim /etc/systemd/system/gogs.service内容如下:
[Unit] Description=Gogs After=network.target Wants=network.target [Service] User=git Group=git WorkingDirectory=/opt/gogs ExecStart=/opt/gogs/gogs web --config /opt/gogs/custom/conf/app.ini Restart=always RestartSec=5 Environment=USER=git Environment=HOME=/home/git [Install] WantedBy=multi-user.target然后是重载并启动:
systemctl daemon-reload systemctl enable --now gogs systemctl status gogs看到active (running)就成功了。查看日志用:
journalctl -u gogs -f这里解释一下为什么Environment=HOME=/home/git。之前遇到过一个问题:systemd启动的进程默认HOME可能是/root,导致git用户下执行某些命令时读取不到家目录配置。显式指定HOME后,SSH key读写、缓存目录都正常了。
5.2 防火墙与安全组放行
生产服务器大概率开着防火墙,CentOS 7默认是firewalld。
我建议先用Nginx做反代,所以只需要放行HTTP/HTTPS端口,不需要直接暴露3000。但如果只是内网测试,直接放行3000也简单:
firewall-cmd --permanent --add-port=3000/tcp firewall-cmd --reload如果用了Nginx反代,放行80和443:
firewall-cmd --permanent --add-service=http firewall-cmd --permanent --add-service=https firewall-cmd --reload另外要确认云厂商安全组也放行了对应端口,不然本地防火墙全开也连不上。这个坑我踩过一次,本地怎么测都通,换外网就超时,最后查半天发现是安全组没加规则。
6. 用Nginx反向代理对外提供服务
6.1 为什么要套一层Nginx
Gogs本身支持HTTP、HTTPS直接跑,但实际部署我还是建议在前面加个Nginx。原因有三:
一是Nginx处理静态资源、并发连接的能力强,能扛住比Gogs单进程更高的访问量。
二是方便统一管理证书。Gogs虽然可以配置TLS证书,但证书续期、多域名配置、日志切割这些还是Nginx更顺手。
三是能隐藏Gogs实际监听端口。Gogs跑在3000,外面只开80/443,安全性和整洁度都更好。
6.2 Nginx配置实战
安装Nginx:
yum install -y nginx systemctl enable --now nginx如果CentOS 7的默认源没有nginx,就得先装epel:
yum install -y epel-release然后创建虚拟主机配置:
vim /etc/nginx/conf.d/gogs.conf内容:
server { listen 80; server_name git.example.com; client_max_body_size 100m; 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 100m这个很重要。默认Nginx上传大小限制是1MB,如果你通过Web页面上传大压缩包或者push较大的二进制文件,不调这个一定报413。
proxy_set_header这些头也必须带,不然Gogs拿到的请求地址全是127.0.0.1,页面上生成的clone链接就可能不对。
然后检查配置并重载:
nginx -t systemctl reload nginx如果你还要上HTTPS,在同一个server块里配置证书路径,监听443,或者用certbot自动申请证书,这里不再展开。
还要注意SELinux。CentOS默认开启SELinux,Nginx往本机3000端口转发时需要放行:
setsebool -P httpd_can_network_connect 1如果不做这步,你会看到Nginx能启动,但访问时一直502。这一点是我在CentOS上遇到过的最多的问题。
6.3 SSH访问的配置补充
Gogs除了HTTP clone,还可以走SSH协议。如果你的用户习惯用SSH方式clone,还需要让git用户能通过SSH登录。
最简单的方式:直接复用系统的sshd端口22。如果你服务器22端口被占用或者为了安全改了自定义端口,要把Gogs配置文件里的SSH_PORT改成和sshd一致,同时防火墙放行该端口。
然后在Gogs网页后台的个人设置里,把用户本地的公钥填进去。最后clone地址会是类似:
git@git.example.com:username/repo.git这里有个常见误区:如果你改了sshd端口,比如改成2222,但Gogs页面里SSH_PORT还写的22,用户复制出来的地址就是错的,连不上。
还有一点,如果你不想通过系统SSH服务暴露git用户,也可以用Gogs内置的SSH服务器,把配置文件里START_SSH_SERVER设为true,并指定SSH_PORT,然后这个端口单独给Gogs用。但这种情况需要确保系统ssh和Gogs内置ssh端口不冲突,我一般不推荐,除非你对Linux用户管理很熟练。
7. 备份、升级与常见问题速查
7.1 备份策略与脚本
Gogs最核心的数据有三块:
| 数据 | 位置 |
|---|---|
| 配置文件 | /opt/gogs/custom/ |
| 仓库数据 | /home/git/gogs-repositories/ |
| 数据库 | SQLite文件或MySQL库 |
只要这三样都在,换一台机器也能完整恢复。
我自己写了个简单的备份脚本放/usr/local/bin/backup_gogs.sh:
#!/bin/bash BACKUP_DIR=/backup/gogs DATE=$(date +%Y%m%d) mkdir -p $BACKUP_DIR/$DATE # 备份配置 cp -r /opt/gogs/custom $BACKUP_DIR/$DATE/ # 备份仓库 cp -r /home/git/gogs-repositories $BACKUP_DIR/$DATE/ # 备份数据库,这里以MySQL为例 mysqldump -h127.0.0.1 -ugogs -p'数据库密码' gogs > $BACKUP_DIR/$DATE/gogs.sql # 打包 tar -czf $BACKUP_DIR/gogs-$DATE.tar.gz -C $BACKUP_DIR/$DATE . rm -rf $BACKUP_DIR/$DATE find $BACKUP_DIR -name "*.tar.gz" -mtime +30 -delete如果用SQLite,备份时不要直接cp,建议用sqlite3的备份命令:
sqlite3 /opt/gogs/data/gogs.db ".backup '/backup/gogs/gogs.db'"因为SQLite在运行时直接复制文件可能得到一个不一致的副本,尤其正在写入时。
最后加个定时任务:
crontab -e 0 2 * * * /bin/bash /usr/local/bin/backup_gogs.sh > /dev/null 2>&1每天凌晨2点自动备份一次,保留30天。
7.2 升级流程
升级Gogs不难,但要按顺序走,别直接覆盖custom目录。
我的流程是这样:
systemctl stop gogs cp -r /opt/gogs/custom /tmp/custom_backup # 下载新版压缩包并解压到临时目录 cd /tmp wget 新版gogs包 tar -xzvf gogs_new.tar.gz # 只替换二进制文件 cp /tmp/gogs/gogs /opt/gogs/gogs chown git:git /opt/gogs/gogs systemctl start gogs启动后看下日志,Gogs会自动执行数据库迁移,一般不需要手动改表结构。
升级前千万备份,尤其是custom/conf/app.ini。我有一次图省事全部覆盖,结果配置被新版默认模板顶掉,服务起不来,耽误了不少时间。
7.3 常见问题排查
| 现象 | 可能原因 | 解决办法 |
|---|---|---|
| 页面无法访问 | 服务没起来、防火墙、安全组 | systemctl status gogs,检查日志和firewall-cmd |
| Nginx访问502 | SELinux拦截 | setsebool -P httpd_can_network_connect 1 |
| clone地址不对 | DOMAIN/ROOT_URL配置错误 | 修改app.ini后重启 |
| Web上传大文件报413 | Nginx默认限制1MB | 设置client_max_body_size |
| 数据库连接失败 | 密码错、host不对、数据库没启动 | 逐项检查,用命令行连一次 |
| push时卡住或超时 | 网络代理、大文件、SSH超时 | 调整Nginx proxy_read_timeout,检查带宽 |
| 以root启动后仓库权限错 | RUN_USER和实际运行用户不一致 | 全目录chown给git,再用git用户启动 |
| 收发邮件不工作 | SMTP配置不对 | 检查app.ini里的mailer段和日志 |
这些基本覆盖了常见问题。我个人的体会是,Gogs部署本身并不复杂,真正容易出问题的都是周边环境:SELinux、防火墙、配置文件里的域名写错,这几个坑占了我遇到问题的八成。
如果你照着这篇走一遍,还是没跑起来,优先看日志,Gogs的日志都在/opt/gogs/log/目录下,比瞎猜准得多。最后再提一个实用习惯:在做任何配置修改之前,先备份一遍custom目录和数据库。改完重启,验证没问题再该干嘛干嘛。Git服务最重要的不是跑起来,是数据别丢。