Cgit 1.3.1 配置参数详解
Cgit 1.3.1 cgitrc 全参数详解:按全局/仓库级/鉴权与安全三类逐项给出作用、取值、默认值与作用域,附 8 组实测回显(root-title、robots、head-include、snapshots、clone-url、section-from-path、max-stats、仓库内 cgitrc)及 start-limit-hit、scan-path 顺序敏感、缓存不失效排障实录。
Cgit 1.3.1 配置参数详解
目标:把 Cgit 1.3.1 的
cgitrc讲透——按「全局参数 / 仓库级参数 / 鉴权与安全」三类,逐项给出作用、取值、默认值与作用域,并用 8 组参数实测回显佐证关键行为。全部结论基于官方cgitrc.5手册与 1.3.1 源码,实测环境为本机已部署实例(Ubuntu 22.04,nginx + fcgiwrap + cgit 1.3.1,访问地址http://127.0.0.1:8144/cgit/)。
一、配置文件的位置与解析规则
1.1 位置与加载顺序
| 项目 | 说明 |
|---|---|
| 编译期默认路径 | /etc/cgitrc |
| 运行期覆盖 | 环境变量 CGIT_CONFIG 指向的文件优先(CGI 场景可在 nginx 的 fastcgi_param 中注入) |
| 格式 | 逐行 NAME=VALUE;空行与以 # 开头的行被忽略 |
| 包含 | include=/path 在当前位置插入另一份配置;include=/etc/cgitrc.d/$HTTP_HOST 可按 Host 做虚拟主机分流 |
| 优先级 | 同一键后出现的覆盖先出现的(repo.* 段内同理) |
1.2 三条必须先记住的规则
- 顺序敏感:
scan-path之前出现的全局键才会被「扫描发现」的仓库继承。写在scan-path之后的全局键只影响显式repo.*定义的仓库——这一点直接决定了max-stats、snapshots、section-from-path、cache-*等键该放哪。 - 行内注释会被当作值(官方 BUGS 章节明示)。
robots=index # allow indexing生成的不是index,而是index # allow indexing,实测回显见第五章 T2。 - 配置无需重启进程:cgit 每个请求都会重新读取
cgitrc,改完只要让页面缓存失效即可(见 1.3)。反复重启服务反而容易触发 systemd 启动频率限制(见第六章)。
1.3 改完配置怎么让它生效
# 1) 让配置立刻可读(cgit 每请求重读,无需重启)
# 2) 清页面缓存:cgitrc 的 cache-root 目录
rm -rf /var/cache/cgit/*
# 3) 平滑重载前端,让新的 fastcgi 参数/静态映射生效
nginx -s reload
若确实需要重启后端 CGI 服务,请间隔 10 秒以上,或被 systemd 拒绝后执行一次 systemctl reset-failed(原因见 6.1)。
二、全局参数(写在 scan-path 之前的才算「全局默认值」)
2.1 站点外观与 SEO
| 参数 | 作用 | 取值 | 默认值 | 作用域 |
|---|---|---|---|---|
css | 页面样式表 URL;可重复出现多次,按顺序全部插入 <head> | URL 路径 | /cgit.css | 全局 |
js | 引入的脚本 URL;置为空串可去掉该 <script> | URL 路径或空 | /cgit.js | 全局 |
logo | 页头 logo 图片 URL | URL 路径 | /cgit.png | 全局 / repo.logo |
logo-link | 点击 logo 跳转的地址;不设则指向仓库首页 | URL | 无(自动计算) | 全局 / repo.logo-link |
favicon | 浏览器图标 URL | URL 路径 | /favicon.ico | 全局 |
robots | <meta name='robots'> 的内容 | 任意字符串(原样输出) | index, nofollow | 全局 |
head-include | 指定文件的内容原样插入所有页面 <head> | 文件路径 | 无 | 全局 |
header | 指定文件的内容原样插入页面顶部 | 文件路径 | 无 | 全局 |
footer | 指定文件的内容原样插入页面底部(替换默认的 "generated by" 行) | 文件路径 | 无 | 全局 |
root-title | 仓库首页大标题 | 文本 | Git Repository Browser | 全局 |
root-desc | 首页标题下的说明 | 文本 | a fast webinterface for the git dscm | 全局 |
root-readme | 该文件内容原样展示在首页 "about" 位置 | 文件路径 | 无 | 全局 |
local-time | 设为 1 时按服务器时区显示提交时间 | 0/1 | 0 | 全局 |
side-by-side-diffs | 差异默认按左右并排展示 | 0/1 | 0 | 全局 |
说明:任务清单里提到的 txt-file 在 cgit 1.3.1 中并不存在。文本类内容的注入由 root-readme / repo.readme / about-filter 三个键承担,不要照抄别的工具的参数名。
2.2 仓库发现与分组
| 参数 | 作用 | 取值 | 默认值 | 作用域 |
|---|---|---|---|---|
scan-path | 递归扫描该目录下的裸仓库并自动生成 repo.* 列表 | 绝对路径 | 无 | 全局(须在其余默认值之后) |
project-list | 只加载该文件列出的子目录(相对 scan-path) | 文件路径 | 无 | 全局(须在 scan-path 之前) |
section | 其后声明的仓库统一归入该分组 | 文本 | 无 | 全局 |
section-from-path | 取仓库路径的前 N 段作为分组名;负数表示从仓库目录往上丢弃 N 段 | 整数 | 0 | 全局(须在 scan-path 之前) |
section-sort | 是否按名称排序分组;0 保持 cgitrc 中的声明顺序 | 0/1 | 1 | 全局 |
repository-sort | 分组内按 name 或 age 排序 | name/age | name | 全局 |
case-sensitive-sort | 列表排序是否区分大小写 | 0/1 | 1 | 全局 |
remove-suffix | 扫描到的 xxx.git 在 URL 与显示名中去掉 .git 后缀 | 0/1 | 0 | 全局(须在 scan-path 之前) |
scan-hidden-path | 是否递归进入以 . 开头的目录 | 0/1 | 0 | 全局(须在 scan-path 之前) |
readme | 仓库 About 页的默认文件名候选,可写多行,取第一个存在的 | 相对仓库路径 | 无 | 全局默认值 |
agefile | 记录仓库「最新提交时间」的文件,供列表显示 Idle | 相对仓库路径 | info/web/last-modified | 全局 |
strict-export | 仅当仓库内存在该标记文件时才允许访问(见第四章) | 文件名 | 无 | 全局(须在 scan-path 之前) |
enable-git-config | 允许读取仓库自身 git config 覆盖 desc/owner/section/homepage | 0/1 | 0 | 全局(须在 scan-path 之前) |
enable-filter-overrides | 允许仓库级 cgitrc 覆盖各类 filter | 0/1 | 无(关) | 全局 |
scan-path 有一个容易被忽略的副作用:开启缓存后,扫描结果本身会被写成缓存目录里的一个 include 文件,由 cache-scanrc-ttl 控制新鲜度。新增仓库后没出现,先清缓存或把该 TTL 调小。
2.3 快照与克隆地址
| 参数 | 作用 | 取值 | 默认值 | 作用域 |
|---|---|---|---|---|
snapshots | 默认生成哪些格式的源码快照链接 | 空格分隔的 tar/tar.gz/tar.bz2/tar.lz/tar.xz/tar.zst/zip,或 all | 无(不生成) | 全局 / repo.snapshots |
repo.snapshots | 仓库级掩码,只能在全局集合内做减法;0 表示关闭 | 同上 / 0 | 继承全局 | 仓库 |
repo.snapshot-prefix | 快照文件名前缀,替代仓库 basename | 文本 | 空 | 仓库 |
clone-url | 克隆地址模板(空格分隔可多条),支持 $CGIT_REPO_* 宏 | 模板串 | 无 | 全局 / repo.clone-url |
clone-prefix | 与仓库 URL 拼接生成克隆地址的公共前缀 | 空格分隔前缀 | 无 | 全局(repo.clone-url 未设时生效) |
enable-http-clone | 允许 cgit 兼作 dumb HTTP 克隆端点 | 0/1 | 1 | 全局 |
2.4 缓存
| 参数 | 作用 | 取值 | 默认值 | 作用域 |
|---|---|---|---|---|
cache-root | 缓存目录 | 绝对路径(支持 $VAR 宏) | /var/cache/cgit | 全局 |
cache-size | 缓存条目上限;0 关闭缓存 | 整数 | 0 | 全局 |
cache-dynamic-ttl | 无固定 SHA1 的仓库页面缓存分钟数 | 分钟 | 5 | 全局 |
cache-repo-ttl | 仓库 summary 页缓存分钟数 | 分钟 | 5 | 全局 |
cache-root-ttl | 仓库首页(index)缓存分钟数 | 分钟 | 5 | 全局 |
cache-static-ttl | 指定 SHA1 的页面缓存分钟数;-1 表示永不过期 | 分钟 | -1 | 全局 |
cache-scanrc-ttl | 扫描结果缓存分钟数 | 分钟 | 15 | 全局 |
cache-about-ttl | About 页缓存分钟数 | 分钟 | 15 | 全局 |
cache-snapshot-ttl | 快照缓存分钟数 | 分钟 | 5 | 全局 |
注意:任务清单里的 cache-ttl 并不是单键,cgit 把它拆成了上面这组 cache-*-ttl。改样式/改配置后仍看到旧页面,九成是这里在生效——手工验证时统一 rm -rf /var/cache/cgit/*。
2.5 展示限额与统计
| 参数 | 作用 | 取值 | 默认值 | 作用域 |
|---|---|---|---|---|
max-repo-count | 首页每页仓库数,0 为不限 | 整数 | 50 | 全局 |
max-repodesc-length | 首页描述列最大字符数 | 整数 | 80 | 全局 |
max-commit-count | log 页每页提交数 | 整数 | 50 | 全局 |
max-message-length | log 页提交信息截断长度 | 整数 | 80 | 全局 |
max-blob-size | 树视图内联展示 blob 的上限(KB),0 不限 | 整数 | 0 | 全局 |
max-atom-items | Atom 订阅条数 | 整数 | 10 | 全局 |
max-stats | 统计页允许的最大周期:week/month/quarter/year;不设则统计功能关闭 | 枚举 | 无(关闭) | 全局(须在 scan-path 之前)/ repo.max-stats |
summary-branches / summary-log / summary-tags | summary 页展示的分支/日志/标签条数 | 整数 | 各 10 | 全局 |
renamelimit | diff 重命名检测文件数上限,-1 用 git 编译期默认 | 整数 | -1 | 全局 |
mimetype.<ext> / mimetype-file | plain 视图的 MIME 映射;后者作为回退表(如 /etc/mime.types) | 扩展名 / 文件路径 | 无 | 全局 |
2.6 功能开关(默认值大多为「关」,按需打开)
| 参数 | 作用 | 默认值 | 作用域 |
|---|---|---|---|
enable-blame | 文件 blame 视图及入口链接 | 0 | 全局 / repo.enable-blame |
enable-commit-graph | log 页左侧 ASCII 提交图 | 0 | 全局 / repo.enable-commit-graph |
enable-log-filecount | log 页显示每个提交改动文件数 | 0 | 全局 / repo.enable-log-filecount |
enable-log-linecount | log 页显示增删行数 | 0 | 全局 / repo.enable-log-linecount |
enable-index-links | 首页每行追加 summary/commit/tree 快捷链接 | 0 | 全局 |
enable-index-owner | 首页显示 Owner 列 | 1 | 全局 |
enable-follow-links | log 视图支持「跟踪文件历史」 | 0 | 全局 / repo.enable-follow-links |
enable-html-serving | /plain 允许按 text/html 输出(有 XSS 风险,慎开) | 0 | 全局 / repo.enable-html-serving |
enable-remote-branches | summary/refs 页展示远端分支 | 0 | 全局 / repo.enable-remote-branches |
enable-subject-links | 父提交链接用提交标题作锚文本 | 0 | 全局 / repo.enable-subject-links |
enable-tree-linenumbers | 纯文本 blob 生成行号链接 | 1 | 全局 |
embedded | 只输出可嵌入其他页面的 HTML 片段 | 关 | 全局 |
noheader | 省略标准页头 | 关 | 全局 |
noplainemail | 隐藏完整作者邮箱 | 0 | 全局 |
commit-sort | date / topo 强制提交排序 | 未设 | 全局 / repo.commit-sort |
branch-sort | name / age 分支排序 | name | 全局 / repo.branch-sort |
2.7 安全与访问控制(全局)
| 参数 | 作用 | 取值 | 默认值 |
|---|---|---|---|
auth-filter | 认证过滤器,负责登录表单输出与凭据校验;不设则不做任何认证 | 命令/脚本 | 无 |
strict-export | 仓库内必须存在指定标记文件才对外可见,模拟 gitweb 的 EXPORT_OK | 文件名 | 无 |
enable-http-clone | dumb HTTP 克隆开关;若另有 git-http-backend 提供服务可关掉 | 0/1 | 1 |
enable-html-serving | 是否允许原样输出 HTML 附件 | 0/1 | 0 |
enable-filter-overrides | 是否允许仓库级 cgitrc 改写 filter(涉及执行外部命令,属提权面) | 0/1 | 关 |
auth-filter 的协议要点:cgit 会以不同 action 调用它——authenticate-cookie 时校验 Cookie 并在退出码返回 0/1;authenticate-post 时从 stdin 读 POST 参数,过滤器写出完整 CGI 响应(通常 302 跳转)并附 Set-Cookie;此外还有 body / css 等 action 用于渲染登录界面。官方示例是 filters/simple-authentication.lua。
三、仓库级参数(repo.*)
仓库段的第一行必须是 repo.url,其余键按需跟随。用 scan-path 自动发现时不需要手写这些键,但可以用同名仓库内的 cgitrc 文件覆盖(见 3.3)。
| 参数 | 作用 | 取值 | 默认值 |
|---|---|---|---|
repo.url | 仓库相对访问路径,必须是该段第一个键 | 相对路径 | 无(必填) |
repo.path | 仓库目录绝对路径;非裸仓库指向其 .git | 绝对路径 | 无(必填) |
repo.name | 列表显示名 | 文本 | 等于 repo.url |
repo.desc | 描述 | 文本 | 无 |
repo.owner | 所有者 | 文本 | 无 |
repo.homepage | 仓库主页链接 | URL | 无 |
repo.section | 所属分组,覆盖当前 section | 文本 | 无 |
repo.defbranch | 默认分支;不存在时退回按名排序的第一条,再退回 master | 分支名 | HEAD 指向的分支 |
repo.readme | About 页文件,可写 master:docs/readme.mkd 形式的 refspec;以 : 开头用查询中的分支/默认分支 | 相对路径/refspec | 继承全局 readme |
repo.about-filter | About 页渲染过滤器(如 Markdown 转 HTML) | 命令 | 无 |
repo.source-filter | 树视图纯文本渲染过滤器(语法高亮) | 命令 | 无 |
repo.email-filter | 作者/提交者邮箱格式化过滤器 | 命令 | 无 |
repo.commit-filter | 提交信息格式化过滤器(如关联工单) | 命令 | 无 |
repo.owner-filter | Owner 列格式化过滤器,替代默认的查询链接 | 命令 | 无 |
repo.snapshots | 该仓库允许的快照格式(全局集合的子集),0 关闭 | 格式列表/0 | 继承全局 |
repo.snapshot-prefix | 快照文件名前缀 | 文本 | 空 |
repo.clone-url | 该仓库的克隆地址列表,优先于全局 clone-url | 模板列表 | 无 |
repo.max-stats | 该仓库允许的最大统计周期 | 枚举 | 无(跟随全局) |
repo.logo / repo.logo-link | 仓库页专用 logo 与跳转 | URL | 继承全局 |
repo.extra-head-content | 追加到该仓库所有页面 <head> 的原文 | HTML 片段 | 无 |
repo.hide | 首页不显示,但直连 URL 仍可访问 | 0/1 | 0 |
repo.ignore | 完全忽略:首页不显示且直连也 404 | 0/1 | 0 |
repo.enable-* | 对应全局开关的仓库级覆盖(blame/commit-graph/follow-links/html-serving/log-filecount/log-linecount/remote-branches/subject-links) | 同全局 | 继承全局 |
3.1 repo.hide 与 repo.ignore 的区别
hide=1:列表消失、URL 仍可访问——适合「不对外宣传但允许直链分享」的仓库。ignore=1:列表消失、直连返回 404——适合归档/敏感仓库。
两者都只影响 cgit 的展示层,不改变磁盘上的仓库,也不影响 git 协议自身的权限。
3.2 仓库级 cgitrc 文件
scan-path 扫描到仓库后,会尝试解析仓库内的 cgitrc 文件。规则:
- 键名去掉
repo.前缀,例如写desc=、snapshots=、owner=; - 不允许出现
repo.url与repo.path; - 各类
filter键只有在全局enable-filter-overrides=1时才被采纳; - 改完仍需清缓存才生效(缓存键包含仓库配置)。
3.3 与全局继承的关系
仓库级值「覆盖」而非「合并」:repo.snapshots 只能从全局集合里挑子集,无法凭空新增全局没开的格式;repo.max-stats 只能在全局允许的范围内调整。若全局不设 snapshots/max-stats,仓库级怎么设都不会出现对应入口。
四、鉴权与安全专项
4.1 认证:auth-filter
cgit 自身没有用户库,认证完全外置给过滤器。三种典型落地方式:
- HTTP Basic:由前端(nginx)做
auth_basic,cgit 不配置auth-filter,最简单但要接受浏览器弹窗。 - 表单登录 + Cookie:
auth-filter指向 Lua/Python 脚本,cgit 输出登录页,脚本校验后返回Set-Cookie,后续authenticate-cookie校验。 - 反向代理单点登录:由前置代理完成认证并注入
REMOTE_USER,cgit 只负责展示。
要点:auth-filter 的返回值语义是「0 无效 / 1 有效」(官方手册原文如此描述 cookie 校验分支),实现时不要按常见 shell 的 0=成功来写。过滤器还会拿到 CGIT_REPO_* 系列环境变量,可据此做按仓库授权。
4.2 导出控制:strict-export
# 全局,且必须写在 scan-path 之前
strict-export=.cgit-export
启用后,只有仓库目录内存在 .cgit-export 标记文件的仓库才对外可见。它模拟 gitweb 的 EXPORT_OK/STRICT_EXPORT,用来让「cgit 能看的仓库」与「git-daemon 导出的仓库」保持一致,避免扫描根目录下误放的临时仓库被公开。
4.3 克隆入口:enable-http-clone
默认 1,cgit 会响应 dumb HTTP 克隆所需的 info/refs、objects/* 等路径。若你已用 git-http-backend 或独立 Git 服务承载克隆,应设为 0,避免两套出口权限不一致。配套的展示项是 clone-url,只影响页面上显示什么地址,不影响实际协议。
4.4 展示层安全开关
enable-index-links:只是给首页加 summary/commit/tree 快捷链接,方便运维检索,本身不涉及权限。enable-html-serving:默认关闭。开启后/plain会按text/html输出,等于允许仓库内的 HTML 文件在本站域名下执行脚本,属于典型 XSS 面,除非仓库内容完全可信,否则保持0。embedded/noheader:用于把 cgit 嵌进既有站点框架。embedded只输出内容片段,noheader保留完整文档但去掉标准页头;两者与鉴权无关,但会改变「谁的外层页面在承载内容」,做 CSP 时需一并考虑。noplainemail:隐藏完整邮箱,减少爬虫收集。
五、8 组参数实测记录
环境:本机已部署实例(Ubuntu 22.04 + nginx + fcgiwrap + cgit 1.3.1),源仓库 demo-hello.git(含 v0.1 标签)与 team/demo-nested.git。每组均为「改 /etc/cgitrc → 清缓存 → nginx -s reload → 抓页面回显」,测完恢复原配置。
| # | 参数 | 观测点 | 结论 |
|---|---|---|---|
| T1 | root-title / root-desc | 首页 <title> 与页头 | 即时生效,两处同步 |
| T2 | robots(含行内注释) | <meta name='robots'> | 值原样输出,注释被吞进值 |
| T3 | head-include | 首页与仓库页 <head> | 文件内容原样插入每一页 |
| T4 | snapshots=zip | summary 快照链接 + 下载 | 只留 zip,下载 200 且可解压 |
| T5 | clone-url 两条模板 | 仓库页 Clone 区 | 两条都渲染,$CGIT_REPO_URL 正确展开 |
| T6 | section-from-path 1→0 | 首页分组行与仓库层级 | 1 时出现 team 分组行,0 时全部平铺 |
| T7 | max-stats 位置 | /stats HTTP 状态 | 写在 scan-path 后不生效(400);前置后 200 |
| T8 | 仓库内 cgitrc | 首页描述/Owner + 快照链接 | 覆盖成功,snapshots=0 关闭快照 |
T1 站点标题与说明
root-title=Quzuo 配置实验室
root-desc=cgitrc 参数实测环境
<title>Quzuo 配置实验室</title>
<td class='main'>Quzuo 配置实验室</td></tr>
<tr><td class='sub'>cgitrc 参数实测环境</td></tr></table>
T2 robots 与行内注释陷阱
<!-- robots=noindex, nofollow -->
<meta name='robots' content='noindex, nofollow'/>
<!-- robots=index # allow indexing -->
<meta name='robots' content='index # allow indexing'/>
第二行是官方 BUGS 章节所述行为的现场复现:注释没有单独成行,而是成为了值的一部分。SEO 配置必须写成独立一行。
T3 head-include
printf '<meta name="x-head" content="v2-after-edit"/>\n' > /etc/cgit/head.html
首页与仓库页回显一致:
<meta name="x-head" content="v2-after-edit"/>
这说明 head-include 是逐字节插入,不做转义、不解析模板;文件改内容后无需改 cgitrc,但仍要清页面缓存。
T4 snapshots 收窄为 zip
snapshots=zip
summary 页快照链接只剩一个:
snapshot/demo-hello-0.1.zip
直接下载验证:
HTTP=200 SIZE=664 TYPE=application/x-zip; charset=UTF-8
/tmp/snap.zip: Zip archive data, at least v1.0 to extract, compression method=store
注意文件名是 demo-hello-0.1.zip——cgit 会自动去掉标签名 v0.1 的前导 v。若想控制前缀,用 repo.snapshot-prefix。
T5 clone-url 多模板与宏展开
clone-url=https://git.quzuo.net/$CGIT_REPO_URL git@git.quzuo.net:$CGIT_REPO_URL
仓库页同时给出两行(<link rel='vcs-git'> 与 Clone 表格各两条):
<link rel='vcs-git' href='https://git.quzuo.net/demo-hello.git' title='demo-hello.git Git repository'/>
<link rel='vcs-git' href='git@git.quzuo.net:demo-hello.git' title='demo-hello.git Git repository'/>
克隆地址只做展示,不改变实际可用协议;$CGIT_REPO_URL 是相对 URL(含子目录时会带上 team/),$CGIT_REPO_PATH 才是磁盘绝对路径,做 SSH 地址时不要混用。
T6 section-from-path 1 与 0
section-from-path=1:
<tr class='nohover-highlight'><td colspan='4' class='reposection'>team</td></tr>
<tr><td class='sublevel-repo'><a href='/cgit/team/demo-nested.git/'>demo-nested.git</a></td>...
section-from-path=0:分组行与 sublevel-repo 计数均为 0,toplevel-repo 计数为 3,三个仓库全部平铺在首页顶层。
结论:该键决定「按路径分层」还是「全部平铺」,且必须在 scan-path 之前定义,否则扫描期已定型的仓库列表不会重算。
T7 max-stats 的位置陷阱
先把它追加在文件末尾(即 scan-path 之后):
stats HTTP=400 SIZE=2519
<div class='error'>Statistics type disabled: week</div>
把 max-stats=quarter 移到 scan-path 之前:
stats HTTP=200 SIZE=3591
<option value='w' selected='selected'>week</option>
<option value='m'>month</option>
这正是 1.2 节「顺序敏感」的实证:全局键写在 scan-path 之后,扫描出的仓库拿不到该默认值,repo.max_stats 仍为 0,统计页直接 400。所有「作用于每个仓库」的全局键都应集中放在 scan-path 之前的区块。
T8 仓库内 cgitrc 覆盖
cat > /var/lib/git/demo-hello.git/cgitrc <<'EOF'
desc=仓库级 cgitrc 覆盖描述
snapshots=0
owner=RepoOwnerFromCgitrc
EOF
首页回显:
<tr><td class='toplevel-repo'><a href='/cgit/demo-hello.git/'>demo-hello.git</a></td><td><a href='/cgit/demo-hello.git/'>仓库级 cgitrc 覆盖描述</a></td><td>
Owner 链接变为 ?q=RepoOwnerFromCgitrc,summary 页 snapshot/ 链接计数为 0。三条覆盖同时生效,且键名均未带 repo. 前缀。
六、排障实录
6.1 systemctl restart 连续调用被拒:start-limit-hit
批量验证时脚本里连续执行 systemctl restart fcgiwrap; systemctl restart nginx,第 5 次之后开始报:
Job for fcgiwrap.service failed.
See "systemctl status fcgiwrap.service" and "journalctl -xeu fcgiwrap.service" for details.
Job for nginx.service failed.
journalctl 给出根因:
fcgiwrap.service: Failed with result 'start-limit-hit'.
Failed to start Simple CGI Server.
nginx.service: Failed with result 'start-limit-hit'.
Failed to start A high performance web server and a reverse proxy server.
systemd 默认 10 秒内最多启动 5 次,超限后直接拒绝,期间站点不可用(表现为 curl 返回空、状态码 000)。处理:
systemctl reset-failed fcgiwrap nginx # 清掉失败计数
nginx -s reload # 日常改配置只需 reload
结论:改 cgitrc 根本不需要重启进程,清缓存 + nginx -s reload 足够;确实要重启时,两次之间留 10 秒以上。
6.2 改了配置页面没变化
按顺序排查:
- 键是否写在了
scan-path之后(T7 的 400 就是这么来的); - 页面缓存是否未失效——
cache-size非 0 时所有页面都有 TTL,手工验证先rm -rf /var/cache/cgit/*; - 仓库内
cgitrc是否覆盖了你改的全局值(T8 的反向效果); - 浏览器/代理缓存:
curl -s直连本机端口可绕过。
6.3 fcgiwrap socket 残留(上轮实证)
重启 fcgiwrap 后若出现 502,且 journalctl 提示无法绑定 socket,通常是 /run/fcgiwrap.socket 残留:旧进程已退出但 socket 文件仍在,新进程 bind 失败。清理后重启即可:
systemctl stop fcgiwrap
rm -f /run/fcgiwrap.socket
systemctl start fcgiwrap
该现象与完整安装链路见《Ubuntu 22.04 安装 Cgit 1.3.1 指南》的排障章节。
6.4 统计页 400「Statistics type disabled」
除了 6.2 的顺序问题,还有一种:全局 max-stats 根本没设。此时 cgit 关闭整个统计功能,访问 /stats 返回 400 并提示 Statistics type disabled: week——这不是故障,而是默认行为。要开放统计,显式设置 max-stats=week|month|quarter|year 并放在 scan-path 之前。
6.5 仓库内 cgitrc 的 filter 不生效
about-filter / source-filter / email-filter / commit-filter / owner-filter 写在仓库内 cgitrc 时,必须同时设置全局 enable-filter-overrides=1,否则静默忽略。这是有意的安全设计:这些键会执行外部命令,不能让仓库内容单方面决定执行什么。
七、一份可直接用的基线配置
# ---- 外观与 SEO ----
css=/cgit-css/cgit.css
logo=/cgit-css/cgit.png
favicon=/cgit-css/favicon.ico
robots=noindex, nofollow
root-title=Quzuo Git Repositories
root-desc=hyperfast web frontend for git repositories, powered by cgit
# ---- 缓存 ----
cache-root=/var/cache/cgit
cache-size=1000
cache-dynamic-ttl=10
cache-repo-ttl=5
cache-static-ttl=-1
cache-scanrc-ttl=1
# ---- 以下全局键必须位于 scan-path 之前 ----
snapshots=tar.gz tar.xz
clone-url=https://git.example.com/$CGIT_REPO_URL
enable-git-config=1
enable-blame=1
enable-index-owner=1
enable-commit-graph=1
enable-log-filecount=1
enable-log-linecount=1
section-from-path=1
max-stats=quarter
virtual-root=/cgit/
# ---- 最后一行:扫描根目录 ----
scan-path=/var/lib/git
八、本篇边界
- Cgit 没有独立的运维 CLI,本专栏不设 D 篇;日常运维动作(清缓存、reload、看 journal)已并入本篇第六、七章。
- 部署方式见本专栏第 3 篇(Compose 编排部署指南),安装与编译见《Ubuntu 22.04 安装 Cgit 1.3.1 指南》,选型对比见《Cgit 1.3.1 介绍与选型指南》。
- 未实测项(仅有手册与源码依据):
auth-filter的完整登录流程与 Cookie 校验、strict-export标记文件的放行/拦截、enable-http-clone的实际git clone往返、remove-suffix与scan-hidden-path对 URL 的影响、enable-index-links的渲染、各cache-*-ttl的精确过期时间、repo.hide与repo.ignore的 404 差异。上述行为均按官方cgitrc.5(1.3.1 自带)描述整理,落地前建议在本机按第五章的方法逐项验证。