The Ultimate Guide to Self-Hosting a Debian Repository
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.
Understanding Debian Repository Structure
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.
Setting Up Your Repository with reprepro
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.
1. Install reprepro
First, install reprepro on your system:
sudo apt install reprepro gnupg
2. Create a GPG key for signing
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
3. Set up the repository structure
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}
4. Add packages to the repository
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.
5. Sign the Release files
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.
Automating Repository Management
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:
Download script
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
Generate index script
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 ..
Package update script
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.
Hosting Your Repository
Once your repository is set up, you need to host it so users can access it. Here are three common options:
Option 1: Apache Web Server
-
Install Apache:
sudo apt install apache2 -
Configure a virtual host:
sudo nano /etc/apache2/sites-available/debian-repo.confAdd 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
Option 2: Nginx Web Server
-
Install Nginx:
sudo apt install nginx -
Configure a server block:
sudo nano /etc/nginx/sites-available/debian-repoAdd 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
Option 3: GitHub Pages
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.
Client Configuration
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
Real-world Example: My Repository
My personal Debian repository at debian.griffo.io hosts packages for several tools that I use regularly:
- lazygit - A simple terminal UI for git commands
- lazydocker - A simple terminal UI for Docker
- uv - A fast Python package installer and resolver
- yazi - A terminal file manager
- lowfi - A TUI system resource monitor
- Ghostty - A fast, GPU-accelerated terminal emulator
I build these packages in separate repositories:
The repository itself is maintained in the debian.griffo.io GitHub repository.
Common Issues and Troubleshooting
GPG Key Problems
If users report issues with GPG keys, ensure:
- Your public key is publicly available
- The InRelease and Release.gpg files are properly signed
- Users are correctly importing the key
Package Conflicts
If a package conflicts with an official package:
- Consider using a different package name (e.g.,
myapp-unofficial) - Use a different version scheme that won’t conflict with official packages
Repository Updates Not Visible
If updates don’t appear for users:
- Verify the Release files have updated dates and checksums
- Check that files are accessible over HTTP/HTTPS
- Confirm package architecture matches what users are expecting
Advanced Topics
Setting Up Multiple Components
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
Creating Multiple Repositories
For completely separate repositories (e.g., stable vs. testing), create separate distributions files:
mkdir -p reprepro/{stable,testing}/conf
Each with its own configuration.
Conclusion
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.