Software Development Simplified

The Ultimate Guide to Self-Hosting a Debian Repository

By Dario on May 1, 2025
Debian Repository Hosting

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

  1. Install Apache:

    sudo apt install apache2
    
  2. 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>
    
  3. Enable the site and restart Apache:

    sudo a2ensite debian-repo.conf
    sudo systemctl restart apache2
    
  4. 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

  1. Install Nginx:

    sudo apt install nginx
    
  2. 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;
        }
    }
    
  3. Enable the site and restart Nginx:

    sudo ln -s /etc/nginx/sites-available/debian-repo /etc/nginx/sites-enabled/
    sudo systemctl restart nginx
    
  4. 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.

  1. Create a GitHub repository for your Debian repository.

  2. Structure your repository with the following directories:

    • apt/ - The Debian repository
    • public/ - Website files (optional)
  3. Configure GitHub Pages in the repository settings.

  4. 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
    
  5. 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.

Twitter iconLinkedIn iconGitHub iconYouTube icon
© 2025 Dario Griffo. All rights reserved.