Ubuntu uses online package repositories to locate available software and then download it to your computer for installation. If you create your own Ubuntu packages, you can install them directly using dpkg, but that's not very convenient when you want to make your packages publicly available or install them on a large number of computers. The solution is to build your own package repository, just like the ones used to distribute the official Ubuntu packages, and populate it with your own custom packages. Once your packages have been published in a repository, anyone can then use it to install your packages using any of the standard package-management tools such as apt, Synaptic, or Adept. All they need to do is add the address of your repository to their system.
This also makes it much easier for users of your software to stay up-to-date because their system will be able to automatically detect new versions of your packages and ask them if they want to update.
Anatomy of a Repository
An Ubuntu package repository is actually quite simple. In its simplest form, it can be just a number of packages placed on a web or FTP server along with a special Packages.gz file that describes them. Each package is a self-contained .deb file that can be downloaded and installed on a computer, while the Packages file acts as a directory for the packages in that particular repository and includes information about each package such as the name, description, version, dependencies, name of the maintainer, and location of the actual package files. By fetching the Packages files from various repositories, Ubuntu can provide the user with a list of available packages and their descriptions, and determine dependencies without having to download each package individually. For a small repository, the .deb and Packages files are pretty much all you need to provide, and setting up everything is quite simple.
Larger repositories often include additional files and are structured differently to make them more efficient. For example, some larger repositories place packages into subdirectories named after the first letter of the package name, rather than just lumping them all in the same directory: audacity and aumix go into an a/ subdirectory, blam goes into b/, and so on. That way no single directory contains too many files, and the performance of the server's filesystem doesn't become a bottleneck. That's not generally a problem until you have many thousands of packages, though, so unless you're setting up an extremely large repository, it's not something you should have to worry about.
Some large repositories also implement package pools. Pools are a way to save disk space and processor time when you have multiple repositories that share some of the same packages. This is the case with the official Debian repositories, for example, where some packages can exist in exactly the same version in two or more of the Experimental, Unstable, Testing, and Stable repositories at the same time. Pools allow all packages in all versions to be stored in the same big directory structure on the server, and each repository then acts as a sort of virtual index that lists or links to only the packages that are intended to be available in it. The Packages file for each of the repositories therefore references just a subset of the packages in the total package pool.
Getting Started
To create your own repository, first you need to create the software packages themselves). Install the packages manually on your local system and make sure they function correctly before you try publishing them in a repository.
You will also need some web-hosting space on either a server that you run or web space provided by a hosting company. In any case, the repository needs to have a consistent address so that other computers know where to find it. You could just use the server's IP address, but ideally it should have a hostname set up properly in DNS.
The main trick to maintaining a repository is generating the Packages file properly, and there are a number of tools to help you do so simply and consistently. The tool you'll use for this hack is apt-ftparchive, a simple program that you can run whenever you want to update your repository. It's best suited to manually maintaining a small-to-medium number of packages in a simple repository. Other tools you can consider include mini-dinstall, which runs as a daemon and automatically handles new packages as they are uploaded to a special incoming directory, and dpkg-scanpackages, which is run manually. The granddaddy of all repository managers is dinstall itself, which is designed to run very large repositories, such as the official Debian package servers, with tens of thousands of packages.
apt-ftparchive is part of the apt-utils package, so the very first thing to do is install apt-utils:
$ sudo apt-get install apt-utils
Next, you need to create a directory inside your web server's document root to store the packages. You could just create a single directory and put everything in there, but for future flexibility, it's a good idea to also create a subdirectory to allow you to have subsets of packages. This is typically used to publish packages built against different releases, such as different versions of the same package for Dapper and Breezy. In this example, you'll create a subdirectory for Dapper packages, but you can name it something else if you prefer. The repository should be in your web server's document root, so if your document root is /var/www (the standard location in Ubuntu), you could just run:
# mkdir -p /var/www/ubuntu/dapper
Now copy the .deb packages you want to serve into that directory. At this point, you should be able to access the packages by pointing a web browser at http://localhost/ubuntu/dapper/
Finally, open a shell and move into the ubuntu directory to execute apt-ftparchive and then compress the resulting Packages file:
# cd /var/www/ubuntu
# apt-ftparchive packages dapper > dapper/Packages
# gzip dapper/Packages
The packages argument tells apt-ftparchive to process packages it finds; dapper is the path to search, which in this case is the dapper subdirectory; and > dapper/Packages redirects the output into a file called Packages, which is then compressed to make it download faster. Easy!
At this point, you have a repository that you can access from other computers to install the packages you've just published, but first you need to tell them how to find it by adding a line to their /etc/apt/sources.list file. The entry should look something like:
deb http://www.example.com/ubuntu dapper/
where www.example.com is replaced by the actual address of your package server.
Then run apt-get update, and you should see your repository being indexed along with the normal Ubuntu repositories, after which you can apt-cache search for your packages, and they should be reported as being available. With a simple apt-get install packagename, you can install any of the packages you've published.
Update the Repository
Created a new or updated package? No problem. Just copy it into the repository alongside the other packages and follow the steps described earlier to rerun apt-ftparchive and generate a new Packages file. Because updated packages have different filenames, you'll need to manually delete superseded packages prior to rerunning apt-ftparchive; otherwise, your repository will just keep getting bigger.
Manage a Repository Without Shell Access
While it's simplest to create your repository directly on the web server, it's certainly not essential. If you have access to web space by FTP but can't get shell access to the server, you can create a repository on your local computer following the instructions in this hack and then just use FTP to upload all the directories and files to the correct location on the server. Then, when you do an update to any of the packages in the repository, just rerun apt-ftparchive locally and then bring the copy on your web server up-to-date again by FTP.