# 用 Caddy 和容器搭建 Git Over HTTPS 服务器


> 文章中省略了一些有关 容器（Docker/Podman） 的基础知识

想拥有一个像 GitHub 一样通过 HTTPS 访问的私有 Git 服务器，但又不想部署 GitLab 或 Gitea 这样功能强大但相对复杂的系统？本文将向你展示如何利用 Caddy2 和 Docker，以一种极其轻量、高效且安全的方式，在几分钟内快速搭建属于你自己的 Git 服务。

## 最终效果

- **轻量高效**: 基于 Caddy 和原生 Git，资源占用极低。
- **自动 HTTPS**: Caddy 自动管理 TLS 证书，所有传输都加密。
- **简单认证**: 使用 Caddy 内置的 `basic_auth` 实现用户名/密码保护。
- **数据持久化**: Git 仓库和 Caddy 证书都通过 Docker Volume 持久化，确保数据安全。
- **易于维护**: 所有组件打包在容器中，一键启停，轻松迁移。

## 准备工作

在开始之前，请确保你已具备：

1. 一台安装了 `Podman`（或 `Docker`和`Docker Compose`）的服务器。
2. 一个解析到你服务器 IP 的域名（例如 `git.your-domain.com`）。
3. 服务器的 80 和 443 端口已开放，用于 Caddy 申请证书和提供 HTTPS 服务。

## 目录结构

为了方便管理，我们先创建如下的目录和文件结构：

```shell
/my-caddy-git-server
├── Caddyfile
├── compose.yml
├── custom-containerfile/
│   └── Containerfile
├── git-repos/
│   └── (Git 仓库将存放在这里)
└── caddy_data/
    └── (Caddy 的证书和状态将存放在这里)
```

## 1. 构建带 `caddy-cgi` 插件的 Caddy 镜像

我们需要一个包含 `caddy-cgi` 插件的自定义 Caddy 镜像，以便让 Caddy 能够执行 `git-http-backend` 程序。

在 `custom-containerfile/Containerfile` 文件中写入以下内容：

```containerfile
# 阶段 1: Builder - 仅用于编译带有插件的 Caddy
FROM docker.io/library/caddy:2-builder AS builder

# 使用 xcaddy 构建一个带 cgi 插件的 Caddy
# caddy-cgi 插件让 Caddy 可以作为 CGI 网关
RUN xcaddy build \
    --with github.com/aksdb/caddy-cgi/v2

# 阶段 2: 最终运行镜像
FROM docker.io/library/caddy:latest

# 在最终镜像中安装 git-daemon，这样运行环境中才会有 git-http-backend
RUN apk update && apk add --no-cache git git-daemon

# 从 builder 阶段复制我们刚刚编译好的、带插件的 caddy 二进制文件
COPY --from=builder /usr/bin/caddy /usr/bin/caddy
```

这个 Containerfile 使用多阶段构建，最终镜像只包含必要的 `git-daemon` 和带插件的 `caddy`，非常精简。

## 2. 配置 Caddyfile

`Caddyfile` 是 Caddy 的配置文件，我们用它来定义 Git 服务的行为。

在项目根目录的 `Caddyfile` 中写入以下内容：

```caddy
# 你的 Git 服务域名
git.your-domain.com {
    # 启用基础认证保护整个服务
    basic_auth {
        # 使用 `caddy hash-password` 命令生成你的密码哈希
        # 将 "your_username" 替换为你的用户名
        # 将 "$2a$14$..." 替换为生成的哈希密码
        your_username $2a$14$ABC...
    }

    # 将所有请求路由到 git-http-backend
    # 在 Alpine 镜像中，git-http-backend 的路径通常是这个
    cgi * /usr/libexec/git-core/git-http-backend {
        # 关键：设置环境变量，告诉 Git 后端如何工作
        # GIT_PROJECT_ROOT: Git 仓库的根目录，必须与 compose.yml 中的挂载路径一致
        # GIT_HTTP_EXPORT_ALL: 允许客户端发现所有仓库，无需额外配置
        env GIT_PROJECT_ROOT=/git-repos GIT_HTTP_EXPORT_ALL=1
    }
}
```

## 3. 编写 Compose 文件

`compose.yml` 文件将所有部分（自定义镜像、配置文件、数据卷）串联起来。

在项目根目录的 `compose.yml` 中写入以下内容：

```yaml
name: git-server
services:
  git-server:
    # 指定使用我们自定义的 Containerfile 进行构建
    build: ./custom-containerfile
    restart: unless-stopped
    ports:
      # 映射 HTTPS 和 HTTP 端口
      - "443:443"
      - "80:80"
    volumes:
      # 挂载 Caddyfile
      - ./Caddyfile:/etc/caddy/Caddyfile
      # 挂载存放 Git 仓库的目录
      - ./git-repos:/git-repos
      # 挂载 Caddy 数据卷，用于持久化 TLS 证书
      - ./caddy_data:/data
```

## 4. 启动服务并创建仓库

1. **启动服务**
   在 `my-caddy-git-server` 目录下，运行以下命令启动服务：

   ```bash
   podman-compose up -d
   ```

   Compose 会自动构建镜像、创建并启动容器。Caddy 会为你的域名申请并配置好 HTTPS 证书。

2. **创建你的第一个仓库**
   服务启动后，在宿主机的 `git-repos` 目录下创建你的第一个裸仓库（Bare Repository）。

   ```bash
   # 进入存放仓库的目录
   cd git-repos

   # 创建一个名为 my-project.git 的裸仓库
   git init --bare my-project.git
   ```

3. **（可选）迁移现有仓库**
   如果你想从 GitHub 或其他地方迁移一个仓库，可以使用 `--mirror` 选项。

   ```bash
   # 这会在当前目录创建一个 my-awesome-project.git 的镜像裸仓库
   git clone --mirror https://github.com/someuser/my-awesome-project.git
   ```

## 5. 克隆与推送

一切就绪！现在，你可以在任何机器上通过 HTTPS 访问你的 Git 仓库了。Clone URL 的格式为 `https://<你的域名>/<仓库名>.git`。

**克隆仓库：**

```bash
git clone https://git.your-domain.com/my-project.git
```

Git 会提示你输入在 `Caddyfile` 中配置的用户名和密码。验证通过后，仓库就会被成功克隆。

**推送更新：**

```bash
cd my-project
echo "Hello, private Git server!" > README.md
git add .
git commit -m "Initial commit"
git push origin main
```

同样，输入凭证后，你的代码就会被安全地推送到私有服务器上。

## 附：关于 Git Over SSH

本文专注于 Git over HTTPS。如果你更喜欢使用 SSH，其实并不需要 Caddy 或容器。

你只需要在你的服务器上有一个标准的用户账户，并在该服务器上安装了 Git。然后：

1. 在服务器上创建一个裸仓库 (`git init --bare my-repo.git`)。
2. 确保你的 SSH 公钥在服务器用户的 `~/.ssh/authorized_keys` 文件中。
3. 使用 SSH 协议进行克隆：`git clone user@your-domain.com:/path/to/my-repo.git`。

这种方式依赖于系统的 SSH 服务，与本文描述的 HTTPS 服务是完全独立的。

## 进阶：使用 cgi 展示 git 仓库

[使用 Caddy 容器和 Cgit 展示 git 仓库](../cgit)


---

> 作者: Nite  
> URL: https://www.nite07.com/zh-cn/posts/git-server/  

