In my previous guide on creating Debian packages, I walked through the process of building packages for multiple Debian distributions using Docker. But creating packages is only half the battle - distributing them efficiently to users requires a properly configured Debian repository.
This guide will show you how to set up your own Debian repository using reprepro
, a tool that simplifies repository management. I’ll share my actual setup from debian.griffo.io, which hosts unofficial packages for tools like lazygit, lazydocker, uv, and more.
Before diving into the setup, let’s understand the structure of a Debian repository:
debian-repository/
├── dists/ # Distribution release directories
│ ├── bookworm/ # Debian 12 (Stable)
│ │ ├── InRelease # Combined Release file with signature
│ │ ├── Release # Repository metadata
│ │ ├── Release.gpg # Detached signature for Release file
│ │ └── main/ # Component directory
│ │ └── binary-amd64/ # Architecture-specific directory
│ │ ├── Packages # Package index
│ │ ├── Packages.gz # Compressed package index
│ │ └── Release # Component-specific metadata
│ ├── trixie/ # Debian 13 (Testing)
│ └── sid/ # Debian Unstable
└── pool/ # Package storage
└── main/ # Main component
├── l/ # First letter of package name
│ ├── lazygit/ # Package directory
│ │ ├── lazygit_0.40.2-1+bookworm_amd64.deb # Package for Bookworm
│ │ ├── lazygit_0.40.2-1+trixie_amd64.deb # Package for Trixie
│ │ └── lazygit_0.40.2-1+sid_amd64.deb # Package for Sid
│ └── lazydocker/ # Another package directory
└── u/
└── uv/ # Another package directory
This structure enables APT to efficiently locate and download packages for the correct distribution and architecture.
reprepro
is a tool that manages the repository structure for you, handling the creation of directories and index files. Let’s walk through the setup process.
First, install reprepro on your system:
sudo apt install reprepro gnupg
Debian repositories should be signed with a GPG key to ensure authenticity:
gpg --full-generate-key
Select RSA (sign only) with a key size of 4096 bits, and follow the prompts to create your key. Once created, note your key ID:
gpg --list-keys --keyid-format long
Export your public key to share with users:
gpg --armor --export YOUR_KEY_ID > repository-key.asc
Create the base directories:
mkdir -p debian-repo/{apt,deb,reprepro/{conf,db}}
Configure reprepro by creating a distributions
file:
cat > debian-repo/reprepro/conf/distributions << EOF
Codename: bookworm
Architectures: amd64
Components: main
Description: Apt repository for unofficial packages
SignWith: YOUR_KEY_ID
Codename: trixie
Architectures: amd64
Components: main
Description: Apt repository for unofficial packages
SignWith: YOUR_KEY_ID
Codename: sid
Architectures: amd64
Components: main
Description: Apt repository for unofficial packages
SignWith: YOUR_KEY_ID
EOF
Create directories for each distribution:
mkdir -p debian-repo/deb/{bookworm,trixie,sid}
To add packages to your repository, place your .deb
files in the appropriate distribution directory:
# Example for lazygit
cp lazygit_0.40.2-1+bookworm_amd64.deb debian-repo/deb/bookworm/
cp lazygit_0.40.2-1+trixie_amd64.deb debian-repo/deb/trixie/
cp lazygit_0.40.2-1+sid_amd64.deb debian-repo/deb/sid/
Then use reprepro to include them in the repository:
cd debian-repo
reprepro --dbdir reprepro/db --confdir reprepro/conf -C main includedeb bookworm deb/bookworm/*.deb
reprepro --dbdir reprepro/db --confdir reprepro/conf -C main includedeb trixie deb/trixie/*.deb
reprepro --dbdir reprepro/db --confdir reprepro/conf -C main includedeb sid deb/sid/*.deb
This command adds the packages to the repository and creates all necessary index files automatically.
reprepro will automatically sign the Release files, but if needed, you can manually sign them:
cd debian-repo/apt/dists/bookworm
cat Release | gpg -s --default-key YOUR_KEY_ID -abs > Release.gpg
cat Release | gpg -s --default-key YOUR_KEY_ID --clearsign > InRelease
Repeat for each distribution.
To streamline repository management, I’ve created several scripts that automate the process. Here’s how I’ve set up automation for my repository at debian.griffo.io:
This script downloads package files from GitHub releases:
#!/bin/bash
# download_deb_file.sh
REPO=$1
PACKAGE_VERSION=$2
BUILD_VERSION=$3
PACKAGE_NAME=$4
PWD=`pwd`
declare -a arr=("bookworm" "trixie" "sid")
for i in "${arr[@]}"
do
DEBIAN_DIST=$i
cd deb/${DEBIAN_DIST}
wget https://github.com/dariogriffo/${REPO}/releases/download/${PACKAGE_VERSION}+${BUILD_VERSION}/${PACKAGE_NAME}_${PACKAGE_VERSION}-${BUILD_VERSION}+${DEBIAN_DIST}_amd64.deb
cd ../..
done
This script updates the repository indexes after adding new packages:
#!/bin/bash
# generate_index.sh
current=`pwd`
reprepro=$current/reprepro
cd apt
reprepro --dbdir $reprepro/db --confdir $reprepro/conf -C main includedeb bookworm $current/deb/bookworm/*deb
reprepro --dbdir $reprepro/db --confdir $reprepro/conf -C main includedeb trixie $current/deb/trixie/*deb
reprepro --dbdir $reprepro/db --confdir $reprepro/conf -C main includedeb sid $current/deb/sid/*deb
cd dists/bookworm
cat Release | gpg -s --default-key YOUR_KEY_ID -abs > Release.gpg
cd -
cd dists/trixie
cat Release | gpg -s --default-key YOUR_KEY_ID -abs > Release.gpg
cd -
cd dists/sid
cat Release | gpg -s --default-key YOUR_KEY_ID -abs > Release.gpg
cd -
cd ..
For each package, I have a specific update script:
#!/bin/bash
# update_uv.sh
REPO=uv-debian
PACKAGE_VERSION=$1
BUILD_VERSION=${2:-1}
PACKAGE_NAME=uv
./download_deb_file.sh ${REPO} ${PACKAGE_VERSION} ${BUILD_VERSION} ${PACKAGE_NAME}
./generate_index.sh
git add .
git commit -m "Update uv to ${PACKAGE_VERSION}"
git push -u origin main
With these scripts, updating a package is as simple as:
./update_uv.sh 0.7.2 1
This downloads the package files, updates the repository indexes, and commits the changes to git.
Once your repository is set up, you need to host it so users can access it. Here are three common options:
Install Apache:
sudo apt install apache2
Configure a virtual host:
sudo nano /etc/apache2/sites-available/debian-repo.conf
Add the following configuration:
<VirtualHost *:80>
ServerName debian.yourdomain.com
DocumentRoot /path/to/debian-repo/apt
<Directory /path/to/debian-repo/apt>
Options Indexes FollowSymLinks
AllowOverride None
Require all granted
</Directory>
ErrorLog ${APACHE_LOG_DIR}/debian-repo-error.log
CustomLog ${APACHE_LOG_DIR}/debian-repo-access.log combined
</VirtualHost>
Enable the site and restart Apache:
sudo a2ensite debian-repo.conf
sudo systemctl restart apache2
Set up HTTPS with Let’s Encrypt:
sudo apt install certbot python3-certbot-apache
sudo certbot --apache -d debian.yourdomain.com
Install Nginx:
sudo apt install nginx
Configure a server block:
sudo nano /etc/nginx/sites-available/debian-repo
Add the following configuration:
server {
listen 80;
server_name debian.yourdomain.com;
root /path/to/debian-repo/apt;
location / {
autoindex on;
try_files $uri $uri/ =404;
}
}
Enable the site and restart Nginx:
sudo ln -s /etc/nginx/sites-available/debian-repo /etc/nginx/sites-enabled/
sudo systemctl restart nginx
Set up HTTPS with Let’s Encrypt:
sudo apt install certbot python3-certbot-nginx
sudo certbot --nginx -d debian.yourdomain.com
GitHub Pages can also host a Debian repository, although with some limitations. It’s a great free option for small repositories.
Create a GitHub repository for your Debian repository.
Structure your repository with the following directories:
apt/
- The Debian repositorypublic/
- Website files (optional)Configure GitHub Pages in the repository settings.
Add a workflow to automatically update the repository:
name: Update Repository
on:
push:
branches: [ main ]
jobs:
update-repo:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Import GPG key
uses: crazy-max/ghaction-import-gpg@v5
with:
gpg_private_key: ${{ secrets.GPG_PRIVATE_KEY }}
passphrase: ${{ secrets.GPG_PASSPHRASE }}
- name: Run repository update
run: |
sudo apt-get update
sudo apt-get install -y reprepro
./generate_index.sh
Add a CNAME file for a custom domain.
Once your repository is hosted, users can add it to their system with these commands:
curl -sS https://debian.yourdomain.com/repository-key.asc | sudo gpg --dearmor --yes -o /etc/apt/trusted.gpg.d/yourrepo.gpg
echo "deb https://debian.yourdomain.com $(lsb_release -sc) main" | sudo tee /etc/apt/sources.list.d/yourrepo.list
sudo apt update
My personal Debian repository at debian.griffo.io hosts packages for several tools that I use regularly:
I build these packages in separate repositories:
The repository itself is maintained in the debian.griffo.io GitHub repository.
If users report issues with GPG keys, ensure:
If a package conflicts with an official package:
myapp-unofficial
)If updates don’t appear for users:
Components (like main, contrib, non-free) can be configured in the distributions
file:
Components: main contrib non-free
Then, when adding packages, specify the component:
reprepro -C contrib includedeb bookworm package.deb
For completely separate repositories (e.g., stable vs. testing), create separate distributions
files:
mkdir -p reprepro/{stable,testing}/conf
Each with its own configuration.
Setting up a personal Debian repository might seem complicated at first, but tools like reprepro
make the process much more manageable. Once you understand the structure and have the initial setup complete, maintaining the repository becomes quite straightforward.
By following this guide, you can create your own repository to distribute your Debian packages professionally. Whether you’re distributing software for a small team or sharing your open-source projects with the world, a proper Debian repository provides a professional and convenient installation experience.
For more details about my personal Debian repository and the packages I maintain, visit debian.griffo.io or check out the GitHub repository.
If you’re looking for information on creating the actual Debian packages, don’t miss my previous guide on Debian packaging.