reprepro is a program to create a Debian repository, so people can access your packages in the normal way. It is particularly well-suited for individual "PPA" repositories. For alternatives, see DebianRepository/Setup. If you want to build packages that go in a repository, see Package build tools.

Generate a PGP certificate

People want to know that packages were actually created by you, not by someone who managed to gain access to your server. That means creating a security certificate, then signing packages with one of its keys and letting people verify them with another.

/!\ This page uses the term "certificate" to refer to the whole blob of data you create, and "key" to refer to individual structures within the certificate. See also What’s a ‘key’? in the the GnuPG FAQ.

Generate a certificate with sensible default settings:

gpg --gen-key

Then do gpg --list-secret-key:

$ gpg --list-secret-key
pub   rsa4096 2010-11-12 [SC]
      0123456789ABCDEFFEDCBA987654321001234567
uid           [ultimate] Joe User (Some organization) <joe.user@example.com>
sub   rsa4096 2010-11-12 [E]

[SC] on the first line means [S]igning and [C]ertification, and the long string on the second line is the its fingerprint. Make a note of that fingerprint, which you will need later.

For more information about using GPG in Debian, see GnuPG.

Configure reprepro

First, create a repo directory and configuration subdirectory:

mkdir -p /path/to/your/repo
mkdir -p /path/to/your/repo/conf

Next, create a /path/to/your/repo/conf/distributions file. It should include a series of blocks like this:

Codename: <release-name>
Suite: <release-pseudonym>
Architectures: source i386 amd64 <...>
Components: main <...>
Contents:
SignWith: <fingerprint>
Origin: <Your project name>
Label: <Your project name>
Description: <Your project description>

Codename: is e.g. trixie or sid. For a list of common values, do debian-distro-info --all. This is not supposed to change - if you need another codename, add a new section.

Suite: is e.g. stable or testing. Unlike the previous name, this can change when new releases come out.

Architectures: is a space-separated list of Debian architecture names.

Contents: is a list of zero or more flags. Including this but leaving it empty causes reprepro to generate Contents files, which are used by apt-file. This will make updates slower, but is valuable to apt-file users.

SignWith: is the signing fingerprint from Generate a PGP certificate, above.

Origin:, Label: and Description: are free-form text displayed to the user or used for pinning. For examples, do e.g. grep -C6 Label: /var/lib/apt/lists/*_InRelease.

conf/distributions should include one block for each release codename you want to support. After creating (or updating) it, you need to make reprepro create symlinks from Suites to Codenames:

cd /path/to/your/repo
reprepro createsymlinks

Finally, you may want to create a /path/to/your/repo/conf/options file. When you call reprepro from /path/to/your/repo, it will act as if these options were specified on the command-line. For example:

cd /path/to/your/repo

# Calling reprepro will behave normally at first...
reprepro ...

# ... set some default options ...
cat > conf/options <<EOF
verbose
ask-passphrase
EOF

# ... now it acts like you called `reprepro --verbose --ask-passphrase`:
reprepro ...

More advanced uses of reprepro (e.g. overriding package metadata), are discussed in the repepro man page.

Add packages

Your build tool should produce a collection of files for each package, including a .changes that contains an index of all the other files. To add the built package to your repository, do:

reprepro -b /path/to/your/repo include <release-name> <package>.changes

Or if you only have a .deb file, do:

reprepro -b /path/to/your/repo includedeb <release-name> <package>.deb

<release-name> should match a Codename: line in your conf/distributions file.

If reprepro returns an error, but you want to ignore it, see how to ignore errors in the man page.

reprepro will try to sign your package when it adds it. If your certificate is password-protected, you will need to specify --ask-passphrase (or add ask-passphrase to your conf/options file).

Configure a web server

The easiest way to let people access your repository is by putting it on a public web server.

Use your own server

If you have access to a public server, you can serve your repository from there.

First, install Apache, nginx, or one of the many other web servers supported by Debian on your server.

Next, serve the /path/to/your/repo/ directory like you would serve any other directory tree. See your server's documentation for details.

Finally, ensure the conf/ and db/ subdirectories are not accessible. These are used internally by reprepro, and could confuse users. Solutions include:

In theory, you don't need HTTPS to serve your repository, because it's already signed with your PGP key. But in practice, you do need HTTPS to serve the PGP key itself, so an attacker can't replace it with their own key in transit. Consider using a free LetsEncrypt HTTPS certificate on your site.

Use static hosting

A Debian repository is just a collection of files, and can be served from any normal static web-hosting service. For example, GitHub Pages, GitLab Pages and CloudFlare pages are all excellent free services. Debian salsa hosting is also available, but has fairly strict resource limits, and is mainly used by people who can get their packages into Debian proper.

/!\ free services generally have acceptable use policies, which may become a problem if your repository is extremely large or popular. Hosting a mirror of archive.debian.org this way is a good way to get your account terminated!

Help people add your repository

Before people can use your repository, you need them to install your (public) signing key and add it to their sources.list. And if you ever want to change your key or list, you'll need to update those files.

One good solution is to put those files in a .deb that you host in your repository. Then you can just ask people to manually install your .deb once.

Adapt the following:

PROJECT=<your-project-name>

# Create the package directory:
mkdir -p ~/"$PROJECT"-archive-keyring
cd       ~/"$PROJECT"-archive-keyring

# Create a control file:
mkdir -p DEBIAN
cat > DEBIAN/control <<EOF
Package: $PROJECT-archive-keyring
Version: 1.0.0-1
Section: misc
Priority: optional
Architecture: all
Maintainer: <your name> <[your e-mail address]>
Description: OpenPGP archive certificates of $PROJECT
 $PROJECT digitally signs its Release files. This package
 contains the archive certificates used for that.
EOF

# Create a keyring file:
mkdir -p usr/share/keyrings
gpg --export-options export-minimal --export <fingerprint> \
    > usr/share/keyrings/$PROJECT.pgp

# Create a sources.list:
mkdir -p etc/apt/sources.list.d
cat > etc/apt/sources.list.d/"$PROJECT".list <<EOF
deb [signed-by=/usr/share/keyrings/$PROJECT.pgp] http://<your-domain>/<your-path>/ <release-pseudonym> <components...>
EOF

# Create your package:
cd ..
dpkg-deb --root-owner-group --build "$PROJECT"-archive-keyring

# Add your package to the archive:
reprepro -b /path/to/your/repo includedeb <release-name> "$PROJECT"-archive-keyring.deb

# Create a symlink so people can find the file:
cd /path/to/your/repo
ln -s "$(find pool -name "$PROJECT"-archive-keyring*.deb)" "$PROJECT"-archive-keyring.deb

# Add a README for people to follow:
cat > README.txt <<EOF
To add this repository to your computer, download
$PROJECT-archive-keyring.deb in this directory,
then do:

    sudo dpkg -i "/path/to/$PROJECT-archive-keyring.deb"
    sudo apt update

For more information, see:
https://wiki.debian.org/DebianRepository/UseThirdParty
EOF

{i} dpkg-deb --build is only intended for very simple packages. For a more flexible solution, see PackagingWithGit.

See also