Dépôt APT/PPA privé sur votre serveur

Dans cet article, je vais vous expliquer comment installer sur votre serveur un dépôt APT privé.

L'intérêt est de pouvoir publier un projet avec du code fermé car les PPA (que j'explique dans cet article) de launchpad.net sont utilisable que pour les projets open source.

Dans mon cas j'en ai besoin pour mon project Douane (que je présente dans cet article [Anglais]).

Principe de fonctionnement

Une fois que votre code source est prêt pour être empaqueté, à l'aide de la commande dput vous enverrez sur votre serveur les fichiers de votre projet et ce dernier qui aura les services rebuildd et reprepro qui tourneront, va compiler votre projet puis génerer les paquets .deb pour les différentes architectures que vous aurez configuré.
Finalement les personnes voulant utiliser votre projet n'auront plus qu'a ajouter votre serveur dans leur sources d'apt, importer votre clé GPG puis mettre à jour leur liste de paquet et installer votre projet.

Le dépôt

Nous allons commencer par mettre en place le dépôt APT et sa clé GPG sur votre serveur de facon à ce que vous puissiez appeler votre serveur, avec apt, depuis votre machine.
Bon le dépôt sera vide mais au moins il fonctionnera :-)

Installation

L'application qui permet de mettre en place un dépôt APT est reprepro.

Une fois que vous êtes connecté à votre serveur:

sudo apt-get install reprepro
sudo mkdir -p /srv/reprepro/{conf,incoming,incomingtmp,bin}

Ceci va donc installer reprepro et créer la structure dans laquelle votre serveur stockera les paquets.

Configuration

Maintenant nous allons configurer reprepro.

conf/distributions

Il faut créer le fichier /srv/reprepro/conf/distributions (en utilisant sudo) et y décrire les différentes distributions supporté par le dépôt:

J'explique plus bas à quoi servent les lignes:

Log: logfile
  --changes /srv/reprepro/bin/build_sources

conf/options

Nous allons aussi définir les options que nous voulons pour reprepro en créant le fichier /srv/reprepro/conf/options (en utilisant sudo) avec ce contenu:

verbose
basedir .

conf/incoming

Afin que nous puissions utiliser la commande dput pour envoyer nos projets il faut configurer une queue d'entrée pour les fichiers. Pour ce faire créez le fichier /srv/reprepro/conf/incoming avec ce contenu:

Dans ce fichier vous devez spécifier les séries/versions que vous supportez. Dans mon exemple j'ai mis les versions precise quantal raring saucy d'Ubuntu.

Création d'une clé GPG

Afin d'éviter que quelqu'un publie des paquets en se faisant passer pour vous il faut créer une clé GPG qui sera utilisée pour signer les paquets .deb.

Sur votre serveur:

sudo -i
gpg --gen-key

(Il est important d'exécuter gpg --gen-key de cette facon, sinon la clé sera attribué à votre utilisateur et vous auriez l'erreur suivante l'or de l'envoie des paquets créé dans votre dépôt:

Could not find any key matching 'votre.clé@repo.votre-serveur.com'

Gardez les valeurs par défaut à chaque questions.
Seul les questions Real name: et Email address: sont importantes.
L'adresse email DOIT correspondre à celle que vous avez mis dans le fichier /srv/reprepro/conf/distributions.
Cette adresse sera visible dans les paquets.

Pour le moment n'entrez pas de passphrase. Ce n'est pas top pour la sécurité, mais je n'ai pas encore réussi à avoir reprepro fonctionnant avec une clé GPG avec une passphrase...

Une fois terminé vous devriez avoir à la fin quelque chose comme ca:

pub   2048R/55B0A66B 2014-01-27
      Key fingerprint = A335 3D06 888C 868A BE0C  9A93 2002 7088 44B9 A86B
uid                  Real name <adresse.email@votre-serveur.com>
sub   2048R/A47A9C27 2014-01-27

Il est important pour l'étape suivante que vous sachiez trouver l'ID de votre clé. Dans cet exemple l'ID est 55B0A66B. C'est la valeur apres le slash (/) de la première ligne.

Publication de la clé GPG

Lorsque les utilisateurs ajouterons votre serveur dans leur sources pour apt, il devront importer votre clé GPG (clé publique), donc il faut la mettre sur un serveur.

Sur votre serveur:

sudo gpg --keyserver keyserver.ubuntu.com --send-keys 55B0A66B
gpg: sending key 55B0A66B to hkp server keyserver.ubuntu.com

La clé est bien envoyée sur le serveur :-)

Nginx

Pour finir il faut configurer nginx (ou apache) pour donner un accès en HTTP à notre dépôt.

Créez le fichier de configuration avec ce contenu:

Puis redémarrez nginx.

Configurer apt pour utiliser votre serveur

Pour finir cette première partie, il ne reste plus qu'à configurer apt sur votre machine pour accéder à votre dépôt (oui vide pour le moment).

sudo add-apt-repository http://repository.votre-serveur.com/
sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 55B0A66B

Bien entendu vous remplacerez l'ID 55B0A66B par le votre ;-)

Maintenant si vous mettez à jour apt:

sudo apt-get update
[...]
W: Failed to fetch http://repository.votre-serveur.com/dists/saucy/main/binary-amd64/Packages  404  Not Found

Donc apt a bien contacté votre serveur, mais celui-ci n'a pas de paquet a installer (Et donc pas de fichier Packages).

Mon premier paquet

Maintenant que notre dépôt est pret il faut le remplir! :-)

Ce que nous voulons c'est avoir un comportement proche des PPA de launchpad.net, c'est à dire envoyer les sources et que le serveur compile pour différentes distributions et architectures.

Nous allons pouvoir faire ceci grâce à rebuildd.

Installation

Ici rien de compliqué. Sur votre serveur:

sudo apt-get install rebuildd

Configuration

Voici le cœur du sujet! :-)

/etc/default/rebuildd

Premièrement il faut authoriser l'exécution de rebuildd.
Modifiez le fichier /etc/default/rebuildd en changant ces paramètres:

START_REBUILDD=1
START_REBUILDD_HTTPD=1
PBUILDER_MIRROR=http://archive.ubuntu.com/ubuntu/
ARCHS="i386 amd64"
DISTS="precise quantal raring saucy"

START_REBUILDD authorise rebuildd de démarrer et START_REBUILDD_HTTPD authorise de démarrer l'interface web (je vous montre le résultat plus bas).

PBUILDER_MIRROR indique ou chercher les versions d'Ubuntu. Ici j'utilise le dépôt principal d'Ubuntu.

Pour finir ARCHS indique que nous voulons complier des paquets 32 et 64 bits et DISTS permet de préciser pour quelles versions d'Ubuntu nous voulons faire des paquets.

Vous remarquerez que nous avons déjà indiqué cette liste dans la configuration de reprepro. La raison est que rebuildd et reprepro sont deux applications différentes pouvant être utilisé indépendement.
(Peut-être une amélioration de cet article: Trouver un moyen de spécifier 1 seule fois les configurations identiques.)

/etc/pbuilderrc

Dans ce fichier nous allons définir une confguration qui sera utilisée par pbuilder l'or de la création des environnements. Par exemple nous allons ajouter le support des dépôts univers et multivers d'Ubuntu.

## Overrides /etc/pbuilderrc

# Default distribution
# DISTRIBUTION=saucy
COMPONENTS="main restricted universe multiverse"

# Repositories
MIRRORSITE=http://archive.ubuntu.com/ubuntu
#OTHERMIRROR="deb ${MIRRORSITE} ${DISTRIBUTION}-updates ${COMPONENTS}|deb ${MIRRORSITE} ${DISTRIBUTION}-security ${COMPONENTS}"

# For build results
BUILDRESULT=/var/cache/pbuilder/result

# Hooks for chroot environment
# HOOKDIR=/var/cache/pbuilder/hook.d

# Mount directories inside chroot environment
BINDMOUNTS=${BUILDRESULT}

# Bash prompt inside pbuilder
export debian_chroot="pbuild$$"

# For D70results hook
export LOCALREPO=${BUILDRESULT}

# Always include source package
DEBBUILDOPTS="-b"

Préparation des environnements de compilation

Pour pouvoir préparer des paquets pour différentes versions d'Ubuntu (et surtout différentes architectures), rebuildd utilise pbuilder.

Ce dernier créer des environments en créant un environnement émulant la version voulut.

rebuildd-init-build-system

Cette commande va créer les environnements définis grâce aux variables précédement définies dans /etc/default/rebuildd: ARCHS et DISTS.

Il va faire la combinaisons des 2 et va donc créer un environment 32 bits et 64 bits pour la version precise d'Ubuntu et ainsi de suite.

Donc dans un terminal:

sudo rebuildd-init-build-system

(Cette commande prendra plus ou moins de temps, dépendant des variables ARCHS et DISTS).

Si vous utilisez Debian

Si vous êtes sous Debian et que vous désirez faire des paquets pour Ubuntu, vous devriez avoir une erreur indiquant que la clé GPG pour le dépôt d'Ubuntu est inconnu.

Un paquet (http://packages.debian.org/jessie/all/ubuntu-archive-keyring/download) pour une trés ancienne version de Debian existait mais il n'est plus disponible. :-(

Une solution est de télécharger et d'installer manuellement ce paquet:

cd /tmp
wget http://ftp.us.debian.org/debian/pool/main/u/ubuntu-keyring/ubuntu-archive-keyring_2012.05.19-1_all.deb
sudo dkpg -i ubuntu-archive-keyring_2012.05.19-1_all.deb

Si vous voulez supporter Ubuntu saucy

Dans ce cas rebuildd-init-build-system va se terminer en erreur disant:

No such script: /usr/share/debootstrap/scripts/saucy

En jettant un oeil dans ce dossier on s'apercoit que par exemple le script raring est juste un lien vers le script gutsy.
Faisons la même chose:

cd /usr/share/debootstrap/scripts/
sudo ln -s gutsy saucy

Puis relancer rebuildd-init-build-system.

Initialiser rebuildd

Pour fonctionner, rebuildd utilise une base de données.
Pour initialiser cette base de données il suffit de lancer la commande:

sudo rebuildd init

Déclanchement de fabrication des paquets

Plus haut je disais que j'expliquais les lignes:

Log: logfile
--changes /srv/reprepro/bin/build_sources

Et bien c'est ici :-D

Ce qu'elles veulent dire c'est que le script /srv/reprepro/bin/build_sources sera exécuté dés qu'un fichier source sera ajouté ou supprimé du dépôt.
C'est exactement ce qu'il nous faut de facon à avoir un système entièrement automatique.

/srv/reprepro/bin/build_sources

Il nous faut donc créer ce script.

Son role est de créer un job rebuildd pour le fichier source ajouté.
Voici un exemple de script:

Ne pas oublier:

sudo chmod +x /srv/reprepro/bin/build_sources

En gros le script créer le job rebuildd que si c'est un ajout et si le fichier est un fichier source (finissant par _source.changes).

Info: rebuildd travail avec un système de queue. Le script va ajouter une entrée dans la queue de rebuildd, mais si le serveur de rebuildd n'est pas démarré, rien ne se passera.

/etc/rebuildd/rebuilddrc

Avant de démarrer rebuildd il faut mettre à jour le fichier de configuration /etc/rebuildd/rebuilddrc.

[build]

Premièrement il faut changer dists en remettant les versions que vous supportez:

dists = precise quantal raring saucy

TODO: Expliquer cette ligne.

source_cmd = /srv/reprepro/bin/get_sources ${d} ${p} ${v}

Pour gérer la signature automatique de vos paquets avec la clé GPG du dépôt il nous faut un autre script:

post_build_cmd = /srv/reprepro/bin/upload_binaries ${d} ${p} ${v} ${a}
[mail]

Afin de recevoir les emails des fabrications de paquets:

mailto = votre-adresse.email@fournisseur.fr

/srv/reprepro/bin/get_sources

TODO: Expliquer cette ligne.

Voici un exemple de script qui ...:

Ne pas oublier:

sudo chmod +x /srv/reprepro/bin/get_sources

/srv/reprepro/bin/upload_binaries

Voici un exemple de script qui utilise l'utilisateur debman pour signer le paquet:

Ne pas oublier:

sudo chmod +x /srv/reprepro/bin/upload_binaries

Démarrage des services rebuildd

Pour que les jobs rebuildd ajouté par le script build_sources soient exécuté il faut démarrer les services rebuildd.

Tout d'abord démarrons rebuildd:

sudo service rebuildd start

Puis démarrons l'interface web de rebuildd:

sudo service rebuildd-httpd start

Vous pouvez d'or et déjà aller sur cette interface web en utilisant votre navigateur web préféré et en allans sur le port 9998.

Vous devriez obtenir ceci:

Envoyer mon premier paquet

Il est temps d'envoyer quelquechose à empaqueté!

Pour ce faire nous utiliserons la commande dput.

Configuration

La configuration de dput consiste en la création d'un fichier .dput.cf sur votre machine de développement avec le contenu suivant:

[DEFAULT]
default_host_main = notspecified

[mon-serveur]
fqdn = repository.mon-serveur.com
login = ftpsecure
incoming = /incoming
method = ftp
hash = sha
allow_unsigned_uploads = 0
run_dinstall = 0

Pour suivre le principe de fonctionnement des PPA, j'utilise ici la methode ftp.
Un compte ftpsecure avec des acces limité est utilisé.

Importer sa clé GPG

Lorsque vous exécutez la commande debuild -S -sa vous signer avec votre clé GPG (sur votre machine de dévelopment cette fois) les fichiers.

Il faut donc que reprepro connaisse votre clé publique afin d'accepter uniquement les fichiers pour les clé qu'il connait (et rejeter tout autres envoie de n'importe qui).

Pour ce faire vous devez exporter votre clé public GPG et l'envoyer sur votre serveur depuis votre machine de développement:

gpg --armor --export votre-adresse-email > votre-adresse-email.asc
scp ./votre-adresse-email.asc root@votre-serveur:~/

Ensuite connectez-vous à votre serveur, la clé se trouve dans son dossier 'home' de root.
Importez la:

sudo gpg --import /root/votre-adresse-email.asc
sudo rm /root/votre-adresse-email.asc

Installer et configurer le service ftp

Il faut maintenant que le service ftp tourne sur votre serveur:

sudo apt-get install vsftpd
sudo adduser --home /srv/reprepro/ ftpsecure

Entrez un mot de passe qui sera à fournir à chaque envoie.

Maintenant changons quelques options dans /etc/vsftpd.conf:

listen=YES
anonymous_enable=NO
local_enable=YES
write_enable=YES
local_umask=022
nopriv_user=ftpsecure
chroot_local_user=YES

Et changez les droits de /srv/reprepro/:

sudo chmod 750 -R /srv/reprepro/
sudo chmod 755 -R /srv/reprepro/incoming
sudo chown ftpsecure:ftpsecure /srv/reprepro/incoming
sudo chmod 755 /srv/reprepro/

De cette facon le dossier 'home' de l'utilisateur ftpsecure est /srv/reprepro/ mais il ne peux accéder que dans /srv/reprepro/incoming.

Et un petit redémarrage de vsftp:

sudo service vsftpd restart

/etc/apt/sources.list

Ici nous allons mettre a jour le fichier /etc/apt/sources.list de votre serveur avec les dépôts que vous supportez vers votre propre serveur.

Cela vous semble bisard ? Je vous rassure c'est normal ! :-)
Allez, on s'accroche, car ca va pas être facile à comprendre.

Cette partie est importante car avant que pbuilder se lance pour fabriquer votre paquet, le script /srv/reprepro/bin/get_sources va être exécuté avec le paramètre -t <distribution ubuntu> afin de récuperer tout le contenue de votre propre dépôt, et donc avoir le fichier .tar.gz ainsi que \_source.changes dans l'environnement de pbuidler.

Sans cette partie pbuilder n'aurait rien a fabriquer.

Donc ajouter ces lignes pour chaque version d'Ubuntu que vous supportez:

# Sources for rebuildd
deb http://repository.mon-serveur.com saucy main
deb-src http://repository.mon-serveur.com saucy main

Donc selon l'exemple de cet article:

# Sources for rebuildd
deb http://repository.mon-serveur.com precise main
deb-src http://repository.mon-serveur.com precise main

deb http://repository.mon-serveur.com quantal main
deb-src http://repository.mon-serveur.com quantal main

deb http://repository.mon-serveur.com raring main
deb-src http://repository.mon-serveur.com raring main

deb http://repository.mon-serveur.com saucy main
deb-src http://repository.mon-serveur.com saucy main

Envoie

Dans le dossier de votre projet, apres avoir préparé le dossier debian/ et excécuté la commande debuild -S -sa vous devriez avoir un fichier finissant par _source.changes.

dput mon-serveur ./helloworld_1.0.0-0ubuntu1~amd64~saucy1_source.changes
[...]
Uploading to mon-serveur (via ftp to repository.mon-serveur.com):
ftpsecure@repository.mon-serveur.com password: 
  Uploading helloworld_1.0.0-0ubuntu1~amd64~saucy1.dsc: done.
  Uploading helloworld_1.0.0-0ubuntu1~amd64~saucy1.tar.gz: done.      
  Uploading helloworld_1.0.0-0ubuntu1~amd64~saucy1_source.changes: done.
Successfully uploaded packages.

Les fichiers seront copier dans votre dépôt, puis rappatrié pour pbuilder grâce a apt et pbuilder se lancera pour fabriquer votre paquet.
Pour finir votre paquet sera copié dans votre dépôt et donc disponible.

Démarrage de la fabrication des paquets

Maintenant que les fichiers sont sur votre serveur, a la bonne place, il ne reste plus qu'a lancer la fabrication:

sudo reprepro -V -b /srv/reprepro processincoming incoming

Cette commande va copier les sources au bonne endroit pour pbuilder puis créer un job pour rebuildd afin de fabriquer les paquets.
Une fois la commande terminé, si vous allez sur l'application web rebuildd vous verez le job:

Automatiser le démarrage

Pour éviter de devoir se connecter et lancer la commande a la main tout le temps, nous allons utiliser inotify (Module Linux pour écouter des évements du disque dur comme la création/modification/... de fichiers).

La solution que je vous propose est incron.

Tout d'abord installez le paquet sur votre serveur:

sudo apt-get install incron

Il faut autoriser l'utilisateur root en modifiant le fichier /etc/incron.allow et en ajoutant root.

Puis le configurer:

sudo incrontab -e

Ceci vous ouvre un fichier a modifier. Ajoutez cette ligne:

Puis tappez : et wq pour sauvegarder et quitter.

Des lor, lorsque des fichiers seront ajouté dans le dossier /srv/reprepro/incoming, le script reprepro_trigger.sh sera exécuté.

Donc il faut créer le script avec sudo nano /usr/local/bin/reprepro_trigger.sh:

Et ne pas oublier de le rendre exécutable:

sudo chmod +x /usr/local/bin/reprepro_trigger.sh