如何设置APT软件源库?

我想在一台服务器上建立一个APT存储库,以提供几个软件包。
有没有一种方法可以在服务器上不安装任何软件的情况下设置它?
这些文件需要如何组织?

编辑:我一定做错了什么...有人可以帮助我吗?我在http://quickmediasolutions.com/apt/dists上有存储库。

我不确定出了什么问题,但是某些配置肯定有问题。我目前只有一个适用于所有架构的软件包。

这是我在/etc/apt/sources.list中添加的内容:

deb http://quickmediasolutions.com/apt stable main

你能编辑并添加你下载的应用程序是什么类型的许可证吗?这是私人使用还是打算分发它们等等? - Jorge Castro
@Jorge:你是什么意思?什么应用程序? - Nathan Osman
1我试图确定这个软件包是否是开源的,你可以直接使用Launchpad。 - Jorge Castro
@Jorge: 不,这并不是开源软件。事实上,这几乎是我写的唯一一个不属于开源软件的应用程序。 - Nathan Osman
5个回答

在一个网络服务器上设置一个简单但已签名的仓库。因为大多数其他教程都有点过时或繁琐,所以我将在这里尝试复制该过程。初始配置需要一些努力,但简单的构建脚本使其易于管理。您只需放入新的*.deb文件,然后更新,或者让cron作业处理。
生成一些签名密钥
首先,您需要为软件包和仓库创建一个gpg签名密钥。将其设置为(4) RSA签名密钥,无密码,并在要求时给它一个唯一的$KEYNAME。(后续示例假设keyname为"dpkg1")。
 gpg --gen-key
 gpg -a --export-secret-key dpkg1 > secret.gpg
 gpg -a --export dpkg1            > public.gpg

我说不需要密码,因为你的网络服务器没有内置的猴子来重复输入密码。签名的软件包和存储库只是为了满足更新管理器对此的投诉。只需将两个密钥上传到您的网络服务器上的新的/apt/存储库目录中,但在初始化之后删除secret.gpg密钥。

更新CGI脚本

这是用于它的简单更新shell/CGI脚本:

#!/bin/sh
echo Status: 200 Okay
echo Content-Type: text/plain
echo
echo Rebuilding APT repository:

{
  #-- settings
  export GNUPGHOME=/var/www/usr12345/files
  export KEYNAME=dpkg1
  #-- one-time setup
  if [ ! -e "$GNUPGHOME/secring.gpg" ] ; then
     gpg --import -v -v ./secret.gpg
     gpg --import -v -v ./public.gpg
     gpg --list-keys
  fi

  #-- symlink .deb files from adjacent sub-directories
  find .. -name '*.deb' -exec ln -s '{}' . \;

  #-- build Packages file
  apt-ftparchive packages . > Packages
  bzip2 -kf Packages

  #-- signed Release file
  apt-ftparchive release . > Release
  gpg --yes -abs -u $KEYNAME -o Release.gpg Release

} 2>&1

这三行gpg只需要执行一次,以初始化在某个目录$GNUPGHOME(在文档根目录上方)中的GPG设置。成功后仅删除secret.gpg
这个小型shell脚本的一个独特功能是它接受您放入的任何*.deb文件,并递归地搜索其他文件(从上一级开始),并创建符号链接。 (最终需要.htaccess Options FollowSymLinks。)
您可以手动将此脚本作为CGI执行,也可以通过cron作业执行。但请隐藏它,或者更好地将其移出文档根目录。
因为它是一个“简单”的apt存储库,所以需要以下apt-sources.list条目:
deb http://example.org/deb/  ./    # Simple signed repo

这适用于单一架构的软件库,如果你不期望有数百个软件包。

软件包签名

一旦设置好了你的 gpg 密钥,对个别软件包进行签名也是非常简单的。

dpkg-sig -k dpkg1 -s builder *.deb

(这应该在构建软件包的工作站上完成,而不是在仓库 Web 服务器上。)

未签名仓库

如果您不需要签名的软件包,则可以将更新脚本简化为:

  dpkg-scanpackages . > Packages
  bzip2 -kf Packages

可以仍然被普通用户使用,但需要为apt.sources设置自定义标志。
deb [trusted=yes] http://apt.example.org/deb/ ./

但请不要习惯性地对所有事情使用“trusted=yes”标志,或者如果您对软件包的来源并不确定。

为了易用性

对于最终用户来说,只需将一个HEADER.html文件放入存储库目录中。Apache的mod_auto_index会在前面添加该注释:

<h1>http://example.org/apt/</h1>
<dl>
<dt>Add this repository to /etc/apt/sources.list as:
 <dd><kbd>deb http://example.org/apt/ ./  # example repo</kbd>
<dt>Import verification key with:
 <dd><kbd>wget -q http://http://example.org/apt/public.gpg -O- | sudo apt-key add -</kbd>
</dl>

替代方案

现在有一些工具可以自动化管理代码库。甚至还有在线托管代码库和软件包构建服务(gemfurypackagecloudbintray等)。

  • 一个相当方便的替代方案是prm。它是一个Ruby脚本,用于构建复杂的APT和YUM仓库。(但让我们希望RPM能够尽快消失吧..)- 最好通过gem install prm进行安装。

  • 我还编写了一个类似的小脚本来自动化这个过程:http://apt.include-once.org/apt-phparchive - 请注意,它不是非常稳定,并且是用PHP编写的(这次纯属巧合),最初是为DEB、RPM-over-APT和Phar捆绑包设计的。

由于这与原问题密切相关,因此也有一些工具可以更轻松地构建Debian软件包。有点过时的是:EPM。更现代的是:FPM。还有我个人的分支:XPM(用于打包脚本语言应用程序的更懒惰方法)。

1当我想使用该软件源时,如何添加GPG密钥? - Bruce Sun
1通常类似于wget …/public.gpg -O- | apt-key add - - mario
如果我确实想要支持多种架构,我需要做哪些改变? - starbeamrainbowlabs
1@starbeamrainbowlabs 不太确定,但我认为 dpkg-scanpackages -m 可能足够了。它会在同一个 Release 文件中列出所有架构。但只要每个 .deb 文件都有唯一的名称/或存储在不同的子目录(amd64/,all/),应该就可以解决问题。否则,可以选择更复杂的仓库工具之一。 - mario

使用dpkg-scanpackages设置一个简单的存储库非常容易。 这个页面 解释了如何设置一个简单的存储库,这个页面 解释了如何使用它(向下滚动到示例4)。


遇到一点问题,无法让它正常工作。请查看我对问题的更新。 - Nathan Osman
1看起来你正在尝试建立一个"自动"仓库。对于一个或只是几个软件包,使用简单的仓库会更好。尝试将你的Packages.gz和deb文件都移到http://quickmediasolutions.com/apt/binary这个地址上。然后你的源将是`deb http://quickmediasolutions.com/apt binary/`。 - crenshaw-dev
2当固定版本时,琐碎的软件仓库会带来问题,但是没错,它们是为了安装少量软件包而设置仓库的最快、最简单的方式。为了仅仅安装2-3个软件包而设置一个共享仓库似乎有些愚蠢。 - Tim Post
乔治,你最终能够让这个工作起来了吗? - crenshaw-dev
@mac: 嗯……我还没来得及试呢 :) 我最后只是把所有东西都上传到了一个PPA。 - Nathan Osman

是的。你可以这样做。你只需要以正确的方式组织文件并创建索引文件。如果你将目录结构放在Web服务器的文档根目录下,那么包就可以通过Web服务器访问。
这里有一个详细描述文件应该如何组织以及如何创建索引文件的链接。
如果你愿意安装一个叫做reprepro的工具,你也可以使用它。这将使管理工作更加方便一些。

@txwikinger:我无法安装软件包的原因是因为服务器正在运行CentOS :) - Nathan Osman
好的,你不需要这样做。你可以在另一台电脑上创建所有内容,然后只需将整个目录树通过rsync同步到CentOS服务器上即可。 - txwikinger
是的,我绝对赞同使用 reprepro。它会让你的生活变得更加轻松。在另一台电脑上创建存储库甚至可能是一个特色,因为它可以更好地保护你的签名密钥。 - andol
@andol & @txwikinger:我正在努力解决问题,但遇到了一些困难。请查看我更新的问题。 - Nathan Osman
对于您的dists文件,您仍然需要./binary-<特定架构>。 - andol
@andol:抱歉,我的“dists”文件?我在存储库的根目录下有一个名为“dists”的文件夹。 - Nathan Osman
好的,这可能是我表达不清楚了。除此之外,应该是复数形式。我习惯将实际的软件包放在./pool目录下,而将./dists目录保留给元数据/软件包信息。也就是说,你需要有单独的./dists/stable/main/binary-{amd64,i386}目录,其中包含它们自己的Packages*文件。然而,它们可以引用相同的实际.deb文件。因此(部分地)解释了./pool目录的流行约定。 - andol
Apache有权限访问apt/dists文件夹以及其中的文件吗? - txwikinger
我因为你提到了reprepro而对你表示赞赏。现在应该将微不足道的存储库视为忌讳。使用reprepro并将新软件包上传到存储库要容易得多。 - umeboshi


对于在按照马里奥的答案后遇到这个错误的任何人:

Unable to find expected entry 'Packages' in Release file (Wrong sources.list entry or malformed file)

做以下操作:
dpkg-scanpackages debs /dev/null > Packages
gzip -k Packages
apt-ftparchive release . > Release
gpg --default-key $KEYID -abs -o Release.gpg Release

我把我的*.deb文件放在debs文件夹里。