APT私有源的搭建

参考及其它的知识

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 本地文件源记得port后一定要加 / 表示文件夹。源后必须接个 文件夹目录(port/),仅个地址不行的
# 不要 InRelease 和 Release.gpg 的话配 [trusted=yes] 可正常使用,若不配的话APT会认为该源不可靠而忽略
deb [trusted=yes] file:///home/leux/pve port/

# 位于 $ARVHIVE_ROOT/dists/$DIST/ 下的 Release/InReleas 文件包含索引文件的校验和路径等信息
# 文件 $ARVHIVE_ROOT/dists/$DIST/$COMP/binary-$ARCH/Packages 含DEB包的索引和校验及路径等信息
# InRelease 文件是内部自认证的。而 Release 文件需要结合 Release.gpg 文件来认证
# Packages 文件列出的DEB文件路径是相对于 $ARCHIVE_ROOT 路径的

# deb [URL] [distribution] [component1] [component2] [...]
# apt 程序解析 source.list 源中的 URL 和 distribution 得到 Release 文件的位置
# 获取 Release 文件并解析 Packages 文件,根据 Release 文件里的内容找到所要装的文件包,并验证所有文件的合法性。

deb [URL] # 如果后面什么都不加,则APT执行会报错。但 URL/ 后面接不接 / 都没关系
deb [URL] ./ # 就会获取 URL/./[In/Release] 来确定 Packages
deb [URL] dev/ # 就会获取 URL/dev/[In/Release] 来确定 Packages
deb [URL] port/ # 就会获取 URL/port/[In/Release] 来确定 Packages
deb [URL] [distribution] [component] # 就会获取 URL/dists/[distribution]/[In/Release] 来确定 Packages

# 以163源为例:deb http://mirrors.163.com/ubuntu jammy main
# 从 http://mirrors.163.com/ubuntu/dists/jammy/Release 中获取到索引的相对路径 main/binary-amd64/Packages
# 再从绝对路径 http://mirrors.163.com/ubuntu/dists/jammy/main/binary-amd64/Packages 中解析DEB包的相关信息

本地搭建某PVE源

  1. 先将这个私有源中指定目录中的包全部下载
1
2
3
4
5
6
7
8
9
10
# 将 https://mirrors.apqa.cn/proxmox/debian/pve/dists/bookworm/port/binary-arm64/Packages 中的包全部下载
mkdir -p /home/leux/pve/port && cd /home/leux/pve/port
URL=https://mirrors.apqa.cn/proxmox/debian/pve/
wget $URL/dists/bookworm/port/binary-arm64/Packages
cat Packages | grep Filename: | sed "s|Filename: |$URL|g" | sed "/-dbg_/d" | sed "/-dbgsym_/d" > url.txt
wget -c -i url.txt

# 该 Packages 全下载有11G大小,625个包。去除如下后缀包后仅有1.41G,461个包
# -dbg_ 供开发人员调试用,-4.07G,-25 sed -i '/-dbg_/d' url.txt
# -dbgsym_ 文件可删除来减负,-5.21G,-139 sed -i '/-dbgsym_/d' url.txt
  1. 生成 PackagesRelease 文件
1
2
3
4
5
6
# 生成完成添加完本地文件源后即可使用了,但会有警告产生
sudo apt install apt-utils
cd /home/leux/pve/ # 必须在源的根目录下执行,否则 Packages 中的包路径会出错导致无法获取
apt-ftparchive packages port/ > port/Packages # 将所有版本的安装包信息写入到 Packages 中
apt-ftparchive release port/ > port/Release # 生成 Release 索引文件
sed -i '1i Codename: port' port/Release # W: Conflicting distribution: ... InRelease (expected port/ but got )
  1. 加密相关文件 InRelease
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 如果不加密,不用 InRelease和Release.gpg 再配 [trusted=yes] 和 apt update --allow-unauthenticated 可将就使用
# E: The repository 'file:/home/leux/pve port/ Release' is not signed.
echo "deb [trusted=yes] file:///home/leux/pve port/" > /etc/apt/sources.list.d/pveport.list

# 先为自己创建密钥,创建时的密码和用户名 leux0 导出时要用到,没有密钥的话后续加密会报如下而失败。如果你有则跳过
# gpg: no default secret key: No secret key # gpg: signing failed: No secret key
gpg --list-keys # 查看密钥
gpg --gen-key # 创建密钥
gpg --armor --output /home/leux/pve/public.key --export leux0 # 导出公钥

# 在 Debian 12 系统下,InRelease 和 Release.gpg 只需要生成其中一个即可
# gpg -ab -o port/Release.gpg port/Release # 生成 Release.gpg 文件
gpg --clearsign -o port/InRelease port/Release # 生成 InRelease 文件

# 因为apt只接受GPG格式,而gpg导出的公钥又是PGP文件,所以需要如下来转换并添加到系统中
# cat /home/leux/pve/public.key | sudo gpg --dearmor -o /etc/apt/trusted.gpg.d/pve.gpg
curl -fsSL http://192.168.1.1/public.key | sudo gpg --dearmor -o /etc/apt/trusted.gpg.d/pve.gpg
  1. 搭建测试服务器
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# 使用BUSYBOX中的HTTPD来搭建简单的服务器测试
# https://packages.debian.org/bookworm/arm64/busybox-static/download

# 将源由本地文件源修改为本地服务器源
echo "deb http://192.168.1.1 port/" > /etc/apt/sources.list.d/pveport.list

# 将 /home/leux/pve/ 作为根目录,80 作为端口启动WEB服务器
busybox httpd -p 80 -h /home/leux/pve/


# 关于busybox httpd的其他使用方法,详细配置文件帮助可见源码:networking/httpd.c
# busybox httpd -p 80 -u 80 -h /www -c /etc/httpd.conf -r "Web Server Authentication"
-i Inetd mode
-f Run in foreground
-v[v] Verbose
-p [IP:]PORT Bind to IP:PORT (default *:80)
-u USER[:GRP] Set uid/gid after binding to port
-r REALM Authentication Realm for Basic Authentication
-h HOME Home directory (default .)
-c FILE Configuration file (default {/etc,HOME}/httpd.conf)
-m STRING MD5 crypt STRING
-e STRING HTML encode STRING
-d STRING URL decode STRING

# /etc/httpd.conf https://blog.csdn.net/shjhuang/article/details/60339874
*.cgi:/bin/sh
*.sh:/usr/bin/sh
*.php:/bin/php
  1. 关于 Packages.gz 文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 默认APT只获取 Packages,可以通过配置APT来改为获取 Packages.gz 或 Packages.xz
root@h88k:~# grep -r GzipIndexes /etc/apt # 先查看是否有配置 GzipIndexes ,以如下我的为例
/etc/apt/apt.conf.d/02-armbian-compress-indexes:Acquire::GzipIndexes "false";

root@h88k:~# cat /etc/apt/apt.conf.d/02-armbian-compress-indexes
Acquire::GzipIndexes "false"; # 将 false 改为 true 来启用压缩
Acquire::CompressionTypes::Order:: "gz"; # 支持的压缩类型 .gz .xz .bz2 .lzma
APT::Compressor::gzip::Cost "10"; # 可解决某些设备 apt search 慢的问题

# 如果需要生成 Packages.gz,必须在生成 Release 前执行,否则将不会在 Release 中记录而找不到它
# apt-ftparchive packages port/ /dev/null | gzip -9c > port/Packages.gz # 将Packages压缩成gz文件(非必须)

# sudo apt install dpkg-dev gzip
# dpkg-scanpackages -m port/ /dev/null | gzip -9c > port/Packages.gz # 将Packages压缩成gz文件(非必须)
# dpkg-scanpackages -m port/ > port/Packages # -m 选项的作用是将所有版本的安装包信息都读取到 Packages 中,不加则只会采集最新版本安装包的信息

root@h88k:~# rm -rf /var/lib/apt/lists/ # 最后删除 apt list 缓存再更新

root@h88k:~# ls /var/lib/apt/lists/ # 可以看到 apt 使用了 Packages.gz
192.168.1.1_port_InRelease
192.168.1.1_port_Packages.gz

# (猜测)如果配置了压缩支持的话源中可以没有 Packages 文件,但必须有 Packages.gz 等。反之没配置压缩则必须有 Packages 否则会报找不到
# (猜测)没开压缩的话,如果没有 Packages 则会通过 Packages.gz 生成。开启压缩的话,如果没有 Packages.gz 则会通过 Packages 生成
  1. 关于APT密钥的警告(以下是22.04以下老版本的做法,新版已弃用)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 将本地公钥添加到 apt 可信密钥库中,即在 /etc/apt/trusted.gpg 这个文件中
sudo apt-key add /home/leux/pve/public.key

# 老版系统把软件包的秘钥保存到 /etc/apt/trusted.gpg 这个 的文件里。新版系统不能把秘钥放在 /etc/apt/trusted.gpg 里,而应放在 /etc/apt/trusted.gpg.d 目录下。否则报如下警告
W: http://192.168.1.1/port/InRelease: Key is stored in legacy trusted.gpg keyring (/etc/apt/trusted.gpg), see the DEPRECATION section in apt-key(8) for details.


# 既可手动指定源中key的路径来消除,也可根据后面两步导出到新版的位置中来消除
echo "deb [signed-by=/etc/apt/trusted.gpg] http://192.168.1.1 port/" > /etc/apt/sources.list.d/pveport.list


# 先查询本地设备上所有的秘钥,并找到刚导入的
leux@h88k:~/pve$ apt-key list
Warning: apt-key is deprecated. Manage keyring files in trusted.gpg.d instead (see apt-key(8)).
/etc/apt/trusted.gpg # 密钥信息存储位置
--------------------
pub rsa3072 2024-07-29 [SC] [expires: 2026-07-29]
7C8E FCC6 4CD4 DEE5 B29F 3069 AF51 EA11 3D27 F56F # 秘钥ID
uid [ unknown] leux0 <xxx@xxx.com> # 作者及邮箱
sub rsa3072 2024-07-29 [E] [expires: 2026-07-29] # 有效期

# 将其导出到新版的位置中。注意:导出时只需要秘钥ID后八位的值即可,而且它们之间没有空格
sudo apt-key export 3D27F56F | sudo gpg --dearmour -o /etc/apt/trusted.gpg.d/pve.gpg
  1. 关于警告:W: Conflicting distribution: http://192.168.1.1 port/ InRelease (expected port/ but got )
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
# 尝试规范化私有源的目录,解决该警告关键在于在 Release 中添加正确的 Codename: bookworm
mkdir -p /home/leux/pve/dists/bookworm/port/binary-arm64
cd /home/leux/pve/dists/bookworm/port/binary-arm64
URL=https://mirrors.apqa.cn/proxmox/debian/pve/
wget $URL/dists/bookworm/port/binary-arm64/Packages
cat Packages | grep Filename: | sed "s|Filename: |$URL|g" | sed "/-dbg_/d" | sed "/-dbgsym_/d" > url.txt
wget -c -i url.txt

# 必须在源的根目录下执行,否则Packages中的包路径会出错导致无法获取
cd /home/leux/pve/
dpkg-scanpackages -m dists/bookworm/port/binary-arm64/ > dists/bookworm/port/binary-arm64/Packages
apt-ftparchive release dists/bookworm/ > dists/bookworm/Release
sed -i '1i Codename: bookworm' dists/bookworm/Release
gpg --clearsign -o dists/bookworm/InRelease dists/bookworm/Release
echo "deb http://192.168.1.1 bookworm port" > /etc/apt/sources.list.d/pveport.list

# 源为 "deb http://192.168.1.1 bookworm port" 会寻找如下(bookworm版本中的port仓库)
http://192.168.1.1/dists/bookworm/port/binary-arm64/Packages

# 在 dists/bookworm/Release 的前面添加 Codename: bookworm 行可解决这个警告。记得加完后在加密
Codename: bookworm
Date: Thu, 13 Jun 2024 03:38:20 +0000
MD5Sum:

# 本源中的目录结构
pve
└── dists
└── bookworm
├── InRelease
├── Release
└── port
   └── binary-arm64
   ├── Packages
   ├── proxmox-ve_8.2.0_all.deb
   ├── pve-manager_8.2.4_arm64.deb
   ├── pve-qemu-kvm_8.1.5-4_arm64.deb
   ├── qemu-server_8.2.1_arm64.deb