Ubuntu仓库构建
5 min read
Page Views
构建Ubuntu/ Debian软件仓库
安装依赖项
sudo apt install gcc dpkg-dev gpg nginx
构建创库
创建存放软件包的仓库目录
mkdir -p ~/example/apt_repo/pool/main
将对应软件包存放到该目录下:
大的仓库管理通常在下面创建子文件夹存放对应分类或项目的软件包
cd ~/example/apt_repo/pool/main && mkdir [target_sub_direcotry]
将软件包存放到对应的子目录:
cp [all_deb_files or holding directories] [target_sub_direcotry]
依据架构支持创建存放包元数据的目录
cd ~/example/apt-repo &&
返回到apt-repo层目录,依据架构创建存放元包数据的目录
cd ~/example/apt-repo && mkdir -p ./dists/stable/main/binary-arm64
使用dpkg-scanpackages 生成Packages记录文件
dpkg-scanpackages --arch arm64 pool/ > dists/stable/main/binary-arm64/Packages
对Packages文件进行压缩
cat dists/stable/main/binary-arm64/Packages|gzip -9 >dists/stable/main/binary-a
rm64/Packages.gz
Note:支持的压缩格式:bzip2,lzma,
创建Release文件
脚本程序,放到example目录下
generate_release.sh
#!/bin/sh
set -e
do_hash() {
HASH_NAME=$1
HASH_CMD=$2
echo "${HASH_NAME}:"
for f in $(find -type f); do
f=$(echo $f | cut -c3-) # remove ./ prefix
if [ "$f" = "Release" ]; then
continue
fi
echo " $(${HASH_CMD} ${f} | cut -d" " -f1) $(wc -c $f)"
done
}
cat << EOF
Origin: Example Repository
Label: Example
Suite: stable
Codename: stable
Version: 1.0
Architectures: amd64 arm64 arm7
Components: main
Description: An example software repository
Date: $(date -Ru)
EOF
do_hash "MD5Sum" "md5sum"
do_hash "SHA1" "sha1sum"
do_hash "SHA256" "sha256sum"
运行脚本
cd ~/example/apt_repo/dists/stable
~/example/generate_release.sh > Release
仓库Release file签名
echo "%echo Generating an example PGP key
Key-Type: RSA
Key-Length: 4096
Name-Real: example
Name-Email: yongqi.chen@skysys.cn
Expire-Date: 0
%no-ask-passphrase
%no-protection
%commit" > /tmp/example-pgp-key.batch
export GNUPGHOME="$(mktemp -d ~/example/pgpkeys-XXXXXX)"
gpg --no-tty --batch --gen-key /tmp/example-pgp-key.batch
查看生成的密匙
gpg --list-keys
导出公钥
gpg --armor --export example > ~/example/pgp-key.public
可通过如下指令查看确保导出单个公钥
cat ~/example/pgp-key.public | gpg --list-packets
导出私钥
gpg --armor --export-secret-keys example > ~/example/pgp-key.private
对release 文件进行签名,在开始用生成的密钥进行签名前,需要确保可以导出备份。定义新的GPG密钥位置
export GNUPGHOME="$(mktemp -d ~/example/pgpkeys-XXXXXX)"
查看密钥
gpg --list-keys
显示如下:
gpg: keybox ‘/home/ubuntu/example/pgpkeys-bJjHJv/pubring.kbx’ created gpg: /home/ubuntu/example/pgpkeys-bJjHJv/trustdb.gpg: trustdb created
导入备份的私钥
cat ~/example/pgp-key.private | gpg --import
现在查看密钥显示应如下:
/home/ubuntu/example/pgpkeys-bJjHJv/pubring.kbx
pub rsa4096 2024-04-08 [SCEA]
51E07666AB32B2F6E1996DAABC73497279AA9C24
uid [ unknown] example
对release file 进行签名
cat ~/example/apt_repo/dists/stable/Release | gpg --default-key example -abs > ~/example/apt_repo/dists/stable/Release.gpg
创建InRelease 文件加速apt 获取速度
cat ~/example/apt_repo/dists/stable/Release | gpg --default-key example -abs --clearsign > ~/example/apt_repo/dists/stable/InRelease
生成apt仓库源
echo "deb [arch=arm64] http://[ip]:[port]/apt_repo stable main" | sudo tee /etc/apt/sources.list.d/example.list
配置NGINX 代理
配置文件在 /etc/nginx/sites-available/default
根据提示配置http服务
软件包更新自动维护程序
from hashlib import sha256
import os
import subprocess
from rich.console import Console
from datetime import datetime
from time import sleep
DIRECTORY="/home/ubuntu/example/apt_repo/pool"
OUTFILE="hashes.txt"
ROOT_DIRECTORY= "/home/ubuntu/example/apt_repo"
LOG_DIRECTORY="/tmp/log/maintaince_tool/"
log_file ="log-"+datetime.strftime(datetime.now(),"%YY-%m-%d-%H-%M-%S")+".txt"
log_file =os.path.join(LOG_DIRECTORY,log_file)
logger=Console(file=log_file)
private_key= '''
-----BEGIN PGP PRIVATE KEY BLOCK-----
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
-----END PGP PRIVATE KEY BLOCK-----
''' #replace your private key.
def calculate_hash(file_path, hash_algorithm="sha256"):
"""Calculate hash for a file."""
hasher = sha256()
with open(file_path, "rb") as f:
while True:
chunk = f.read(4096)
if not chunk:
break
hasher.update(chunk)
return hasher.hexdigest()
def generate_hashes(directory, output_file, hash_algorithm="sha256"):
"""Generate hashes for all files in a directory and save to output file."""
hashes=[]
with open(output_file, "w") as f:
for root, dirs, files in os.walk(directory):
for file in files:
file_path = os.path.join(root, file)
file_hash = calculate_hash(file_path, hash_algorithm)
hashes.append(file_hash)
return hashes
def save_hash_to_file(hash_file,hashes):
with open(hash_file,"w")as fp:
fp.writelines(hashes)
def load_hashes(hash_file):
with open(hash_file,"r")as fp:
hashes=fp.readlines()
return hashes
if __name__=="__main__":
# create log directory
if not os.path.exists(LOG_DIRECTORY):
os.makedirs(LOG_DIRECTORY)
# load hashes
hash_file=os.path.join(DIRECTORY,OUTFILE)
hashes=[]
#
if not os.path.exists(hash_file):
hashes=generate_hashes(DIRECTORY,hash_file)
save_hash_to_file(hash_file,hashes)
else:
hashes=load_hashes(hash_file)
# maintaining progress.
while True:
new_hashes=generate_hashes(DIRECTORY,hash_file)
if hashes != new_hashes: # repository has been updated
# 1.Regenerate Packages File
shell_scripts=f"/usr/bin/bash -c ' cd {ROOT_DIRECTORY} && dpkg-scanpackages --arch arm64 pool/ > ./dists/stable/main/binary-arm64/Packages && cat dists/stable/main/binary-arm64/Packages|gzip -9 > dists/stable/main/binary-arm64/Packages.gz '"
ret=subprocess.call(shell_scripts,shell=True)
if ret!=0:
# log errors
logger.log("[#ff0000]Regenerate Packages file failed.[ff0000]")
pass
# 2. Regenerate Release file
shell_scripts=f"/usr/bin/bash -c 'cd {os.path.join(ROOT_DIRECTORY,'''dists/stable''')} && ~/example/generate_release.sh > Release'"
ret=subprocess.call(shell_scripts,shell=True)
if ret!=0:
logger.log("[#ff0000]Regenerate Release file failed.[ff0000]")
pass
# 3. sign the release file with private-key
shell_scripts=f"/usr/bin/bash -c 'gpg --import << f{private_key} && cat {os.path.join(ROOT_DIRECTORY,'''dists/stable/Release''')} | gpg --default --key example -abs > {os.path.join(ROOT_DIRECTORY,'''dists/stable/Release.gpg''')}' "
ret=subprocess.call(shell_scripts,shell=True)
if ret!=0:
logger.log("[#ff0000]Sign Release file failed.[ff0000]")
# 4. create InRelease file
shell_scripts=f"/usr/bin/bash -c 'gpg --import << f{private_key} && cat {os.path.join(ROOT_DIRECTORY,'''dists/stable/Release''')} | gpg --default --key example -abs --clearsign > {os.path.join(ROOT_DIRECTORY,'''dists/stable/InRelease''')}' "
ret=subprocess.call(shell_scripts,shell=True)
if ret!=0:
logger.log("[#ff0000]Create InRelease file failed.[ff0000]")
#save new hash to file
hashes=new_hashes
save_hash_to_file(hash_file,hashes)
sleep(10)
Last updated on 2025-07-11