Aller au contenu

Configuration des clients

Configurer les machines pour installer des paquets depuis votre dépôt Repod.

Prérequis

  • Le serveur du dépôt Repod est démarré et accessible depuis la machine cliente
  • Au moins un paquet a été uploadé et publié avec succès
  • La clé publique GPG du dépôt est disponible (dans Paramètres → GPG)

Clients APT (Debian / Ubuntu)

Étape 1 — Importer la clé de signature GPG

Le client APT vérifie la signature du fichier InRelease du dépôt. Importer la clé de signature une fois par machine :

curl -fsSL http://VOTRE_HOTE:80/repos/dists/jammy/InRelease \
  | gpg --dearmor \
  | sudo tee /etc/apt/trusted.gpg.d/repod.gpg > /dev/null
  1. Ouvrir Paramètres → GPG dans l'interface web Repod
  2. Cliquer Copier la clé publique
  3. Sur la machine cliente :
    echo "COLLER_LA_CLE_ICI" | gpg --dearmor \
      | sudo tee /etc/apt/trusted.gpg.d/repod.gpg > /dev/null
    

Étape 2 — Ajouter la source APT

# Remplacer 'jammy' par le nom de code de votre distribution cible
echo "deb http://VOTRE_HOTE:80/repos jammy main" \
  | sudo tee /etc/apt/sources.list.d/repod.list

Étape 3 — Mettre à jour et installer

sudo apt update
sudo apt install monpaquet

Vérifier la configuration

# Vérifier que le dépôt est reconnu
apt-cache policy monpaquet
# Devrait afficher "http://VOTRE_HOTE:80/repos jammy/main" comme candidat

Plusieurs distributions

/etc/apt/sources.list.d/repod.list
# Paquets Ubuntu 22.04
deb http://VOTRE_HOTE:80/repos jammy main
# Paquets Ubuntu 24.04 (si vous maintenez des paquets séparés par version)
deb http://VOTRE_HOTE:80/repos noble main

Rôle Ansible

configure-repod.yml
---
- name: Configurer le dépôt APT Repod
  hosts: all
  become: true
  tasks:
    - name: Importer la clé GPG Repod
      ansible.builtin.get_url:
        url: "http://VOTRE_HOTE:80/repos/gpg.key"
        dest: /tmp/repod.asc

    - name: Convertir et installer la clé
      ansible.builtin.shell: |
        gpg --dearmor < /tmp/repod.asc > /etc/apt/trusted.gpg.d/repod.gpg

    - name: Ajouter la source APT
      ansible.builtin.apt_repository:
        repo: "deb http://VOTRE_HOTE:80/repos {{ ansible_distribution_release }} main"
        filename: repod
        state: present
        update_cache: yes

Clients RPM — DNF (AlmaLinux / RHEL / Rocky / Fedora)

Étape 1 — Importer la clé de signature GPG

sudo rpm --import http://VOTRE_HOTE:80/repos/gpg.key

Vérifier que la clé a bien été importée :

rpm -q gpg-pubkey --qf '%{name}-%{version}-%{release} --> %{summary}\n'

Étape 2 — Créer le fichier de dépôt

/etc/yum.repos.d/repod.repo
[repod]
name=Repod Private Repository
baseurl=http://VOTRE_HOTE:80/repos/almalinux9/x86_64/
enabled=1
gpgcheck=1
gpgkey=http://VOTRE_HOTE:80/repos/gpg.key
repo_gpgcheck=0
metadata_expire=300

repo_gpgcheck=0

Laisser repo_gpgcheck=0 sauf si vous avez signé repomd.xml avec une clé que DNF peut vérifier séparément. Le gpgcheck=1 au niveau des paquets suffit pour la plupart des déploiements.

Étape 3 — Installer des paquets

# Rafraîchir les métadonnées
sudo dnf makecache --repo=repod

# Installer un paquet
sudo dnf install monpaquet

# Lister les paquets disponibles depuis Repod uniquement
sudo dnf list available --repo=repod

baseurl par distribution

Distribution baseurl
AlmaLinux 8 http://VOTRE_HOTE:80/repos/almalinux8/x86_64/
AlmaLinux 9 http://VOTRE_HOTE:80/repos/almalinux9/x86_64/
Rocky Linux 8 http://VOTRE_HOTE:80/repos/rocky8/x86_64/
Rocky Linux 9 http://VOTRE_HOTE:80/repos/rocky9/x86_64/
CentOS Stream 9 http://VOTRE_HOTE:80/repos/centos-stream9/x86_64/
Fedora 42 http://VOTRE_HOTE:80/repos/fedora/x86_64/
openSUSE Leap 15.6 http://VOTRE_HOTE:80/repos/opensuse-leap-15.6/x86_64/

Rôle Ansible (DNF)

configure-repod-rpm.yml
---
- name: Configurer le dépôt RPM Repod
  hosts: all
  become: true
  tasks:
    - name: Importer la clé GPG Repod
      ansible.builtin.rpm_key:
        key: "http://VOTRE_HOTE:80/repos/gpg.key"
        state: present

    - name: Ajouter le dépôt Repod
      ansible.builtin.yum_repository:
        name: repod
        description: Repod Private Repository
        baseurl: "http://VOTRE_HOTE:80/repos/{{ ansible_distribution | lower }}{{ ansible_distribution_major_version }}/x86_64/"
        enabled: yes
        gpgcheck: yes
        gpgkey: "http://VOTRE_HOTE:80/repos/gpg.key"
        state: present

Clients RPM — Zypper (openSUSE Leap)

Étape 1 — Ajouter le dépôt

sudo zypper addrepo \
  --name "Repod Private Repository" \
  --gpgcheck \
  http://VOTRE_HOTE:80/repos/opensuse-leap-15.6/x86_64/ \
  repod

Étape 2 — Importer la clé GPG

sudo rpm --import http://VOTRE_HOTE:80/repos/gpg.key

Étape 3 — Installer des paquets

sudo zypper refresh repod
sudo zypper install monpaquet

Clients Maven (mvn / Gradle)

Le support Maven de Repod (V1) héberge des artefacts de release privés — il ne fait pas office de proxy vers Maven Central. Chaque déploiement (PUT) nécessite une authentification HTTP Basic ; les lectures (GET) sont ouvertes, la même limitation connue déjà documentée pour les téléchargements de paquets APT/RPM/APK. Les versions SNAPSHOT ne sont pas encore prises en charge — ne déployez que des versions de release.

Étape 1 — Configurer les identifiants dans settings.xml

Le <server><id> doit correspondre à l'<id> utilisé dans le bloc <distributionManagement>/<repository> de votre POM ci-dessous. Le mot de passe peut être votre mot de passe de compte Repod ou, pour la CI/CD, un token API (repod_...).

~/.m2/settings.xml
<settings>
  <servers>
    <server>
      <id>repod-releases</id>
      <username>VOTRE_NOM_UTILISATEUR</username>
      <password>VOTRE_MOT_DE_PASSE_OU_TOKEN_API</password>
    </server>
  </servers>
</settings>

Dépôts en HTTP simple

Maven bloque par défaut les dépôts externes en http:// depuis la version 3.8.1. Si votre instance Repod n'est pas encore derrière TLS (voir docker-compose.tls.yml), ajoutez une surcharge de miroir pour débloquer spécifiquement l'identifiant de votre dépôt :

~/.m2/settings.xml
<mirrors>
  <mirror>
    <id>maven-default-http-blocker</id>
    <mirrorOf>external:http:*,!repod-releases</mirrorOf>
    <name>Autoriser repod-releases en HTTP simple (dev uniquement)</name>
    <url>http://0.0.0.0/</url>
    <blocked>true</blocked>
  </mirror>
</mirrors>

Étape 2 — Publier (mvn deploy)

pom.xml
<project>
  ...
  <distributionManagement>
    <repository>
      <id>repod-releases</id>
      <url>http://VOTRE_HOTE:8000/api/v1/maven/releases</url>
    </repository>
  </distributionManagement>
</project>

releases est le nom du dépôt Maven cible — il est créé automatiquement au premier déploiement réussi (aucun pré-enregistrement nécessaire), sur le même modèle de dépôt dynamique que le registre OCI. Ensuite :

mvn deploy

Les sommes de contrôle (.sha1/.md5) et maven-metadata.xml sont toujours générées côté serveur à partir de l'artefact réellement stocké — tout ce que le client Maven envoie pour ces fichiers est accepté mais ignoré, jamais utilisé tel quel.

Étape 3 — Résoudre (mvn dependency:get / dépendances classiques)

pom.xml ou settings.xml <profile>
<repositories>
  <repository>
    <id>repod-releases</id>
    <url>http://VOTRE_HOTE:8000/api/v1/maven/releases</url>
  </repository>
</repositories>
mvn dependency:get -Dartifact=com.acme:widget:1.0.0

Gradle

build.gradle
repositories {
    maven {
        url "http://VOTRE_HOTE:8000/api/v1/maven/releases"
        credentials {
            username = project.findProperty("repodUser") ?: ""
            password = project.findProperty("repodToken") ?: ""
        }
    }
}
publishing {
    repositories {
        maven {
            url "http://VOTRE_HOTE:8000/api/v1/maven/releases"
            credentials {
                username = project.findProperty("repodUser") ?: ""
                password = project.findProperty("repodToken") ?: ""
            }
        }
    }
}

Contrôle d'accès

Par défaut, tout nom de dépôt est ouvert au mvn deploy pour les comptes uploader/maintainer/admin. Pour restreindre un dépôt spécifique à certains rôles ou groupes, utiliser POST /api/v1/maven/repositories/{name}/access (admin uniquement) — le même modèle RBAC que distribution_access/oci_repository_access : aucune ligne signifie ouvert, l'admin passe toujours outre, et un refus en lecture renvoie 404 plutôt que 403 pour éviter de révéler l'existence d'un dépôt restreint.


Clients PyPI (pip / twine)

Le support PyPI de Repod (V1) héberge des wheels/sdists privés — il ne fait pas office de proxy vers PyPI. Il implémente l'API Simple Repository (PEP 503) en HTML pour pip install/pip download, ainsi que le protocole d'upload « legacy » (POST .../legacy/) pour twine upload — le même protocole utilisé par upload.pypi.org sur le vrai PyPI, donc les outils standards fonctionnent sans modification. Contrairement à Maven, les lectures (pages de l'API Simple et téléchargements de fichiers) sont elles aussi soumises au RBAC lorsqu'un index de dépôt est restreint — voir « Contrôle d'accès » ci-dessous.

Étape 1 — Installer (pip install)

pip install --index-url http://VOTRE_UTILISATEUR:VOTRE_MOT_DE_PASSE_OU_TOKEN@VOTRE_HOTE:8000/api/v1/pypi/private/simple/ monpaquet

Ou en le rendant persistant dans pip.conf/pip.ini :

~/.pip/pip.conf (Linux) ou %APPDATA%\pip\pip.ini (Windows)
[global]
index-url = http://VOTRE_UTILISATEUR:VOTRE_MOT_DE_PASSE_OU_TOKEN@VOTRE_HOTE:8000/api/v1/pypi/private/simple/

private est le nom de l'index PyPI cible — comme les dépôts Maven et OCI, il est créé automatiquement au premier upload réussi (aucun pré- enregistrement nécessaire). Si l'index n'a aucune restriction RBAC, les identifiants dans l'URL sont optionnels — un simple pip install --index-url http://VOTRE_HOTE:8000/api/v1/pypi/private/simple/ monpaquet fonctionne aussi.

Combiner avec le PyPI public

Utiliser --extra-index-url au lieu de --index-url pour se rabattre sur pypi.org pour les paquets non hébergés en privé :

pip install --extra-index-url http://VOTRE_HOTE:8000/api/v1/pypi/private/simple/ monpaquet

Étape 2 — Publier (twine upload)

pip install twine
twine upload --repository-url http://VOTRE_HOTE:8000/api/v1/pypi/private/legacy/ \
  -u VOTRE_NOM_UTILISATEUR -p VOTRE_MOT_DE_PASSE_OU_TOKEN_API \
  dist/*

Ou via .pypirc :

~/.pypirc
[distutils]
index-servers = repod-private

[repod-private]
repository = http://VOTRE_HOTE:8000/api/v1/pypi/private/legacy/
username = VOTRE_NOM_UTILISATEUR
password = VOTRE_MOT_DE_PASSE_OU_TOKEN_API
twine upload --repository repod-private dist/*

Les sommes de contrôle sont toujours calculées côté serveur à partir du fichier uploadé — le sha256_digest envoyé par twine est accepté mais non utilisé tel quel.

Contrôle d'accès

Par défaut, tout nom d'index est ouvert en publication pour les comptes uploader/maintainer/admin, et ouvert en lecture pour tout le monde. Pour restreindre un index spécifique (lectures et écritures) à certains rôles ou groupes, utiliser POST /api/v1/pypi/repositories/{name}/access (admin uniquement) — même modèle RBAC que distribution_access/maven_repository_access : aucune ligne signifie ouvert, l'admin passe toujours outre, un refus renvoie 404 plutôt que 403 pour éviter de révéler l'existence d'un index restreint. Un index restreint rejette les pip install/pip download non authentifiés — fournir les identifiants dans --index-url comme montré ci-dessus.


Clients npm (npm / yarn)

Le support npm de Repod (V1) héberge des paquets privés — il ne fait pas office de proxy vers npmjs.org. Il implémente le vrai protocole du registre npm (packument via GET /{package}, publication via un simple PUT /{package} avec le tarball encodé en base64 dans le corps de la requête — la même forme que celle envoyée par npm publish à n'importe quel registre), donc les outils standards fonctionnent sans modification. Comme pour PyPI, les lectures (packument + téléchargement du tarball) sont elles aussi soumises au RBAC lorsqu'un namespace est restreint.

Étape 1 — Obtenir un token

Générer un token API Repod (Paramètres → Tokens API, ou demander à un admin) — le flux interactif npm login n'est pas pris en charge en V1 ; coller directement un token pré-généré dans .npmrc à la place (l'approche standard pour les registres privés — GitHub Packages, Artifactory et Verdaccio avec authentification par token fonctionnent tous de la même manière).

Étape 2 — Configurer .npmrc

~/.npmrc ou ./.npmrc (local au projet)
registry=http://VOTRE_HOTE:8000/api/v1/npm/private/
//VOTRE_HOTE:8000/api/v1/npm/private/:_authToken=VOTRE_TOKEN_API

private est le namespace npm cible — comme pour Maven/PyPI, il est créé automatiquement à la première publication réussie (aucun pré-enregistrement nécessaire). Si le namespace n'a aucune restriction RBAC, la ligne _authToken n'est nécessaire que pour npm publish (les lectures fonctionnent sans elle).

Pour restreindre une organisation spécifique à un namespace privé tout en gardant le reste sur le registre npm public :

.npmrc
@monorg:registry=http://VOTRE_HOTE:8000/api/v1/npm/private/
//VOTRE_HOTE:8000/api/v1/npm/private/:_authToken=VOTRE_TOKEN_API

Étape 3 — Installer / publier

npm install monpaquet        # se résout via le registre configuré
npm publish                  # depuis le répertoire du paquet

Contrôle d'accès

Par défaut, tout namespace est ouvert en publication pour les comptes uploader/maintainer/admin, et ouvert en lecture pour tout le monde. Pour restreindre un namespace (lectures et écritures) à certains rôles ou groupes, utiliser POST /api/v1/npm/repositories/{name}/access (admin uniquement) — même modèle RBAC que maven_repository_access/pypi_repository_access : aucune ligne signifie ouvert, l'admin passe toujours outre, un refus renvoie 404 plutôt que 403.

Limitations connues en V1

  • Seul le dist-tag latest est pris en charge — il pointe vers la version publiée le plus récemment (le comportement réel par défaut de npm pour npm publish sans --tag), pas nécessairement la version au semver le plus élevé.
  • Les champs dependencies/scripts/engines et autres champs de package.json ne sont pas conservés dans le packument — suffisant pour npm install <pkg>/npm publish d'un paquet autonome, pas pour résoudre un paquet qui dépend lui-même d'autres paquets npm.
  • npm unpublish et npm deprecate ne sont pas implémentés.

Accès authentifié (tokens API)

Si votre instance Repod nécessite une authentification pour télécharger des paquets (ce n'est pas le cas par défaut avec le Nginx du dépôt, mais c'est possible via des règles de reverse proxy), utiliser l'authentification HTTP Basic ou un token dans l'en-tête de requête.

/etc/apt/auth.conf.d/repod.conf
machine VOTRE_HOTE:80
login token
password VOTRE_TOKEN_API

Ajouter les identifiants au fichier .repo :

/etc/yum.repos.d/repod.repo
[repod]
name=Repod Private Repository
baseurl=http://VOTRE_HOTE:80/repos/almalinux9/x86_64/
enabled=1
gpgcheck=1
gpgkey=http://VOTRE_HOTE:80/repos/gpg.key
username=token
password=VOTRE_TOKEN_API


Configuration CI/CD

.github/workflows/install.yml
- name: Configurer le dépôt Repod (APT)
  run: |
    curl -fsSL http://${{ secrets.REPOD_HOST }}/repos/dists/jammy/InRelease \
      | gpg --dearmor \
      | sudo tee /etc/apt/trusted.gpg.d/repod.gpg > /dev/null
    echo "deb http://${{ secrets.REPOD_HOST }}/repos jammy main" \
      | sudo tee /etc/apt/sources.list.d/repod.list
    sudo apt update
    sudo apt install monpaquet
.gitlab-ci.yml
install:
  before_script:
    - |
      curl -fsSL http://${REPOD_HOST}/repos/dists/jammy/InRelease \
        | gpg --dearmor \
        | tee /etc/apt/trusted.gpg.d/repod.gpg > /dev/null
      echo "deb http://${REPOD_HOST}/repos jammy main" \
        > /etc/apt/sources.list.d/repod.list
      apt-get update -qq
  script:
    - apt-get install -y monpaquet

Résolution de problèmes

Problème Cause probable Solution
NO_PUBKEY lors de apt update Clé GPG non importée ou expirée Ré-exécuter la commande d'import de clé
404 Not Found lors de apt update Nom de code de distribution incorrect Vérifier le codename dans sources.list
GPG key retrieval failed sur dnf install Clé non importée Exécuter rpm --import ...
Version de paquet obsolète Cache de métadonnées trop long dnf makecache ou apt update
HTTPS requis par la politique Politique interne Ajouter un reverse proxy avec TLS ; voir le guide reverse proxy

Guide de dépannage complet →