Just set up a simple but signed repository on a webserver. Because most other tutorials are somewhat dated or cumbersome, I'll try to replicate the procedure here. The initial configuration is a bit effort, but the simple build script keeps it easy to manage. And you can just drop in new *.deb files, then update.
setup keys
First you need to create a gpg signing key for packages and your repository. Make it a (4) RSA signing key, no password, and give it a unique $KEYNAME when asked for, further examples assume "dpkg1".
gpg --gen-key
gpg -a --export-secret-key dpkg1 > secret.gpg
gpg -a --export dpkg1 > public.gpg
I said no password, because your webserver has no monkey to type it in repeatedly. And the signed packages and repository are only meant to satisfy update-managers obnoxiousness anyway. Just upload both keys to the new /apt/ repository directory on your webserver, but delete the secret.gpg key after initialization.
update script
This is the simple update shell/CGI script for it:
#!/bin/sh
echo Status: 200 Okay
echo Content-Type: text/plain
echo
echo Rebuilding APT repository:
{
#-- settings
export GNUPGHOME=/var/www/usr12345/files
export KEYNAME=dpkg1
#-- one-time setup
if [ ! -e "$GNUPGHOME/secring.gpg" ] ; then
gpg --import -v -v ./secret.gpg
gpg --import -v -v ./public.gpg
gpg --list-keys
fi
#-- symlink .deb files from adjacent sub-directories
find .. -name '*.deb' -exec ln -s '{}' . \;
#-- build Packages file
apt-ftparchive packages . > Packages
bzip2 -kf Packages
#-- signed Release file
apt-ftparchive release . > Release
gpg --yes -abs -u $KEYNAME -o Release.gpg Release
} 2>&1
The three gpg lines only need to be executed once, to initialize the GPG setup in some directory $GNUPGHOME (above the document root). Delete only the secret.gpg after success.
One unique feature of this small shell script is that it accepts any *.deb files that you drop in, but also searches recursively (starting from one level up) for others, and links them. (Needs .htaccess Options FollowSymLinks eventually.)
You can either execute this script manually as CGI or per cron-job. But hide it, or better yet move it out of the data directory.
Because it's a "trivial" apt repository it needs following apt-sources.list entry:
deb http://example.org/deb/ ./ # Simple singed repository
That's suitable for single-architecture repositories, and if you don't expect hundreds of packages.
package signing
Signing your individual packages is also trivial, once you've set up your gpg keys:
dpkg-sig -k dpkg1 -s builder *.deb
(This should be done on the workstation where packages are built, not on the repository webserver.)
unsigned repo
If you didn't need any signing, then you could slash the update script down to just:
dpkg-scanpackages . > Packages
bzip2 -kf Packages
usability
For end users, just drop a HEADER.html into the repository directory. Apache mod_auto_index will prepend that note:
<h1>http://example.org/apt/</h1>
<dl>
<dt>Add this repository to /etc/apt/sources.list as:
<dd><kbd>deb http://example.org/apt/ ./ # example repo</kbd>
<dt>Import verification key with:
<dd><kbd>wget -q http://http://example.org/apt/public.gpg -O- | sudo apt-key add -</kbd>
</dl>