Cgit 1.3.1 Docker Compose 部署指南
Cgit 无官方容器镜像(2026-10-27 实查),本文以多阶段 Dockerfile 从官方源码包自建 cgit:1.3.1 镜像(308MB),Compose 一条命令拉起 nginx+fcgiwrap+Cgit 1.3.1 浏览站,含数据持久化、配置挂载与 fcgiwrap socket 排障实录。
Cgit 1.3.1 Docker Compose 部署指南
目标:用 Docker Compose 一条命令拉起「nginx + fcgiwrap + Cgit 1.3.1」完整 Git 仓库浏览站。因 Cgit 官方未发布任何容器镜像(2026-10-27 实查 Docker Hub 无官方仓库),本文采用多阶段 Dockerfile 从官方源码包自建镜像
cgit:1.3.1并如实说明,全部步骤在 Ubuntu 22.04 + Docker 实测通过。
一、环境信息
- 宿主机:Ubuntu 22.04 LTS,x86_64,Docker Engine 24+(含 compose 插件)
- 镜像:
cgit:1.3.1(自建,308MB;基础镜像 ubuntu:22.04) - 应用版本:Cgit 1.3.1(内嵌 Git 2.54.0)+ nginx 1.18.0 + fcgiwrap
- Compose 项目名:
cgit-1.3.1-stack(显式 name,防与其他栈互删) - 容器名:
cgit-1.3.1-web;端口映射:宿主8145→ 容器80 - 网络:
cgit-net(external 桥接网络);数据卷:./repos(仓库 bind mount)+cgit-cache(页面缓存命名卷)
二、镜像选型说明
先给结论:Cgit 没有官方容器镜像。2026-10-27 实查:
- Docker Hub 无
library/cgit官方镜像,第三方镜像零星且全部停留在旧版、无 1.3.1; - 上游官方(git.zx2c4.com/cgit)只发布源码 tar 包,不提供容器构建产物;
- Cgit 本体是一个 CGI 二进制,运行还需 nginx + fcgiwrap 配套,官方不发镜像与其「单 CGI 程序」定位一致。
因此本文方案为自建镜像:多阶段 Dockerfile——第一阶段从官方源码包编译 cgit-1.3.1(内嵌 git-2.54.0),第二阶段以 ubuntu:22.04 为底安装 nginx/fcgiwrap 并拷入编译产物。最终镜像 308MB(docker images 实测),运行期内容仅 nginx + fcgiwrap + cgit.cgi,无编译链残留。
三、前置条件
docker version --format '{{.Server.Version}}'
docker compose version
确认 Docker 与 compose 插件可用。准备项目目录与素材(源码包需提前下载并校验,下载与 SHA256 实测值见《Ubuntu 22.04 安装 Cgit 1.3.1 指南》第五章):
mkdir -p /opt/cgit-1.3.1-stack
cd /opt/cgit-1.3.1-stack
ls
cgit-1.3.1.tar.xz git-2.54.0.tar.xz Dockerfile cgitrc default.conf entrypoint.sh docker-compose.yml repos/
四、部署步骤
4.1 Dockerfile(多阶段自建镜像)
# 构建阶段:编译 cgit 1.3.1(官方未发布容器镜像,自建)
FROM ubuntu:22.04 AS builder
ENV DEBIAN_FRONTEND=noninteractive
RUN apt-get update && apt-get install -y --no-install-recommends \
build-essential libssl-dev zlib1g-dev pkg-config xz-utils ca-certificates \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /build
COPY cgit-1.3.1.tar.xz git-2.54.0.tar.xz ./
RUN tar -xJf cgit-1.3.1.tar.xz && tar -xJf git-2.54.0.tar.xz \
&& rm -rf cgit-1.3.1/git && mv git-2.54.0 cgit-1.3.1/git
WORKDIR /build/cgit-1.3.1
RUN make -j"$(nproc)" NO_LUA=1 && make install NO_LUA=1
# 运行阶段:nginx + fcgiwrap + cgit.cgi
FROM ubuntu:22.04
ENV DEBIAN_FRONTEND=noninteractive
RUN apt-get update && apt-get install -y --no-install-recommends \
nginx fcgiwrap git gzip xz-utils \
&& rm -rf /var/lib/apt/lists/*
COPY --from=builder /var/www/htdocs/cgit /var/www/htdocs/cgit
COPY --from=builder /usr/local/lib/cgit/filters /usr/local/lib/cgit/filters
COPY cgitrc /etc/cgitrc
COPY default.conf /etc/nginx/conf.d/default.conf
RUN rm -f /etc/nginx/sites-enabled/default \
&& mkdir -p /var/lib/git /var/cache/cgit \
&& chown -R www-data:www-data /var/cache/cgit
COPY entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh
EXPOSE 80
VOLUME ["/var/lib/git", "/var/cache/cgit"]
ENTRYPOINT ["/entrypoint.sh"]
要点:rm -rf cgit-1.3.1/git && mv git-2.54.0 cgit-1.3.1/git 是 Cgit 特有构建约定(Git 源码必须嵌入 cgit 源码树的 git/ 子目录);NO_LUA=1 裁掉可选 Lua 过滤器依赖。
4.2 entrypoint.sh(含 socket 残留规避)
#!/bin/sh
set -e
# fcgiwrap 以 www-data 运行 CGI,socket 放 www-data 自有目录
mkdir -p /run/fcgiwrap
chown www-data:www-data /run/fcgiwrap
# 清理重启残留的 socket 文件,否则 fcgiwrap 报 "Address already in use"
rm -f /run/fcgiwrap/fcgiwrap.socket
su -s /bin/sh www-data -c "fcgiwrap -s unix:/run/fcgiwrap/fcgiwrap.socket" &
i=0; while [ ! -S /run/fcgiwrap/fcgiwrap.socket ] && [ $i -lt 50 ]; do sleep 0.1; i=$((i+1)); done
exec nginx -g "daemon off;"
⚠️ 排障实录:第 8 行
rm -f必不可少。fcgiwrap 启动时若 socket 路径已存在(容器重启而 /run 被持久化、或 entrypoint 重入),会直接失败退出,实测报错:Failed to bind: Address already in use容器场景 /run 默认是 tmpfs 本应干净,但只要把 socket 放到了挂载卷/自定义 tmpfs 之外的可写层路径,重启即踩坑——启动前清理 socket 是 fcgiwrap 容器化的标准动作。等 socket 就绪的 while 轮询(最多 5 秒)保证 nginx 拉起时 fcgiwrap 已可接客,避免首波请求 502。
4.3 nginx 站点配置 default.conf
server {
listen 80 default_server;
server_name _;
location /cgit-css/ {
alias /var/www/htdocs/cgit/;
}
location ~ ^/cgit(/.*)?$ {
fastcgi_pass unix:/run/fcgiwrap/fcgiwrap.socket;
fastcgi_param SCRIPT_FILENAME /var/www/htdocs/cgit/cgit.cgi;
fastcgi_param PATH_INFO $1;
include fastcgi_params;
}
location = /cgit { return 301 /cgit/; }
location = / { return 301 /cgit/; }
}
关键点是 PATH_INFO $1 剥离 /cgit 前缀(否则 Cgit 把 cgit 当仓库名解析);socket 路径与 entrypoint 中 fcgiwrap 的监听路径一致。
4.4 docker-compose.yml
name: cgit-1.3.1-stack
services:
cgit:
build: .
image: cgit:1.3.1
container_name: cgit-1.3.1-web
ports:
- "8145:80"
volumes:
- ./repos:/var/lib/git
- cgit-cache:/var/cache/cgit
restart: unless-stopped
networks:
- cgit-net
volumes:
cgit-cache:
networks:
cgit-net:
external: true
name: cgit-net
4.5 建网、构建、启动
docker network create cgit-net
cd /opt/cgit-1.3.1-stack
docker compose build
构建输出节选(实测首尾):
#0 building with "default" instance using docker driver
#1 [internal] load build definition from Dockerfile
#1 transferring dockerfile: 1.36kB done
...
#11 [builder 7/7] RUN make -j"$(nproc)" NO_LUA=1 && make install NO_LUA=1
#11 CACHED
...
#20 naming to docker.io/library/cgit:1.3.1 done
#20 unpacking to docker.io/library/cgit:1.3.1 0.0s done
#20 DONE 0.2s
启动并确认状态:
docker compose up -d
docker ps --filter name=cgit-1.3.1-web --format '{{.Names}}\t{{.Image}}\t{{.Status}}\t{{.Ports}}'
cgit-1.3.1-web cgit:1.3.1 Up 26 minutes 0.0.0.0:8145->80/tcp, [::]:8145->80/tcp
4.6 验证
容器内进程全景(实测):
docker exec cgit-1.3.1-web ps aux
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 1 0.0 0.0 55220 12424 ? Ss 09:43 0:00 nginx: master process nginx -g daemon off;
root 10 0.0 0.0 6220 3776 ? S 09:43 0:00 su -s /bin/sh www-data -c fcgiwrap -s unix:/run/fcgiwrap/fcgiwrap.socket
www-data 12 0.0 0.0 2900 1892 ? Ss 09:43 0:00 sh -c fcgiwrap -s unix:/run/fcgiwrap/fcgiwrap.socket
www-data 13 0.0 0.0 6252 2620 ? S 09:43 0:00 fcgiwrap -s unix:/run/fcgiwrap/fcgiwrap.socket
www-data 14 0.0 0.0 55548 3432 ? S 09:43 0:00 nginx: worker process
...
HTTP 层验证(宿主机):
curl -s http://127.0.0.1:8145/cgit/ | grep -E "generator|footer"
<meta name='generator' content='cgit v1.3.1'/>
<div class='footer'>generated by <a href='https://git.zx2c4.com/cgit/about/'>cgit v1.3.1</a> (<a href='https://git-scm.com/'>git 2.54.0</a>) at 2026-10-27 10:13:10 +0000</div>
浏览器访问 http://<宿主机IP>:8145/cgit/ 即可看到仓库列表页。
五、数据持久化说明
| 路径 | 类型 | 内容 | 备份建议 |
|---|---|---|---|
./repos → /var/lib/git | bind mount | 全部裸仓库(真实数据) | 纳入常规备份;新增仓库直接拷入该目录即被 scan-path 发现 |
cgit-cache → /var/cache/cgit | 命名卷 | HTML 页面缓存 | 不需要备份,丢了自动重建 |
往 ./repos 里放裸仓库即可上线展示(无需重启):
cd /opt/cgit-1.3.1-stack/repos
git init --bare demo-hello.git
echo "cgit compose 演示仓库" > demo-hello.git/description
chown -R 33:33 demo-hello.git # 33=容器内 www-data
六、环境变量表
本镜像未定义应用级环境变量——Cgit 的全部行为由 /etc/cgitrc 控制(CGI 程序无 env 配置面)。可调项仅为镜像/Compose 层:
| 变量 | 默认 | 说明 |
|---|---|---|
DEBIAN_FRONTEND=noninteractive | 镜像内置 | 构建期 apt 静默,无需改 |
端口 8145:80 | compose 文件 | 宿主端口按规划改左侧即可 |
restart: unless-stopped | compose 文件 | 生产建议保留 |
cgitrc 参数调整走「八、配置文件挂载」的重建流程。
七、配置参数说明
镜像内置 /etc/cgitrc(与 B1 裸机版同一份,完整逐项释义见《Cgit 1.3.1 配置参数详解》篇):
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
snapshots=tar.gz tar.xz
enable-git-config=1
enable-index-owner=1
enable-commit-graph=1
enable-log-filecount=1
enable-log-linecount=1
section-from-path=1
virtual-root=/cgit/
scan-path=/var/lib/git
容器化场景特别注意:cache-root=/var/cache/cgit 与命名卷对应;scan-path=/var/lib/git 与 bind mount 对应;virtual-root=/cgit/ 与 nginx location 前缀三者必须一致。
八、配置文件挂载
cgitrc 与 default.conf 在构建期 COPY 进镜像(配置即代码,镜像自包含)。若希望不改镜像直接换配置,改用 bind mount 覆盖——compose 的 volumes 增加两行:
volumes:
- ./repos:/var/lib/git
- cgit-cache:/var/cache/cgit
- ./cgitrc:/etc/cgitrc:ro
- ./default.conf:/etc/nginx/conf.d/default.conf:ro
改完配置后重载生效:
docker exec cgit-1.3.1-web nginx -s reload # 改 nginx 配置时
docker restart cgit-1.3.1-web # 改 cgitrc 时(CGI 每请求新进程,其实仅清缓存即可:docker exec cgit-1.3.1-web sh -c 'rm -rf /var/cache/cgit/*')
九、等价 docker run
不依赖 compose 文件的等价命令(供理解全貌,推荐仍用 compose):
docker build -t cgit:1.3.1 /opt/cgit-1.3.1-stack
docker network create cgit-net
docker volume create cgit-cache
docker run -d --name cgit-1.3.1-web --restart unless-stopped \
--network cgit-net \
-p 8145:80 \
-v /opt/cgit-1.3.1-stack/repos:/var/lib/git \
-v cgit-cache:/var/cache/cgit \
cgit:1.3.1
十、常用运维命令
# 查看日志(nginx access/error 均打到 stdout/stderr)
docker logs -f cgit-1.3.1-web
# 进容器排查
docker exec -it cgit-1.3.1-web bash
# 清页面缓存(改 cgitrc 后或页面疑似陈旧)
docker exec cgit-1.3.1-web sh -c 'rm -rf /var/cache/cgit/*'
# 重启 / 停止 / 删除栈
docker compose restart
docker compose down # 保留卷与镜像
docker compose down -v # 连缓存卷一起删(仓库在 ./repos 不受影响)
# 升级 Cgit 版本:替换源码包、改 Dockerfile 版本号后
docker compose build --no-cache && docker compose up -d
十一、常见问题(FAQ)
11.1 容器起来了但访问 502 Bad Gateway
现象:nginx 日志 connect() to unix:/run/fcgiwrap/fcgiwrap.socket failed。定位:fcgiwrap 未起来或 socket 路径不一致——最常见是重启后残留 socket 导致 fcgiwrap Failed to bind: Address already in use 退出(见 4.2 排障实录)。解决:确认 entrypoint 含 rm -f socket 行;docker exec 进去 ls -la /run/fcgiwrap/ 核对 socket 存在且属 www-data。
11.2 仓库拷进 ./repos 但列表页看不到
定位:①必须是不带工作区的裸仓库(git init --bare 或 git clone --bare 产物);②属主须可读(容器内 www-data,uid 33);③cache-scanrc-ttl=1 意味着扫描结果缓存 1 分钟,急见效果可清缓存。解决:chown -R 33:33 repos/<repo>.git 后等 1 分钟或清缓存。
11.3 页面无样式
定位:/cgit-css/ 404。解决:核对 default.conf 的 alias 指向 /var/www/htdocs/cgit/(构建期已 COPY 静态资源到该路径),且 cgitrc 的 css=/cgit-css/cgit.css 与之呼应。
11.4 自建镜像构建慢
编译内嵌 Git 是全量 C 编译,首次构建数分钟属正常;层缓存机制下改 cgitrc/default.conf 重构建秒级完成(#11 CACHED 即证)。拉取 ubuntu:22.04 与源码包慢时走代理:docker build --build-arg https_proxy=http://192.168.1.62:7897 .(需 Dockerfile 兼容)或配置 Docker daemon 代理。
11.5 想换 Cgit 版本
下载新版 cgit-<ver>.tar.xz 与对应内嵌 Git 包放入项目目录,改 Dockerfile 中两处文件名,docker compose build --no-cache && docker compose up -d 即可;cgitrc 跨版本基本兼容。
十二、参考链接
- Cgit 官方仓库:https://git.zx2c4.com/cgit/about/
- cgit-1.3.1 源码包:https://git.zx2c4.com/cgit/snapshot/cgit-1.3.1.tar.xz
- fcgiwrap:https://github.com/gnosek/fcgiwrap
- 裸机部署对照:《Ubuntu 22.04 安装 Cgit 1.3.1 指南》
- 组件选型:《Cgit 1.3.1 介绍与选型指南》