如何创建本地APT软件源?

我想在我的局域网上建立自己的本地软件仓库,这样局域网中的设备就可以从中进行更新和升级。我希望能够下载软件包并将其存储在本地服务器上,以便我可以通过它来进行更新、升级、安装等操作,而无需使用互联网。

2可能重复:http://askubuntu.com/questions/974/how-can-i-install-software-or-packages-without-internet-offline - stephenmyall
3我不认为这是一个重复的问题。maythux想要实现的是创建自己的存储库服务器,以便与aptitude一起使用。而Keryx所做的是替代aptitude作为软件包管理器,并创建外部软件包源。 - con-f-use
1可能是重复的问题?-http://askubuntu.com/questions/9809/is-it-possible-to-mirror-the-apt-repositories或http://askubuntu.com/questions/3503/best-way-to-cache-apt-downloads-on-a-lan - jrg
10个回答

Ubuntu帮助维基上来看:

There are 4 steps to setting up a simple repository for yourself

1.Install dpkg-dev
2.Put the packages in a directory
3.Create a script that will scan the packages and create a file apt-get update can read
4. Add a line to your sources.list pointing at your repository

Install dpkg-dev

Type in a terminal

sudo apt-get install dpkg-dev

The Directory

Create a directory where you will keep your packages. For this example, we'll use /usr/local/mydebs.

sudo mkdir -p /usr/local/mydebs

Now move your packages into the directory you've just created.

Previously downloaded Packages are generally stored on your system in the /var/cache/apt/archives directory. If you have installed apt-cacher you will have additional packages stored in its /packages directory.

The Script update-mydebs

It's a simple three liner:

#! /bin/bash
 cd /usr/local/mydebs
 dpkg-scanpackages . /dev/null | gzip -9c > Packages.gz

Cut and paste the above into gedit, and save it as update-mydebs in ~/bin. (the tilde '~' means your home directory. If ~/bin does not exist, create it: Ubuntu will put that directory in your PATH. It's a good place to put personal scripts). Next, make the script executable:

chmod u+x ~/bin/update-mydebs

How the script works:

dpkg-scanpackages looks at all the packages in mydebs, and the output is compressed and written to a file (Packages.gz) that apt-get update can read (see below for a reference that explains this in excruciating detail). /dev/null is an empty file; it is a substitute for an override file which holds some additional information about the packages, which in this case is not really needed. See deb-override(5) if you want to know about it.

Sources.list

add the line

deb file:/usr/local/mydebs ./

to your /etc/apt/sources.list, and you're done.

CD Option

You can burn the directory containing the debs to a CD and use that as a repository as well (good for sharing between computers). To use the CD as a repository, simply run

sudo apt-cdrom add

Using the Repository

Whenever you put a new deb in the mydebs directory, run

sudo update-mydebs
sudo apt-get update

Now your local packages can be manipulated with Synaptic, aptitude and the apt commands: apt-get, apt-cache, etc. When you attempt to apt-get install, any dependencies will be resolved for you, as long as they can be met.

Badly made packages will probably fail, but you won't have endured dpkg hell.


4能否为我解释一下 dpkg-scanpackages . /dev/null | gzip -9c > Packages.gz 这行代码的语法?你知道 /dev/null 在这里有什么作用吗?我虽然查了手册,但还是不太明白。 - sayantankhan
@blade19899 我需要稍微澄清一下,请。我想要一个只包含几个特定软件包的存储库,而不是我曾经接触过的每个软件包。我理解这种技术可以实现这个目标吗?这里的目标是为一个软件安装组在一个与外界隔离的局域网上使用一个存储库,远离诱惑去apt-get那些不需要的软件包。 - Wes Miller
@WesMiller 我觉得你需要,我刚修改了他的帖子! - blade19899
@blade19899 对不起,我不明白你的回答。 - Wes Miller
@WesMiller 你需要BigSack。我刚刚为他的帖子编辑了一些语法问题(我认为已经有一段时间了)。这不是我的答案,而是BigSack的。 - blade19899
@BigSack 你什么时候运行 update-mydebs?难道不应该在每次系统更新之前运行 apt-get update 吗? - user877329
通过命令行添加软件源:sudo apt-add-repository "deb file:///usr/local/mydebs ./" - benjaoming
一直想知道如何创建仓库,但以前从未有过这个需求。我会收藏这个链接,以后有机会试一试。从广义上讲,我了解仓库的工作原理,但只是在处理HTTP请求方面。 - proprocastinator
14请注意,如果您在/etc/apt/sources.list中使用了deb file:/usr/local/mydebs ./,您可能会遇到以下问题:E: 仓库 'file:/home/path Release' 没有 Release 文件。N: 无法安全地从此类仓库进行更新,默认情况下已禁用。为了解决这个问题,请使用deb [trusted=yes] file:/usr/local/mydebs ./ - patryk.beza
新的行应该放在sources.list的顶部还是底部?或者无所谓吗? - falsePockets
你甚至可以自动更新mydebs:将下面的代码复制到终端中并执行即可: echo 'APT::Update::Pre-Invoke {"cd /usr/local/mydebs; dpkg-scanpackages . /dev/null > /usr/local/mydebs/Packages"};' > /etc/apt/apt.conf.d/00mydebs - blaimi
我建议使用apt-ftparchive而不是dpkg-scanpackages,正如我在我的回答中提到的那样。 - Pandya
同样重要的是:如果您不将本地仓库固定(pin),那么如果互联网仓库中有更高版本的软件包,它将被忽略。 - Alba Mendez

在本地局域网上建立离线仓库的方法:
1. 安装一个本地Apache Web服务器。
# apt-get install apache2

默认情况下,Debian的Apache软件包会在您的系统上设置一个位于/var/www目录下的网站。对于我们的目的来说,这是可以接受的,所以没有必要做更多的事情。您可以通过将您喜欢的浏览器指向http://localhost来轻松测试它。您应该能够看到默认的安装后网页,实际上存储在/var/www/index.html中。 创建Debian软件包仓库目录 为此,选择创建一个名为/var/www/debs的目录。在其中,您应该为每个需要支持的架构创建一个"architecture"目录。如果您只使用一台计算机(或一种类型的计算机),那么您只需要一个目录--通常是32位系统的"i386"或64位系统的"amd64"。如果您使用其他架构,我假设您可能已经了解这一点。 现在,只需将给定架构的".deb"软件包文件复制到相应的目录中。如果您现在将您喜欢的网络浏览器指向http://localhost/debs/amd64(例如),您将看到适用于64位系统的软件包列表。 创建Packages.gz文件 现在,我们需要创建一个供APT使用的目录文件。这可以通过一个名为"dpkg-scanpackages"的实用程序来完成。以下是我在我的局域网上更新AMD64软件包时使用的命令:
# cd /var/www/debs/

# dpkg-scanpackages amd64 | gzip -9c > amd64/Packages.gz

让APT知道这个存储库
现在剩下的事情就是让APT知道你的存储库。你可以通过更新/etc/apt/sources.list文件来实现。你需要添加类似于以下的条目:

deb http://localhost/debs/ amd64/

我使用了我的系统的实际主机名而不是localhost - 这样代码对于我局域网中的所有计算机都是相同的,但如果你只运行一台电脑,localhost也没问题。 现在,更新APT:
# apt-get update

2将那行代码添加到/etc/apt/sources.list文件中会导致在不在局域网内时无法更新,对吗? - Felix
2对于Ubuntu 16.04,你可能需要将这个答案中的/var/www/debs替换为/var/www/html/debs。否则,你将需要额外的步骤来手动编辑你的Apache配置文件在/etc/apache2目录下。 - Erik

创建一个经过身份验证的存储库

我已经查看了这里和其他网站上的答案,大多数都有(在我看来是个很大的)缺点,那就是您正在设置一个未经身份验证的存储库。这意味着您需要使用apt-get命令并加上--allow-unauthenticated选项来安装来自该存储库的软件包。这可能存在安全风险,特别是在脚本中,您安装的软件包可能不全来自您的本地存储库。

请注意,我在这里没有涵盖如何通过局域网进行共享,但这是一个相当通用的配置,可以使用Apache或nginx(请参阅这里的其他答案)。

设置存储库目录

mkdir /home/srv/packages/local-xenial
cd /home/srv/packages/local-xenial

然后在 sources.list 中添加一行类似这样的内容:
deb file:/home/srv/packages/local-xenial/ ./

添加和移除软件包

移除软件包

rm /home/srv/packages/local-xenial/some_package_idont_like

添加套餐
cp /some/dir/apackage.deb /home/srv/packages/local-xenial

现在运行以下脚本,它将生成Packages、Release和InRelease文件,并使用您的gpg私钥对其进行签名:
#!/bin/bash

if [ -z "$1" ]; then
       echo -e "usage: `basename $0` DISTRO
where DISTRO is the Ubuntu version codename (e.g. 14.04 is trusty)\n
The way to use this script is to do the changes to the repo first, i.e. delete or copy in the .deb file to /srv/packages/local-DISTRO, and then run this script\n
This script can be run as an unprivileged user - root is not needed so long as your user can write to the local repository directory"
else
    cd /srv/packages/local-"$1"

    # Generate the Packages file
    dpkg-scanpackages . /dev/null > Packages
    gzip --keep --force -9 Packages

    # Generate the Release file
    cat conf/distributions > Release
    # The Date: field has the same format as the Debian package changelog entries,
    # that is, RFC 2822 with time zone +0000
    echo -e "Date: `LANG=C date -Ru`" >> Release
    # Release must contain MD5 sums of all repository files (in a simple repo just the Packages and Packages.gz files)
    echo -e 'MD5Sum:' >> Release
    printf ' '$(md5sum Packages.gz | cut --delimiter=' ' --fields=1)' %16d Packages.gz' $(wc --bytes Packages.gz | cut --delimiter=' ' --fields=1) >> Release
    printf '\n '$(md5sum Packages | cut --delimiter=' ' --fields=1)' %16d Packages' $(wc --bytes Packages | cut --delimiter=' ' --fields=1) >> Release
    # Release must contain SHA256 sums of all repository files (in a simple repo just the Packages and Packages.gz files)
    echo -e '\nSHA256:' >> Release
    printf ' '$(sha256sum Packages.gz | cut --delimiter=' ' --fields=1)' %16d Packages.gz' $(wc --bytes Packages.gz | cut --delimiter=' ' --fields=1) >> Release
    printf '\n '$(sha256sum Packages | cut --delimiter=' ' --fields=1)' %16d Packages' $(wc --bytes Packages | cut --delimiter=' ' --fields=1) >> Release

    # Clearsign the Release file (that is, sign it without encrypting it)
    gpg --clearsign --digest-algo SHA512 --local-user $USER -o InRelease Release
    # Release.gpg only need for older apt versions
    # gpg -abs --digest-algo SHA512 --local-user $USER -o Release.gpg Release

    # Get apt to see the changes
    sudo apt-get update
fi

conf/distributions文件示例内容

Origin: My_Local_Repo Label: My_Local_Repo Codename: xenial Architectures: i386 amd64 Components: main Description: 我的本地APT仓库 SignWith: 12345ABC

链接

https://wiki.debian.org/RepositoryFormat

http://ubuntuforums.org/showthread.php?t=1090731

https://help.ubuntu.com/community/CreateAuthenticatedRepository


@Phillip,你的编辑使用了 date -Rc,我根据编辑说明纠正为 date -Ru,假设这就是你的意思。 - muru
谢谢,我最近才开始收到apt的警告,原因是生成的日期是按本地时区而不是UTC。我已经在自己的脚本中修复了这个问题,但是忘记在这里编辑它。 - happyskeptic
1@KevinJohnson我已经更新了主要答案,并附上了我的本地apt仓库中的文件示例。 - happyskeptic

你可能想要看一下 apt-mirrorapt-cacher
这里有一个关于如何安装和使用它的指南。

你五年前的回答被标记为低质量。如果它被删除了,去元社区请求恢复。我投票保持开放,但是它需要编辑!**;-)** - Fabby

你还可以通过nginx和reprepro来设置本地源服务器。
  1. 安装Debian软件包

    sudo apt-get install reprepro nginx 
    
  2. 创建reprepro目录并进行编辑

    sudo mkdir -p /srv/reprepro/ubuntu/{conf,dists,incoming,indices,logs,pool,project,tmp}
    
    $ cd /srv/reprepro/ubuntu/
    $ sudo chown -R `whoami` . # 将仓库所有者更改为当前用户
    

    /srv/reprepro/ubuntu/conf/distributions

    Origin: 你的名字
    Label: 你的仓库名称
    Codename: karmic
    Architectures: i386 amd64 source
    Components: main
    Description: 正在创建的仓库的描述
    SignWith: YOUR-KEY-ID
    

    /srv/reprepro/ubuntu/conf/options

    ask-passphrase
    basedir .
    
  3. 将其包含在reprepro中,构建它

    $ reprepro includedeb karmic /path/to/my-package_0.1-1.deb \
    # 将 /path/to/my-package_0.1-1.deb 更改为您的软件包的路径
    
  4. 配置nginx:

    /etc/nginx/sites-available/vhost-packages.conf

    server {
      listen 80;
      server_name packages.internal;
    
      access_log /var/log/nginx/packages-access.log;
      error_log /var/log/nginx/packages-error.log;
    
      location / {
        root /srv/reprepro;
        index index.html;
      }
    
      location ~ /(.*)/conf {
        deny all;
      }
    
      location ~ /(.*)/db {
        deny all;
      }
    }
    
  5. 优化桶大小:

    /etc/nginx/conf.d/server_names_hash_bucket_size.conf

    server_names_hash_bucket_size 64;
    

参考 安装指南链接


4虽然这个理论上回答了问题,但最好包括答案的关键部分,并提供参考链接。 - gertvdijk
@elprup:你可能忘记更新那个答案了 :) - 0xC0000022L
reprepro不支持同一软件包的多个版本。听起来有些奇怪,但这就是reprepro的工作方式。 - maxadamo

在Ubuntu 18.04上,@BigSack的回答Ubuntu官方维基帖子中的指示对我没有起作用,直到我做了以下两个更改:

  1. 生成一个未压缩的 Packages 文件(执行此操作时,工作目录必须是所有软件包所在的位置)

    cd /usr/local/mydebs
    dpkg-scanpackages -m . > Packages
    
  2. /etc/apt/sources.list 中添加以下条目

    deb [trusted=yes] file:/usr/local/mydebs ./
    

There are several reasons you may want to create a local repository. The first is that you want to save on bandwidth if you have multiple Ubuntu machines to update. For example if you had 25 Ubuntu machines that all needed updating at least once a week, you would significantly save bandwidth because you could do all but the repository locally.

Most organizations have decent bandwidth for their network gateways but this bandwidth is a precious commodity that needs to be used wisely.

Many organizations still have routers with 10MB or 100MB limits at the gateway but 1 GB network connections internally so bandwidth could be better used internally. The second reason for creating your own repository is that you can control what applications are loaded on your internal Ubuntu machines.

You can remove any applications your organization does not want to use on the local network from the repository that updates the machines. Even better, you can create a test box and test applications and versions before you allow them to roll out into your network assuring security and stability.

You first have to setup a mirror, to do that you need to Just press Ctrl+Alt+T on your keyboard to open Terminal. When it opens, run the command below.

apt-get install apt-mirror 

Once you have your set up apt-mirror you can start your download of the repository with this command.

apt-mirror /etc/apt/mirror.list1

继续阅读

1来源:创建一个Ubuntu仓库


抱歉,链接已失效。 - xamiro

建立一个离线本地仓库
1. 创建一个可访问的目录(至少由root用户可访问)

sudo mkdir /var/my-local-repo

  1. 将所有deb文件复制到此目录中。
  2. 扫描该目录

sudo dpkg-scanpackages /var/my-local-repo /dev/null > /var/my-local-repo/Packages

  1. 将本地仓库添加到源列表中

echo "deb file:/var/my-local-repo ./" > /tmp/my-local.list

sudo mv /tmp/my-local.list /etc/apt/sources.list.d/my-local.list

sudo apt-get update


同样的东西也在官方维基上有:Repositories/Personal - Community Help Wiki - sdaau

我尝试使用选定答案中的apt-rdepends,但当我尝试从我的本地仓库安装软件包时,它抱怨缺少依赖项。
apt-rdepends没有列出我的软件包的一些依赖项。我怀疑这与apt-cache show显示多个记录有关。
相反,我使用了apt-cache depends,这解决了问题:
获取递归依赖项列表
apt-cache depends <packagename> -i --recurse

-i:只包含重要的依赖项 --recurse:递归

将其转化为易于理解的列表

  • 去除符号和空格:| tr -d "|,<,>, "
  • 去除Depends:和PreDepends::| sed -e 's/^Depends://g' | sed -e 's/^PreDepends://g'
  • 对列表进行排序:| sort
  • 仅保留唯一值:| uniq > list.txt

完整命令:

apt-cache depends <packagename> -i --recurse | tr -d "|,<,>, " | sed -e \
's/^Depends://g' | sed -e 's/^PreDepends://g' | sort | uniq > list.txt

下载软件包

for i in $( cat list.txt ); do apt-get download $i; done;

扫描包并将其转换为Packages.gz。
dpkg-scanpackages . /dev/null | gzip -9c > Packages.gz

1可能是一个好主意,提及你所指的答案是哪个... - anonymous2

请查看OpenRepo(https://github.com/openkilt/openrepo
这个开源项目作为一个Web服务器运行。您可以将软件包上传到它上面,然后它会在您的局域网上托管,供其他服务器进行升级。