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 排障实录。

CgitCgitGit 服务Docker Compose2026/10/27

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/gitbind 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:80compose 文件宿主端口按规划改左侧即可
restart: unless-stoppedcompose 文件生产建议保留

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 跨版本基本兼容。

十二、参考链接