简体中文

效果预览

只需要在软件列表文件中添加你想要入库的 github 链接地址即可,比如:

APT 仓库软件列表

当软件列表文件更新后会生成带有索引目录的 APT 仓库

索引目录的 APT 仓库

核心优势

  • 跨平台分发:GitHub Pages(国际) + 阿里云 OSS(国内)双通道
  • 军工级安全:GPG 签名 + 密钥分层管理
  • 极速构建:单次构建耗时 < 2 分钟(实测数据)
  • 零成本起步:GitHub Actions 免费配额

如果你是专家,你可以直接 Fork 我的仓库改改就能用:https://github.com/qlAD/aptRepo

前置知识

APT 仓库如何工作

首先要明白 APT 仓库其实就是一个规范整理的文件夹,里面包含了软件包和索引文件。

具体的目录结构如下:

.
├── conf
│   └── distributions
├── db
│   ├── checksums.db
│   ├── contents.cache.db
│   ├── packages.db
│   ├── references.db
│   ├── release.caches.db
│   └── version
├── dists
│   └── sid
│       ├── InRelease
│       ├── main
│       │   └── binary-amd64
│       │       ├── Packages
│       │       ├── Packages.gz
│       │       └── Release
│       ├── Release
│       └── Release.gpg
└── pool
    └── main
        └── c
            └── clash-verge
                └── clash-verge_2.2.3_amd64.deb

我们需要做的就是整理好这些文件放到一个可以被访问的地方,并且让 APT 客户端知道这个地方。

整理文件很简单,有一个自动化的工具叫做 reprepro,它会自动帮你生成这些文件。

然后把这些文件放到一个可以被访问的地方,比如 Web 服务器、GitHub Pages 或者阿里云 OSS。

最后在 /etc/apt/sources.list.d 中添加一个 .sources 文件,告诉 APT 客户端这个地方在哪里。

# /etc/apt/sources.list.d/qladgk.sources
Types: deb
URIs: https://apt-repo.qladgk.com/debian
Suites: sid
Components: main
Signed-By: /etc/apt/keyrings/qladgk.asc

然后当你运行 apt update 的时候,APT 客户端就会去这个地方下载索引文件,然后根据索引文件去下载软件包。

GPG 签名

GPG 密钥就好像互联网上的另一个自己,私钥就像是你的身份证,公钥就像是你的名片。

公钥可以随意发给别人,私钥必须要保管好。

APT 仓库的软件包都需要进行 GPG 签名,这样才能保证文件的完整性和安全性,或者直接对整个仓库进行签名。

如果你不进行签名,APT 客户端会报错,提示你这个仓库不可信。

如果你泄露了私钥,别人可以通过你的私钥对软件包进行签名,这样就可以伪造软件包,APT 客户端会认为这个软件包是可信的。

部署搭建步骤

1. 生成 GPG 密钥对

首先需要安装 GPG 工具,如果你使用的是 Debian 或 Ubuntu,可以直接使用以下命令安装:

sudo apt install gnupg

接下来生成 GPG 密钥对,使用以下命令:

gpg --full-generate-key

在生成过程中,你需要选择密钥类型、密钥大小、有效期等信息。

其中密钥类型包括如下选项

GPG 密钥类型

其中默认的 ECC(椭圆曲线密码学)提供了更高的安全性与更短的密钥长度,但它在某些旧系统中可能不被支持

所以这里就选择第一项 RSA 和 RSAi 就行

然后密钥大小建议选择 4096 位,这样可以提供更高的安全性

有效期可以根据需要设置,建议设置为 1 年以上,因为 Debian 的 apt 会警告一年内即将过期的密钥,这里我选的是永不过期

当所有信息填完之后会打开密码输入框来加密你的密钥,有密码的好处是即使泄露了私钥,别人也不能通过一个带密码的私钥来签名

全部截图如下:

生成带密码的 GPG 密钥

到此密钥对生成成功,接下来需要把密钥对导出,然后私钥给到 Github Action 让它帮我们自动签名,把公钥暴露在网络上供人使用

2. 导出密钥对

首先我们可以查看刚才创建的密钥对

gpg --list-secret-keys

确认密钥存在后,使用 ASCII 的形式导出

因为我们要把私钥复制到 Github Action 中的环境变量里,所以要用 ASCII 这种方便复制的形式

gpg -a -o public-key.asc --export 你的密钥中的邮箱 #导出公钥
gpg -a -o private-key.asc --export-secret-keys 你的密钥中的邮箱 #导出私钥

导出密钥的时候需要输入你刚才设置的密码

-a 为 –armor 的简写,表示密钥以 ASCII 的形式输出,不加则默认以二进制的形式 gpg 输出

-o 为 –output 的简写,指定写入的文件

全部截图如下:

导出 GPG 密钥

密钥创建并导出之后就可以开始设置 Github 仓库

3. 创建 GitHub 仓库

由于我们要使用 GitHub Actions 来自动化构建 APT 仓库,并且会用到 Github Pages 来搭建仓库的访问地址,所以首先需要一个 GitHub 仓库来存放我们的代码和配置。

首先在 GitHub 上创建一个新的仓库,比如 apt-repo

创建 GitHub 仓库

然后来到仓库的设置页面,允许 Actions 的一些权限

允许 Actions 权限

接着设置一些环境变量,如下

Actions 的环境变量

其中前三个与阿里云的 OSS 相关,如果你没有阿里云的 OSS 可以不设置

后两个是 GPG 的私钥和密码,复制私钥和输入私钥的密码就行

4. 配置 GitHub Actions

在仓库根目录下创建一个 .github/workflows 目录,然后在里面创建一个 update-repo.yml 文件。

内容如下:

name: Update APT Repository

on:
  workflow_dispatch:
  push:
    paths:
      - "packages.list"

jobs:
  build-repo:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Setup Environment
        run: |
          sudo apt-get update
          sudo apt-get install -y reprepro gnupg wget

      - name: Import GPG key
        uses: crazy-max/ghaction-import-gpg@v6
        with:
          gpg_private_key: ${{ secrets.GPG_PRIVATE_KEY }}
          passphrase: ${{ secrets.GPG_PASSPHRASE }}

      - name: Fetch Packages
        run: |
          mkdir -p downloaded_packages
          ./scripts/fetch-packages.sh

      - name: Build Repo
        run: |
          ./scripts/setup-reprepro.sh

      - name: Upload APT Repo to Aliyun OSS
        uses: fangbinwei/aliyun-oss-website-action@v1
        with:
          accessKeyId: ${{ secrets.ACCESS_KEY_ID }}
          accessKeySecret: ${{ secrets.ACCESS_KEY_SECRET }}
          bucket: ${{ secrets.ACCESS_BUCKET_NAME }}
          endpoint: oss-cn-shanghai.aliyuncs.com
          folder: ./gh-pages

      - name: Generate Directory Listings
        uses: jayanta525/github-pages-directory-listing@v4.0.0
        with:
          FOLDER: ./gh-pages

      - name: Upload artifact
        uses: actions/upload-pages-artifact@v3.0.1
        with:
          path: "./gh-pages"

  deploy-index:
    needs: build-repo
    permissions:
      pages: write
      id-token: write
    environment:
      name: github-pages
      url: ${{ steps.deployment.outputs.page_url }}
    runs-on: ubuntu-latest
    steps:
      - name: Deploy to GitHub Pages
        id: deployment
        uses: actions/deploy-pages@v4.0.0

支持手动触发和当 packages.list 有更新后自动触发,当然你也可以设置每周触发一次,但是频率不要太高

如果你不需要阿里云的 OSS 部署就将这部分删掉

- name: Upload APT Repo to Aliyun OSS
  uses: fangbinwei/aliyun-oss-website-action@v1
  with:
    accessKeyId: ${{ secrets.ACCESS_KEY_ID }}
    accessKeySecret: ${{ secrets.ACCESS_KEY_SECRET }}
    bucket: ${{ secrets.ACCESS_BUCKET_NAME }}
    endpoint: oss-cn-shanghai.aliyuncs.com
    folder: ./gh-pages

其中还用到了两个 action 的模板,如果有想了解的自己去看

5. 编写脚本

./scripts/fetch-packages.sh 用于下载软件列表 packages.list 中特点架构的软件包

#!/bin/bash

REPO_LIST="packages.list"
TMP_DIR="downloaded_packages"

while IFS= read -r repo_url; do
  repo_owner=$(echo "$repo_url" | cut -d'/' -f4)
  repo_name=$(echo "$repo_url" | cut -d'/' -f5)

  # 仅下载 amd64 架构的包
  assets=$(curl -s "https://api.github.com/repos/${repo_owner}/${repo_name}/releases/latest" |
           jq -r '.assets[] | select(.name | test(".*_amd64\\.deb$")) | .browser_download_url')

  for asset_url in $assets; do
    wget -P "$TMP_DIR" "$asset_url"
  done
done < "$REPO_LIST"

packages.list 文件中每一行对应一个 Github 仓库

./scripts/setup-reprepro.sh 用来创建 APT 仓库所需要的目录结构

#!/bin/bash

REPO_DIR="gh-pages/debian"
CONF_DIR="repo-config"

# 清理旧数据
rm -rf "$REPO_DIR" "$CONF_DIR"

# 初始化配置目录
mkdir -p "$REPO_DIR"
mkdir -p "$CONF_DIR"/conf

Codename="sid"
Suite="$Codename"

# 生成核心配置文件
cat > "$CONF_DIR"/conf/distributions <<EOF
Origin: apt-repo
Label: apt-repo
Description: Self APT Repository
Codename: $Codename
Suite: $Suite
Architectures: amd64
Components: main
SignWith: yes
EOF

# 导入软件包
for deb in downloaded_packages/*.deb; do
  # 导入到仓库
  reprepro -V -b "$CONF_DIR" -S misc includedeb "$Codename" "$deb"
done

# 生成元数据
reprepro -b "$CONF_DIR" export "$Codename"

# 合并文件到发布目录
rsync -a "$CONF_DIR"/ "$REPO_DIR/"

关于 distribution 中 codename/component/suite 这些术语,debian 官方是有解释

一般 codenam 与 suite 一致,都是各个版本的代号,比如 bionicxenialtrixie

另外别忘了给脚本加上可执行权限

6. Github Pages

接下来在仓库的设置页面,开启 GitHub Pages 功能,选择 Actions 作为源

开启 GitHub Pages 功能

最后别忘了你还要上传一个 packages.list 文件

最后结构应该如下所示

最后结构

然后只用运行 Action 就会自动完成所有事

验收成果

查看索引网页

本身的 APT 仓库是只能被 apt line 识别,没有索引。但是我在 action 里面加了搭建索引的步骤

只需要在浏览器访问你的 pages 地址即可,因为我自定义了域名所以是 https://repos.qladgk.com/debian/

你应该会看到如下界面

索引目录的 APT 仓库

其实索引并不重要,只是方便网页查看而已

导入这个 apt 仓库

首先要接受别人的仓库你需要下载别人仓库提供的公钥,如果你还不知道公钥是什么,就往前翻

我的公钥的直链下载链接在 https://apt-repo.qladgk.com/public-key.asc

所以我可以直接用命令行下载

sudo apt-get update
sudo apt-get install ca-certificates curl #必须安装的工具
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://apt-repo.qladgk.com/public-key.asc -o /etc/apt/keyrings/qladgk.asc
sudo chmod a+r /etc/apt/keyrings/qladgk.asc

这里将下载的公钥存放在 /etc/apt/keyrings 也是 Debian 官方推荐的,现在很少用 apt-key add 这个命令,也不推荐放在 /etc/apt/trusted.gpg.d 或者 /usr/share/keyrings/

然后创建软件源管理文件,推荐使用 DEB822 格式 /etc/apt/sources.list.d/xxxxx.sources 来管理软件源

创建 /etc/apt/sources.list.d/qladgk.sources 文件,内容如下:

Types: deb
URIs: https://repos.qladgk.com/debian
Suites: sid
Components: main
Signed-By: /etc/apt/keyrings/qladgk.asc

其中的 Suites、Components 按照你的仓库来填写

测试安装软件

接下来执行 apt update 你就能看见 apt 已经获取到了这个仓库的数据

完整截图如下:

导入仓库

然后尝试安装你仓库里的软件包

apt安装软件

验证仓库签名

由于我在脚本中选择的是对整个仓库进行签名,所以需要下载仓库的密钥进行核对

在如图的位置中下载仓库签名

仓库签名

然后通过 gpg 验证

gpg --verify Release.gpg Release

完整截图如下:

验证仓库签名

结尾

其实只要是个标准的 apt 仓库都能通过这种方法进行管理,比如说 Docker、Chrome、Vscode

apt软件源

如果你想把旧版本的 sources.list 换成 xxxx.sources 可以通过如下命令

apt modernize-sources

不用担心你会丢失原有的 .list 他只是被重命名成了 .list.old

最后,如何用包管理器快速方便的获取到你想要的包呢?把 Debian 换成 Arch 就行 :)

0
0
0
0