Guide d'installation en production — APT Repo Manager¶
Ce guide couvre l'installation complète d'APT Repo Manager dans un environnement de production sur un serveur Linux (Debian/Ubuntu). Suivez chaque étape dans l'ordre.
Table des matières¶
- Prérequis système
- Récupération du projet
- Configuration
- Premier démarrage
- Configuration GPG
- Changement du mot de passe admin
- Vérification du bon fonctionnement
- Configuration du pare-feu
- Sauvegarde automatique
- Mise à jour de l'application
- Résolution des problèmes courants
1. Prérequis système¶
Système d'exploitation¶
- Debian 11/12 ou Ubuntu 22.04/24.04 LTS (recommandé)
- Accès root ou sudo
Logiciels requis¶
| Logiciel | Version minimale | Vérification |
|---|---|---|
| Docker Engine | 24.0 | docker --version |
| Docker Compose | 2.20 (plugin) | docker compose version |
| Git | 2.x | git --version |
| OpenSSL | 1.1+ | openssl version |
Important : Utilisez le plugin Docker Compose v2 (
docker compose) et non l'ancienne commandedocker-compose.
Installation de Docker (si absent)¶
# Supprimer d'éventuelles anciennes versions
sudo apt-get remove -y docker docker-engine docker.io containerd runc
# Installer les dépendances
sudo apt-get update
sudo apt-get install -y ca-certificates curl gnupg lsb-release
# Ajouter le dépôt officiel Docker
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg \
| sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
sudo chmod a+r /etc/apt/keyrings/docker.gpg
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] \
https://download.docker.com/linux/ubuntu \
$(. /etc/os-release && echo "$VERSION_CODENAME") stable" \
| sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt-get update
sudo apt-get install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
# Ajouter l'utilisateur courant au groupe docker
sudo usermod -aG docker $USER
newgrp docker
Ressources matérielles minimales¶
| Ressource | Minimum | Recommandé |
|---|---|---|
| CPU | 2 vCPU | 4 vCPU |
| RAM | 2 Go | 4 Go |
| Disque | 20 Go | 100 Go+ |
| Réseau | 100 Mb/s | 1 Gb/s |
Le disque doit être suffisant pour stocker les paquets
.debdansrepos/pool/. Prévoyez de l'espace selon le volume de paquets attendu.
Ports réseau requis¶
| Port | Service | Exposition |
|---|---|---|
| 80 | Dépôt APT | Publique (clients) |
| 3003 | Interface web | Publique ou VPN |
| 8000 | API backend | Reverse proxy TLS |
2. Récupération du projet¶
Cloner le dépôt¶
# Répertoire d'installation recommandé
sudo mkdir -p /opt/repod
sudo chown $USER:$USER /opt/repod
cd /opt/repod
git clone https://github.com/votre-organisation/repod.git .
Si vous déployez depuis une archive plutôt que depuis Git :
Vérifier la structure du projet¶
ls /opt/repod
# Attendu : backend/ frontend/ repos/ docker-compose.yaml .env.example backend.env.example backup.sh
3. Configuration¶
3.1 Fichier .env (variables frontend et ports)¶
Éditez .env avec l'URL publique réelle de votre serveur :
Contenu type — remplacez repo.example.com par votre domaine ou adresse IP :
PUBLIC_URL=https://repo.example.com:3003
REACT_APP_API_URL=https://repo.example.com:8000
REACT_APP_REPO_URL=https://repo.example.com:80
FRONTEND_PORT=3003
APP_VERSION=v2.0.0
PUBLIC_URLetREACT_APP_API_URLdoivent correspondre aux URLs réellement accessibles par les navigateurs des utilisateurs.
3.2 Fichier backend.env (secrets et authentification)¶
Générer la clé secrète JWT¶
Copiez la valeur produite, elle sera utilisée comme JWT_SECRET_KEY.
Générer le hash bcrypt du mot de passe admin¶
docker run --rm python:3.10-slim python3 -c \
"from passlib.context import CryptContext; \
print(CryptContext(schemes=['bcrypt']).hash('VotreMotDePasse!'))"
Remplacez VotreMotDePasse! par un mot de passe respectant la politique :
- Minimum 8 caractères
- Au moins une majuscule
- Au moins un chiffre ou caractère spécial
Attention : Dans
backend.env, si le hash bcrypt contient le caractère$, chaque$doit être doublé en$$. Exemple :
Contenu type de backend.env¶
JWT_SECRET_KEY=<valeur générée par openssl rand -hex 32>
JWT_EXPIRE_MINUTES=60
ADMIN_USERNAME=admin
ADMIN_PASSWORD_HASH=$$2b$$12$$<reste du hash bcrypt>
CORS_ORIGINS=https://repo.example.com:3003
AUTH_RATELIMIT_PER_MINUTE=10
JWT_SECRET_KEYest obligatoire en production. L'application refuse de démarrer si la valeur par défaut est détectée.
3.3 Sécuriser les fichiers de configuration¶
3.4 Créer la structure des volumes¶
mkdir -p /opt/repod/repos/{audit,auth,clamav-db,gnupg,grype-db,imports,logs,manifests,package-index,pool,security,staging/incoming,staging/quarantine}
Description des répertoires :
| Répertoire | Contenu |
|---|---|
audit/ |
Journaux d'audit JSONL (append-only) |
auth/ |
Base SQLite des utilisateurs + tokens de reset |
clamav-db/ |
Définitions antivirus ClamAV |
gnupg/ |
Trousseau GPG (partagé entre services) |
grype-db/ |
Cache base de données CVE Grype |
imports/ |
Cache temporaire des imports |
logs/ |
Journaux de téléchargements Nginx |
manifests/ |
Manifestes JSON des paquets |
package-index/ |
Index APT SQLite |
pool/ |
Fichiers .deb |
security/ |
Décisions CVE et tokens API JSON |
staging/ |
Zone de staging (upload et quarantaine) |
4. Premier démarrage¶
4.1 Construire et démarrer les services¶
Docker va télécharger et construire les images puis démarrer trois conteneurs :
| Conteneur | Rôle | Port |
|---|---|---|
frontend-ui |
Interface web React | 3003 |
backend-api |
API FastAPI + logique métier | 8000 |
depot-apt |
Serveur APT Nginx | 80 |
4.2 Vérifier que les conteneurs sont en cours d'exécution¶
Tous les services doivent afficher l'état Up ou running.
4.3 Surveiller les logs au démarrage¶
# Logs de l'API backend
docker logs backend-api -f
# Logs du frontend
docker logs frontend-ui -f
# Logs du serveur APT
docker logs depot-apt -f
Attendez que le backend affiche quelque chose de similaire à :
4.4 Vérifier le health check de l'API¶
Réponse attendue :
5. Configuration GPG¶
Le dépôt APT doit être signé avec une clé GPG pour que les clients apt acceptent les paquets.
Option A : Via l'interface web (recommandé)¶
- Ouvrez
https://repo.example.com:3003dans un navigateur - Connectez-vous avec les identifiants admin configurés
- Allez dans Paramètres > GPG
- Cliquez sur Générer une clé GPG
- Renseignez le nom réel et l'adresse e-mail
- Cliquez sur Générer
Option B : Via la ligne de commande¶
docker exec depot-apt gpg --homedir /repos/gnupg --no-default-keyring \
--keyring /repos/gnupg/pubring.kbx --batch --gen-key <<EOF
%no-protection
Key-Type: RSA
Key-Length: 4096
Name-Real: repod APT Repository
Name-Email: repod@example.com
Expire-Date: 2y
%commit
EOF
Adaptez Name-Real et Name-Email à votre organisation.
Exporter la clé publique GPG¶
La clé publique doit être distribuée aux clients pour qu'ils puissent vérifier les signatures :
# Exporter la clé publique depuis le conteneur
docker exec depot-apt gpg --homedir /repos/gnupg \
--armor --export repod@example.com > /opt/repod/repos/pubkey.asc
# Vérifier l'export
cat /opt/repod/repos/pubkey.asc
Configuration côté client APT¶
Les machines clientes doivent importer la clé et configurer le dépôt :
# Sur chaque machine cliente
curl -fsSL https://repo.example.com/pubkey.asc | sudo gpg --dearmor \
-o /etc/apt/keyrings/repod.gpg
echo "deb [signed-by=/etc/apt/keyrings/repod.gpg] \
http://repo.example.com/ stable main" \
| sudo tee /etc/apt/sources.list.d/repod.list
sudo apt-get update
6. Changement du mot de passe admin¶
Il est fortement recommandé de changer le mot de passe admin dès la première connexion via l'interface web.
Via l'interface web¶
- Connectez-vous avec le mot de passe configuré dans
backend.env - Allez dans Profil > Changer le mot de passe
- Saisissez l'ancien mot de passe puis le nouveau (et sa confirmation)
- Cliquez sur Enregistrer
Via l'API¶
# Récupérer un token JWT
TOKEN=$(curl -s -X POST http://localhost:8000/auth/login \
-H "Content-Type: application/json" \
-d '{"username":"admin","password":"AncienMotDePasse!"}' \
| python3 -c "import sys,json; print(json.load(sys.stdin)['access_token'])")
# Changer le mot de passe
curl -s -X POST http://localhost:8000/auth/change-password \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"old_password":"AncienMotDePasse!","new_password":"NouveauMotDePasse!"}'
7. Vérification du bon fonctionnement¶
Utilisez cette liste de contrôle après l'installation initiale.
Checklist de vérification¶
# 1. Tous les conteneurs sont en cours d'exécution
docker compose ps
# 2. Health check de l'API
curl -s http://localhost:8000/health/live | python3 -m json.tool
# 3. Interface web accessible
curl -s -o /dev/null -w "%{http_code}" http://localhost:3003
# Attendu : 200
# 4. Serveur APT accessible
curl -s -o /dev/null -w "%{http_code}" http://localhost:80
# Attendu : 200 ou 301
# 5. Swagger UI désactivé en production (doit retourner 404)
curl -s -o /dev/null -w "%{http_code}" http://localhost:8000/docs
# Attendu : 404
# 6. Connexion admin fonctionnelle
curl -s -X POST http://localhost:8000/auth/login \
-H "Content-Type: application/json" \
-d '{"username":"admin","password":"VotreMotDePasse!"}'
# Attendu : réponse JSON avec access_token
# 7. ClamAV opérationnel
docker exec backend-api curl -s http://localhost:3310
# Attendu : réponse PONG ou signature ClamAV
# 8. GPG configuré
docker exec depot-apt gpg --homedir /repos/gnupg --list-keys
# Attendu : au moins une clé listée
Vérification de la signature du dépôt APT¶
# Vérifier que le Release est signé
curl -s http://localhost/dists/stable/InRelease | head -5
# Attendu : bloc PGP SIGNED MESSAGE
Vérification des logs d'audit¶
# Les actions admin doivent être tracées
ls -la /opt/repod/repos/audit/
cat /opt/repod/repos/audit/$(date +%Y-%m-%d).jsonl | head -20
8. Configuration du pare-feu¶
Avec UFW (recommandé sur Ubuntu)¶
# Activer UFW si ce n'est pas déjà fait
sudo ufw enable
# Autoriser SSH (ne pas s'oublier !)
sudo ufw allow 22/tcp
# Interface web APT Repo Manager
sudo ufw allow 3003/tcp
# Dépôt APT (clients apt)
sudo ufw allow 80/tcp
# Port 8000 (backend API) : NE PAS exposer directement
# Utilisez un reverse proxy TLS — voir docs/REVERSE_PROXY.md
# Vérifier les règles
sudo ufw status numbered
Note de sécurité : Le port 8000 (API backend) ne doit pas être exposé directement sur Internet. Placez-le derrière un reverse proxy (Nginx, Caddy, Traefik) avec TLS. Consultez
docs/REVERSE_PROXY.mdpour la configuration TLS.
Avec iptables¶
# Autoriser le trafic entrant sur le port 3003 (UI)
sudo iptables -A INPUT -p tcp --dport 3003 -j ACCEPT
# Autoriser le trafic entrant sur le port 80 (APT)
sudo iptables -A INPUT -p tcp --dport 80 -j ACCEPT
# Sauvegarder les règles
sudo apt-get install -y iptables-persistent
sudo netfilter-persistent save
9. Sauvegarde automatique¶
Sauvegarde manuelle¶
Le script sauvegarde le répertoire repos/ et les fichiers de configuration.
Configurer la rétention¶
Planification automatique avec cron¶
Ajoutez la ligne suivante pour une sauvegarde quotidienne à 3h du matin :
Vérifier les sauvegardes¶
# Lister les sauvegardes existantes
ls -lh /opt/repod/backups/
# Vérifier le journal des sauvegardes
tail -50 /var/log/repod-backup.log
Sauvegarde des secrets¶
Les fichiers suivants doivent être sauvegardés séparément dans un coffre-fort sécurisé :
# Fichiers critiques à sauvegarder hors du serveur
/opt/repod/.env
/opt/repod/backend.env
/opt/repod/repos/gnupg/ # Clé GPG privée
/opt/repod/repos/auth/ # Base des utilisateurs
Attention : La perte de la clé GPG privée (
repos/gnupg/) rend impossibles les futures signatures du dépôt APT. Sauvegardez-la de manière sécurisée.
10. Mise à jour de l'application¶
Procédure de mise à jour standard¶
cd /opt/repod
# 1. Sauvegarder avant la mise à jour
./backup.sh
# 2. Récupérer les nouvelles versions
git fetch origin
git pull origin main
# 3. Arrêter les services
docker compose -f docker-compose.yaml down
# 4. Reconstruire les images avec la nouvelle version
docker compose -f docker-compose.yaml build --no-cache
# 5. Redémarrer les services
docker compose -f docker-compose.yaml up -d
# 6. Vérifier le bon démarrage
docker compose ps
curl http://localhost:8000/health/live
Mise à jour de l'image Docker uniquement (sans rebuild)¶
cd /opt/repod
./backup.sh
docker compose -f docker-compose.yaml pull
docker compose -f docker-compose.yaml up -d
Vérifier la version déployée¶
Rollback en cas de problème¶
cd /opt/repod
# Revenir à la version précédente dans git
git log --oneline -10
git checkout <commit-précédent>
# Redémarrer avec la version précédente
docker compose -f docker-compose.yaml down
docker compose -f docker-compose.yaml up -d --build
11. Résolution des problèmes courants¶
Le conteneur backend-api ne démarre pas¶
Symptôme : docker compose ps affiche Exited pour backend-api.
Causes fréquentes :
JWT_SECRET_KEYnon défini ou utilisant la valeur par défaut dansbackend.env- Solution : générez une clé avec
openssl rand -hex 32et relancez $non doublé en$$dans le hash bcrypt debackend.env- Solution : éditez
backend.envet doublez tous les$du hash - Erreur de syntaxe dans
backend.env - Solution : vérifiez qu'il n'y a pas d'espaces autour des
=
L'interface web affiche une erreur de connexion à l'API¶
Symptôme : Le frontend charge mais affiche une erreur lors de la connexion.
# Vérifier que le backend répond
curl http://localhost:8000/health/live
# Vérifier les CORS
docker logs backend-api --tail 20 | grep -i cors
Cause fréquente : CORS_ORIGINS dans backend.env ne correspond pas exactement à PUBLIC_URL dans .env (protocole, port, domaine).
Les clients APT rejettent le dépôt (erreur de signature)¶
Symptôme : apt update échoue avec The following signatures couldn't be verified.
# Vérifier que la clé GPG est configurée
docker exec depot-apt gpg --homedir /repos/gnupg --list-keys
# Vérifier que le Release est signé
curl http://localhost/dists/stable/InRelease | head -3
Solution : Si aucune clé n'est listée, générez une clé GPG (voir section 5) puis re-publiez le dépôt via l'interface web.
ClamAV ne se met pas à jour¶
Symptôme : Avertissements dans les logs concernant les définitions ClamAV obsolètes.
# Mettre à jour manuellement les définitions
docker exec backend-api freshclam
# Vérifier le volume clamav-db
ls -la /opt/repod/repos/clamav-db/
L'espace disque est insuffisant¶
# Vérifier l'espace disponible
df -h /opt/repod/
# Lister les plus gros paquets
du -sh /opt/repod/repos/pool/* | sort -rh | head -20
# Nettoyer les paquets en quarantaine
ls /opt/repod/repos/staging/quarantine/
# rm -f /opt/repod/repos/staging/quarantine/* # à faire manuellement après vérification
Accès refusé sur le port 3003 ou 80¶
# Vérifier les règles de pare-feu
sudo ufw status
# Vérifier que Docker écoute bien sur les ports
ss -tlnp | grep -E '3003|8000|:80'
Réinitialiser le mot de passe admin¶
Si le mot de passe admin est perdu :
# Générer un nouveau hash bcrypt
docker run --rm python:3.10-slim python3 -c \
"from passlib.context import CryptContext; \
print(CryptContext(schemes=['bcrypt']).hash('NouveauMotDePasse!'))"
# Mettre à jour backend.env avec le nouveau hash (doubler les $)
nano /opt/repod/backend.env
# Redémarrer le backend pour prendre en compte
docker compose restart backend-api
Consulter tous les logs en temps réel¶
# Tous les services en même temps
docker compose logs -f
# Un seul service
docker logs backend-api -f
docker logs frontend-ui -f
docker logs depot-apt -f
Annexe : Commandes de référence rapide¶
# Démarrer en production
docker compose -f docker-compose.yaml up -d
# Arrêter tous les services
docker compose -f docker-compose.yaml down
# Redémarrer un service spécifique
docker compose restart backend-api
# Voir l'état des services
docker compose ps
# Health check
curl http://localhost:8000/health/live
# Sauvegarder
cd /opt/repod && ./backup.sh
# Voir les logs
docker logs backend-api -f
docker logs frontend-ui -f
docker logs depot-apt -f
# Accéder au shell d'un conteneur
docker exec -it backend-api bash
docker exec -it depot-apt bash
Guide valable pour APT Repo Manager v2.0.0 — Dernière mise à jour : mai 2026