Contents
- Introduction
- Generating OpenPGP keys
- Configuring Apache
- Configuring Nginx
- Configuring github page
- Configuring reprepro
- Using overrides
- Adding packages to the repository
- Exporting the public OpenPGP key
- Creating a sources.list.d file (DEB822-style)
- Signing Debian packages without adding to repository
- Troubleshooting
Introduction
It can be quite useful to be able to distribute your own Debian packages using apt, without having to push them to the Debian project itself. Doing this properly requires several steps:
- Generate OpenPGP keys for package/catalog file signing
- Generate the Debian packages
Create an apt repository using reprepro
Add packages to the repository (again, using reprepro)
- Sign the Debian packages
- Get access to public facing web server.
- option1: Install, configure, and run a webserver your self (e.g. Apache)
- option2; Get an account on a web server (e.g. github.com account)
- Transfer repository data on local secure machine to remote web server (rsync, git, ...)
- Configure the APT client to access repository with the secure APT
Each of these steps is covered here. For more detail than is presented here, see the following HOWTO's:
Creating your own Signed APT Repository and Debian Packages: very good explanation of the use of GnuPG (slightly outdated)
reprepro(1) man page
reprepro's manual (not same as the man page)
sources.list(5) man page
Generating OpenPGP keys
GnuPG can be used here for two purposes:
- Signing the catalog files (automatically by reprepro) -- this is desirable method for most cases
- Signing the Debian packages (manually)
Before generating a key, become familiar with current best practices for key security. As of this writing, a good description is available at "OpenPGP Key Checks" and a good ~/.gnupg/gpg.conf for the user that will generate the key would include:
# Prioritize stronger algorithms for new keys. default-preference-list SHA512 SHA384 SHA256 SHA224 AES256 AES192 AES CAST5 BZIP2 ZLIB ZIP Uncompressed # Use a stronger digest than the default SHA1 for certifications. cert-digest-algo SHA512
Generate the key using the following command:
$ gpg --gen-key
or
$ gpg --full-gen-key
In general, you should run that command on the secure computer creating repository structure files for the apt repository, as the user that will sign the packages. Then you should set up method to replicate repository contents to the remote server (rsync etc.). (Leaving secret key on a remote server is never a good idea.)
Configuring Apache
If you decide to run webserver yourself for the repository, you need to configure it.
Here we assume you got Apache (2.4, buster or newer) running already, and serving web pages - even if only the default index.html. First you need a directory for the apt repository:
$ mkdir -p /srv/repos/apt/debian
Next you should add Apache rules to make a few directories used internally by reprepro invisible to users of your repository. Add something like this to a Apache server configuration file fragment (e.g. /etc/apache2/conf.available/repos.conf) or to a VirtualHost definition:
# /etc/apache2/conf.available/repos.conf # Apache HTTP Server 2.4 Alias /repos/apt/debian /srv/repos/apt/debian <Directory /srv/repos/ > # We want the user to be able to browse the directory manually Options Indexes FollowSymLinks Multiviews Require all granted </Directory> # This syntax supports several repositories, e.g. one for Debian, one for Ubuntu. # Replace * with debian, if you intend to support one distribution only. <Directory "/srv/repos/apt/*/db/"> Require all denied </Directory> <Directory "/srv/repos/apt/*/conf/"> Require all denied </Directory> <Directory "/srv/repos/apt/*/incoming/"> Require all denied </Directory>
This allows users to browse the pool directory with the browser, should he/she want to. The configuration also blocks a few directories used by reprepro internally, without affecting normal apt usage. Finally check that the configuration is sane and reload it:
$ sudo a2enconf repos # enable repos conf $ apache2ctl configtest # test the configuration Syntax OK $ sudo service apache2 reload # enable the configuration
Configuring Nginx
You can also run the webserver using nginx.We assume nginx is installed on your machine.
Open the configuration file with any text editor.
$ nano /etc/nginx/sites-available/default
And add the following configuration directives:
server { listen 80; access_log /var/log/nginx/repo-error.log; error_log /var/log/nginx/repo-error.log; location / { root /srv/repos/apt; autoindex on; } location ~ /(.*)/conf { deny all; } location ~ /(.*)/db { deny all; } }
Reload nginx
# systemctl restart nginx
With your server’s IP address, you can now add this repository to any other debian machine and install packages from your repository.
Configuring github page
If you don't feel like running webserver yourself for the repository, you may be able to use free webservers if the repository is small enough to meet their acceptable use policy.
Many free source code hosting services such as Github and Gitlab comes with web site hosting service with https://<username>.github.io like URL. They can be used to host a package repository. The repository content transfer is as easy as committing them to the <username>.github.io repository.
Although Debian Debian salsa should be able to do this too, it may not be a good idea since its resource is quite tight already.
Hosting entire repository of Debian mirror this way is strongly discouraged even for commercial free service sites.
Configuring reprepro
Reprepro eases the task of creating apt-compatible directory layout, apt-specific files and databases and removing and adding packages to the repository.
First, create a reprepro configuration directory:
$ mkdir -p /srv/repos/apt/debian/conf
Second, create the conf/distributions file. In our example, the contents of /srv/repos/apt/debian/conf/distributions would look something like this:
Origin: Your project name Label: Your project name Codename: <osrelease> Architectures: source i386 amd64 Components: main Description: Apt repository for project x SignWith: <key-id>
Above, <osrelease> is an official Debian release name (e.g. buster or bulleseye or sid) and <key-id> is the ID of the OpenPGP key you generated. You can check the key ID (fingerprint) with gpg:
$ gpg --list-secret-key --with-subkey-fingerprint pub rsa4096 2010-09-23 [SC] E123D55E623D56323D65E123655E623D563D5831 uid [ultimate] Joe User (Some organization) <joe.user@example.com> sub rsa4096 2010-09-23 [E] F24957412415744F1495F149571F2495F2495714
Here <keyid> (fingerprint) for the OpenPGP key is F24957412415744F1495F149571F2495F2495714 (that's technically the subkey, which is recommended to be used for this sort of signing purpose).
You can repeat the section as many times as needed for different OS releases.
Third, add an options file to make daily life with reprepro command-line a little easier. This file is in /srv/repos/apt/debian/conf/options:
verbose basedir /srv/repos/apt/debian ask-passphrase
For further details, refer to the instruction given here.
Using overrides
Sometimes, you want to add a package from another source (for example, Debian unstable) to your repository. Rather than have to repackage it, you can use overrides to change some of its metadata.
This configuration is not needed if you do not plan to use packages from other sources.
To enable overrides, add the following to your conf/distributions file:
DebOverride: override.<osrelease> DscOverride: override.<osrelease>
As above, <osrelease> is an official Debian release name (e.g. squeeze or wheezy), and those lines should be added to each release section you have configured.
Then, for each release you support, create the override file, where you add additional metadata for each package. This file is saved to /var/www/repos/apt/debian/conf/override.<osrelease>:
your_package_name Priority optional your_package_name Section net
Adding packages to the repository
Once all of the above is done, you can add packages to the repository. Reprepro takes care of signing and all, so this should suffice:
$ reprepro include <osrelease> <changesfile>
Again, <osrelease> is something like squeeze or wheezy.
Run the command from your repository directory, or pass the -b option with the path to the directory, or set the REPREPRO_BASE_DIR environment variable to the directory path.
You may also need to add --ignore=wrongdistribution to the above as needed.
Reprepro should prompt you for the GnuPG password, because options file contains the ask-passphrase configuration option. See man reprepro for more options, e.g. how to import a package's changes file to the repository.
Exporting the public OpenPGP key
Finally, you need to export the public part of your OpenPGP keypair from the keychain:
$ gpg --armor --output whatever.gpg.key --export-options export-minimal --export <key-id>
Copy this to a webserver so that users can download it and add it to their OpenPGP keychains similarly to this (as root):
$ wget -O - http://www.example.com/repos/apt/conf/<whatever>.gpg.key | apt-key add -
Creating a sources.list.d file (DEB822-style)
You can obtain your public key by:
$ gpg --export -a --export-options export-minimal <your-hash>
You need to publish instruction to the repository users how to access this APT repository securely using this public key.
The simplest way is to use DEB822-style sources.list(5) file. The following script as installation method is one way to post your public-key:
$ sudo tee /etc/apt/sources.list.d/examplesite.sources <<"EOF" Types: deb URIs: http://examplesite.github.io/debian/ Suites: sid Components: main Signed-By: -----BEGIN PGP PUBLIC KEY BLOCK----- . mQINBEya74YBEADDpLTJCmyS97kZ6JvlpUEoSoVbqEkyQVfrV7C7VqlBGWO0bTKI z0QAOkzF47HIDTez+ISLRd84Dyh/BPpSTF2CP3HnLo21UxotvQFeVVs87EKTgrM5 MsRgmEU4o28be0Uz0ix0U5ahaOqX6TI1+faZ8Bn2Q9MnhYoSaS0DyRrEAIU0xrSk VDrN3GrjUYli2GwF/GgKCKT92rxPvcaJIbtMqNWkm9QJVqyTLNw/kY1ywU5weehE tIK0IU2ib5dakYubUfdCv54UXAB30sryMpgbi60ELEtEG1t6icKBOta+kCHkDggl Ts9YIAOMQvRy1qwiySuv1P+4AOSoC7yS/WlGBoGOhThSnGcdjoXXGixmkeSw3MO5 F/2e3vd7BWDDygyxJldtf8p6OmD6bj7FLoPB97Qvilpt2JQ27Sn9zVOC4/wCKaqx 628GXsKx4gyoieSCKxHJuGTuD7nyAnqn/E04IyhJ5TAjai39x+ZUwWnT84dSOnEm 0+3lORr9Iwkrbrom5BFZ9vrgEQ1Dp52v5anfjlPPiPdUMF/66H9nFrhjS26LLodA WUEWAoc4u2vjAOD2LGjCs1XKdVMgFci2rVLSVYlj2aWjU3dPUvqvGo0IReiJx9RY MEBZnc9CHEdWFZjVUFFKc/pjrgwIcq6LDRIPdd2n8bYy0y8TxFwyax9bPQARAQAB tB1Pc2FtdSBBb2tpIDxvc2FtdUBkZWJpYW4ub3JnPokCOAQTAQIAIgUCTJrvhgIb AwYLCQgHAwIGFQgCCQoLBBYCAwECHgECF4AACgkQHhNWiB3Y15FJNRAAuKkCIxJO 3QrcscEPwS0n/gXBPYlAkxNMJOT3Iju8D7aweIjEeEm4YN8wZWNvqD1npkFHcDXl LlNpcsIoQOoyyT4XIJ2bC8z80pxGTUdNd/FcmmJi8QMrg8+xf/cGvA3FdM9vdWOQ lai5m5HyAdz/kvxD5KXw6GUOybzxVSg/MKK+Ugcwl/sHU9FT9zgy5myeNSiChn1J DntBsKh3TWQd3uXKdFS0vaMvDDm3HeSwXBcV0tT8tMuaxOu2gdxv0br+SoFytsN+ PSjTTr8Tu6n/EkwMugUmXTqoNRS726nt4fVzbKYIQ9QEz2O8udC5PumHvTIOKcTn ExuMy+M9cZhr5q5YOIIST3A04PtT6oUA5yJPtlQMGpE2642CwebWpXAhz+STWVJ7 9mziN9Spd1TQ7r5wAukvYSRalO67WeONzntyX9KEzL2397ExKvO8FBpSpzms0S2F 34CrZW2MfhrbOb3gh9phUXRLd2anU6k3cTiAMnMmLK+j8y3PDV2AApfhtaHQ7PPB EYCvtsiDj28kpTX2gh9rqhJFG/vQbHBDQQvb8C4eoIYCIwVrZ8GGXZTz+CSLsTax auCjBlLpV1I3n7jAddpHE4nsAA6FkQK63jhQg+maiiIOmdEQa00P+0Re4txOqlJR Kyao3TFRmJY/Z4Qbl3bfDfmzNZ0lZRHGZ+K5Ag0ETJrvhgEQANuySzxnEDcSFToN biGiotoRfCJvKdHjPWLke7Vji+ro4BR151wSjhv7lsVIiGhEmIp/bRO8mY3rwgiG 1RUNI8cqDlzI0PtYJrrhcmi3ppB5y3frkJilFgQijhDHnTTId1d3ntwwzzBrAxh8 Bvx7BNbD9cN6ChIUJ6B6ISQpgw7EKnOTfYYc+EA/EppYcNsXKgm77W7/PC5Ss1Q0 1EQ2O9GDQxiF8OEbJANSO4wExAWK5LN4Kuod4vt7hoGzgfKo1woviuephAUxnqqK hK/WG0YB/nPFdGLn+mYWomMTe4ayrCIsHxS70gIt36DUAA1SDCTp8Fb34s9AB6YY EK83g4NW09e/Czoxl3W8Kej1uPwt62MVxjc8HzQ3wPCriXbye5Lc74NARj+N6lor t5CwyPRiy5iBaygZVOw+pBA4kRdi5sGUvbSZ4tTvtCHMcg1zpSHs/P/qSUGsO+wG m9nWCB4i4zsDZ9GlEpneqSVtWgXKEbTzymC/Z0tvORAOvamCkt06nnsbJqNdI7g8 2oCL/rkKCxNG/675kPHJGw/f1GyWuJz/6U1Zv6QFpKzVID9Wj5+pow8uDLxywEWH XmFjMEfg8E0FO4UStCo+qsIUdd6jQHh/VuFsGPQS0lH1FnR+jYljyrxUFcUFlrVz G5YtDrXFILFbEVUkbKrGbsfYUU2BABEBAAGJAh8EGAECAAkFAkya74YCGwwACgkQ HhNWiB3Y15HN0A//QAKmdXv7nuddbe0kWb27779e0HXKpuhj9DyuKU7lXIMqSwtD +/yo4vbb1nGVnPO/+xTF6ecUjnDrEMe/Q2fqHbm3bglwlkii9flvwORjxxBfghdJ ipFuloL3C28VuQgx2kNeYtbvyLP6roZxR80c2+NQTHtkL2Ba2dtiptwsB4vKk+a0 vi9g+MjbPknSkoZ6TbZVog7ia0HcbS+QstfXCQUPi1ccKK9oNFVdTTBLamnq4Ts6 TAPRmRt7y4ob2dBm4R0Hpb9qIhTsI0+YKL7rtXHX2bFcMgg0OHz/Vn8LGT+euEgc Zi9CQp8C6mrO+mFybBSWhndBra8NPTSY4iLYz/MlHq6vvtFsmeCpO2BpfI5vUSWl tSI7whA5B2wAEJ6oEWHfdxvWSzRDQ+BORk6I4QQZpulQRqjHpeDSiMLCZHXqikdo oYlQr2hin9CBKPECAqNdqVSYjooOJlyEYfRbz/hqsOcfqigqKKJx3vqKSxkta6bi eHjRE+iyP1usPbzY4bLj4gMP/CpDC8+mkNmNluFKFRHmCu+Jzlg+lcYH1tVUqVYe 9wlS6op6YDVVwPWT9vU3sviry81ADb25Dg8TBQz5UCZvF8iHEpTS7KcmWKLW8oNY 2y9kyyQKjvp2s5m59LrAy3gunqEqMS3oxqPj8/NMvWK8mJoL07R52TxDk6k= =Ao1Z -----END PGP PUBLIC KEY BLOCK----- EOF
Please note key is padded with leading " " and a blank line is replaced with " ." (space and period)
Now secure APT will work flawlessly as:
$ sudo apt update $ sudo apt install <your-package-name>
Signing Debian packages without adding to repository
dpkg-sig is almost never what you want, ignore this section.
reprepro will take care of the signing, so you normally don't have to do this separately. But if you do want to simply sign a package, without deploying it on your repository, you can use dpkg-sig.
First, install dpkg-sig:
$ sudo apt install dpkg-sig
Then sign your package(s):
dpkg-sig -k keyid --sign builder your_packages_$VERSION_$ARCHITECTURE.deb
Refer to this article for more details.
Troubleshooting
When importing packages from Debian you might find that you are missing SHA-1 and SHA-256 hashes in your apt metadata (Release/Packages/Sources files). To rectify this reprepro has a redochecksums command that you should run.