Organigramme d'installation
Les outils
Conteneur proxy : Voir la page
- Création du conteneur
- Installation et configuration de nginx
- Installation de certbot pour let's encrypt
- Voir pour installer des outils de sécurité (fail2ban,...)
Conteneur Mariadb : Voir la page
- Création du conteneur
- Installation de mariadb
- Configuration
- Création d'un utilisateur
Conteneur PhpMyadmin : Voir la page
- Création du conteneur
- Installation d'apache2 et de phpmyadmin
- Configuration d'apache2 et de phpmyadmin
Les applis
Conteneur tables : Voir la page
(Cf tables sur alpine léger & pmb sur alpine léger pour apache2
Conteneur pmb : Voir la page
(cf pmb sur alpine léger (historique dans pmb sur alpine lourd)
Conteneur wiki : Cf wiki (mediawiki) sur alpine léger
- Création d'un utilisateur et d'une base de donnée vide pour le wiki
- Transfert de la base de données
- Création du conteneur
- Installation du serveur web
- Installation de la nouvelle version de mediawiki
- Initialisation de l'application
- Modification de LocalSettings.php
- Récupération du contenu sur l'ancien serveur et transfert des données
- Corrections
Conteneur wp : Voir la page
(cf wordpress sur alpine léger mais sauter à la fin. Mariadb et phpmyadmin dans d'autres conteneurs...)
Stockage et sauvegardes
création d'un volume pour les sauvegardes :
# lxc storage volume create default sauvegarde-lxc size=50GB
Montage du volume dans chaque conteneur :
# lxc config device add <nom du conteneur> sauvegarde-mount disk source=sauvegarde-lxc pool=default path=/sauvegardes
logiciel : borg sauvegarde et rétention de données. Comte chez Kiki, à pousser en ssh.
Sécurisation
Mises à jour automatiques
Installer vim-nox (coloration syntaxique).
Au niveau du système hôte, on ajoute le script :
/root/scripts/lxc_auto_update.sh :
#!/bin/bash
LOG_FILE="/var/log/lxc_update.log"
MAX_RUNS_TO_KEEP=2
RUN_START_MARKER="--- Début de l'exécution du script ---"
RUN_END_MARKER="--- Fin de l'exécution du script ---"
PROXY_CONTAINER="proxy"
WEB_CONTAINERS=("wp" "pmb" "wiki" "tables") # Liste de tous les conteneurs web
WEB_SERVICE_NAME="apache2" # Nom du service web à vérifier (adapter si nécessaire)
SLEEP_AFTER_RESTART=10 # Délai après le redémarrage des conteneurs web
bavarder() {
local message="$1"
echo "$(date '+%Y-%m-%d %H:%M:%S') - $message" >> "$LOG_FILE"
}
# Ajouter un marqueur de début d'exécution
bavarder "$RUN_START_MARKER"
# Récupérer la liste des noms de conteneurs Alpine
containers=$(lxc list --format csv | tail -n +2 | cut -d',' -f1)
bavarder "Liste des conteneurs récupérée : '$containers'"
# Séparer les noms de conteneurs en un tableau
IFS=$'\n' read -r -d '' -a container_array <<< "$containers"
# Boucle pour lancer les mises à jour
{
for container in "${container_array[@]}"; do
bavarder "--- Début du traitement du conteneur : '$container' ---"
config=$(lxc config show "$container")
if echo "$config" | grep -iq "alpine"; then
bavarder "Le conteneur '$container' semble être basé sur Alpine."
is_running=$(lxc list --format csv | grep "^${container}," | grep ",RUNNING,")
if [ -n "$is_running" ]; then
bavarder "Le conteneur '$container' est en cours d'exécution, lancement de la mise à jour..."
lxc exec "$container" -- sh -c "apk update && apk upgrade --available"
result=$?
if [ "$result" -ne 0 ]; then
bavarder "Erreur lors de la mise à jour de '$container'."
fi
else
bavarder "Le conteneur '$container' n'est pas en cours d'exécution, mise à jour ignorée."
fi
else
bavarder "Le conteneur '$container' ne semble pas être basé sur Alpine, mise à jour ignorée."
fi
bavarder "--- Fin du traitement du conteneur : '$container' ---"
done
} >> "$LOG_FILE" 2>&1
bavarder "Fin de la tentative de mise à jour des conteneurs."
# --- Début du redémarrage des conteneurs Alpine (sauf le proxy) ---
bavarder "--- Début du redémarrage des conteneurs Alpine (sauf $PROXY_CONTAINER) ---"
for container in "${container_array[@]}"; do
if [ "$container" != "$PROXY_CONTAINER" ]; then
config=$(lxc config show "$container")
if echo "$config" | grep -iq "alpine"; then
is_running=$(lxc list --format csv | grep "^${container}," | grep ",RUNNING,")
if [ -n "$is_running" ]; then
bavarder "Redémarrage du conteneur '$container'..."
lxc restart "$container"
sleep "$SLEEP_AFTER_RESTART"
# Vérifier l'état du service web pour les conteneurs web
is_web_container=0
for web_container in "${WEB_CONTAINERS[@]}"; do
if [ "$container" == "$web_container" ]; then
is_web_container=1
break
fi
done
if [ "$is_web_container" -eq 1 ]; then
service_status=$(lxc exec "$container" -- rc-service "$WEB_SERVICE_NAME" status 2>&1)
if ! echo "$service_status" | grep -q "started"; then
bavarder "$WEB_SERVICE_NAME ne semble pas en cours d'exécution dans '$container', tentative de démarrage..."
lxc exec "$container" -- rc-service "$WEB_SERVICE_NAME" start
sleep 5
service_status_after_start=$(lxc exec "$container" -- rc-service "$WEB_SERVICE_NAME" status 2>&1)
if ! echo "$service_status_after_start" | grep -q "started"; then
bavarder "Échec du démarrage de $WEB_SERVICE_NAME dans '$container'."
else
bavarder "$WEB_SERVICE_NAME démarré avec succès dans '$container'."
fi
else
bavarder "$WEB_SERVICE_NAME semble être en cours d'exécution dans '$container'."
fi
fi
fi
fi
fi
done
bavarder "--- Fin du redémarrage des conteneurs Alpine (sauf $PROXY_CONTAINER) ---"
# --- Redémarrage du conteneur proxy en dernier ---
bavarder "--- Début du redémarrage du conteneur proxy ($PROXY_CONTAINER) ---"
is_proxy_running=$(lxc list --format csv | grep "^${PROXY_CONTAINER}," | grep ",RUNNING,")
if [ -n "$is_proxy_running" ]; then
bavarder "Redémarrage du conteneur proxy '$PROXY_CONTAINER'..."
lxc restart "$PROXY_CONTAINER"
result=$?
if [ "$result" -ne 0 ]; then
bavarder "Erreur lors du redémarrage du conteneur proxy '$PROXY_CONTAINER'."
fi
else
bavarder "Le conteneur proxy '$PROXY_CONTAINER' n'est pas en cours d'exécution, redémarrage ignoré."
fi
bavarder "--- Fin du redémarrage du conteneur proxy ($PROXY_CONTAINER) ---"
# Ajouter un marqueur de fin d'exécution
bavarder "$RUN_END_MARKER"
# --- Gestion de la rotation des logs ---
if [ -f "$LOG_FILE" ]; then
# Récupérer toutes les occurrences du marqueur de début d'exécution
start_markers=$(grep -c "^$RUN_START_MARKER" "$LOG_FILE")
# Calculer le nombre d'exécutions à supprimer
runs_to_remove=$((start_markers - MAX_RUNS_TO_KEEP))
if [ "$runs_to_remove" -gt 0 ]; then
# Utiliser awk pour ne conserver que les N dernières exécutions
awk -v n="$MAX_RUNS_TO_KEEP" -v start_marker="$RUN_START_MARKER" -v end_marker="$RUN_END_MARKER" '
BEGIN { count = 0; in_run = 0; }
$0 ~ start_marker {
count++;
if (count > (NR - RSTART) + 1 - (n * (RLENGTH ? 1 : 0))) {
in_run = 1;
} else {
in_run = 0;
print;
}
}
$0 ~ end_marker {
if (!in_run) {
print;
}
}
!($0 ~ start_marker) && !($0 ~ end_marker) {
if (!in_run) {
print;
}
}
' "$LOG_FILE" > "$LOG_FILE.tmp" && mv "$LOG_FILE.tmp" "$LOG_FILE"
fi
fi
# Définir l'adresse e-mail pour les notifications
EMAIL_DESTINATAIRE="toto@mail.com" # Remplace par ton adresse e-mail
# Vérifier s'il y a eu des erreurs et envoyer un e-mail si c'est le cas
if grep -q "Erreur" "$LOG_FILE"; then
cat "$LOG_FILE" | mail -s 'Rapport de mise à jour LXC - Erreurs détectées' "$EMAIL_DESTINATAIRE"
fi
exit 0
Envoi des E-mails
L'envoi des mails nécessite l'installation de mailutils et ssmtp :
apt-get install mailutils ssmtp
Configuration de ssmtp :
vi /etc/ssmtp/ssmtp.conf
ssmtp.conf
# # Config file for sSMTP sendmail # # The person who gets all mail for userids < 1000 # Make this empty to disable rewriting. root=toto@monmail.fr # The place where the mail goes. The actual machine name is required no # MX records are consulted. Commonly mailhosts are named mail.domain.com mailhub=smtp.gmail.com:587 (pour gmail) # Where will the mail seem to come from? # rewriteDomain= # The full hostname hostname=raspberrypi # Are users allowed to set their own From: address? # YES - Allow the user to specify their own From: address # NO - Use the system generated From: address FromLineOverride=YES UseTLS=YES UseSTARTTLS=YES AuthUser=toto@monfournisseur.com AuthPass=MonMotdePasseDeConnection
Remarques :
- Pour gmail, il faut créer un mot de passe d'application dans les paramètre du compte google et l'utiliser ici.
- Pour que la redirection de mails fonctionne, il faut que l'adresse de destination finale soit différente de l'adresse utilisée pour l'identification pour l'envoi des mails.
On automatise l'exécution (dimache à 2h du matin) :
crontab -e 0 2 * * 7 /root/scripts/lxc_auto_update.sh
Sauvegardes automatiques des données des conteneurs web
On va programmer une sauvegarde automatique pour chaque conteneur web, ainsi que pour le conteneur mariadb. Ces sauvegardes se feront dans un espace commun qui sera à son tour sauvegardé sur un site distant à intervalles réguliers en gérant la rotation des sauvegardes.
Les conteneurs :
- mariadb
- wiki
- pmb
- wp
bénéficieront de ce mécanisme.
Pour les conteneurs proxy, phpma et tables, une simple sauvegarde à la main suffira.
On commence par créer un volume de 50Gb et on le monte dans les conteneurs concernés :
lxc storage volume create default sauvegarde-lxc size=50GB lxc config device add wp sauvegarde-mount disk source=sauvegarde-lxc pool=default path=/sauvegardes lxc config device add wiki sauvegarde-mount disk source=sauvegarde-lxc pool=default path=/sauvegardes lxc config device add mariadb sauvegarde-mount disk source=sauvegarde-lxc pool=default path=/sauvegardes lxc config device add pmb sauvegarde-mount disk source=sauvegarde-lxc pool=default path=/sauvegardes
mariadb
- On commence par créer un utilisateur spécifique à la sauvegarde.
Sous phpMyAdmin, création de l'utilisateur backup_user avec les privilèges SELECT et LOCK TABLES pour les tables pmb, wiki et wordpress. - Création du script de sauvegarde des tables
On sauvegarde les tables pmb, wordpress et wiki en générant un fichier de log dans /var/log/backup_mariadb.log.
- On commence par créer un utilisateur spécifique à la sauvegarde.
/usr/local/bin/backup_mariadb.sh :
#!/bin/sh
DATE=$(date +%Y%m%d_%H%M)
OUTPUT_FILE="/sauvegardes/db_backup_${DATE}.sql.gz"
USER="backup_user"
PASSWORD="*********" # Mot de passe de backup_user
# Liste des bases de données à sauvegarder
DATABASES="pmb wiki wordpress"
# Exporte chaque base de données et la compresse
for DB in $DATABASES; do
echo "Sauvegarde de la base de données : $DB"
mysqldump -u "$USER" -p"$PASSWORD" "$DB" | gzip >> "$OUTPUT_FILE"
done
chmod 600 "$OUTPUT_FILE" # Restreindre les permissions
echo "Sauvegarde des bases de données terminée : $OUTPUT_FILE" >> /var/log/backup_mariadb.log
- Rendre le script exécutable :
- Rendre le script exécutable :
chmod +x /usr/local/bin/backup_mariadb.sh
- Automatiser le script le samedi à 2h du matin :
Avec crontab -e, ajouter la ligne :
- Automatiser le script le samedi à 2h du matin :
0 2 * * 6 /usr/local/bin/backup_mariadb.sh
wiki
MediaWiki installe par défaut des extensions et des skins. La sauvegarde de ces extension alourdit considérablement le fichier. Le script parcourt le dossier pour les exclure et ne tenir compte que de celles nouvellement installées.
Il crée également un fichier de log /var/log/backup_wiki.log
/usr/local/bin/backup_wiki.sh:
#!/bin/sh
DATE=$(date +%Y%m%d_%H%M)
OUTPUT_FILE="/sauvegardes/wiki_backup_${DATE}.tar.gz"
MEDIAWIKI_ROOT="/var/www/localhost/htdocs/"
BASE_EXTENSIONS="AbuseFilter CategoryTree Cite CiteThisPage CodeEditor ConfirmEdit DiscussionTools Echo Gadgets ImageMap InputBox Interwiki Linter LoginNotify Math MultimediaViewer Nuke OATHAuth PageImages ParserFunctions PdfHandler Poem ReplaceText Scribunto SecureLinkFixer SpamBlacklist SyntaxHighlight_GeSHi TemplateData TextExtracts Thanks TitleBlacklist VisualEditor WikiEditor"
FILES_TO_BACKUP="images
LocalSettings.php
extensions-custom/
skins-custom/"
echo "--- Début du script ---"
echo "Date de la sauvegarde : $DATE"
echo "Fichier de sortie : $OUTPUT_FILE"
echo "Racine de MediaWiki : $MEDIAWIKI_ROOT"
echo "Extensions de base : $BASE_EXTENSIONS"
echo "Fichiers de base à sauvegarder : $FILES_TO_BACKUP"
echo "---"
cd "$MEDIAWIKI_ROOT" || { echo "Erreur lors du changement de répertoire vers $MEDIAWIKI_ROOT"; exit 1; }
echo "Répertoire courant : $(pwd)"
echo "--- Identification des extensions personnalisées ---"
echo "Création du fichier temporaire /tmp/backup_list.txt"
echo "$FILES_TO_BACKUP" > /tmp/backup_list.txt
cat /tmp/backup_list.txt | while IFS= read -r LINE; do
echo "Ajout de '$LINE' à la liste de sauvegarde."
done
echo "---"
echo "Traitement des extensions dans $MEDIAWIKI_ROOT/extensions/"
for EXTENSION_DIR in "$MEDIAWIKI_ROOT"extensions/*; do
if [ -d "$EXTENSION_DIR" ]; then
EXTENSION_NAME=$(basename "$EXTENSION_DIR")
echo "Extension trouvée : $EXTENSION_NAME \(chemin complet : $EXTENSION_DIR\)"
IS_BASE=0
for BASE_EXT in $BASE_EXTENSIONS; do
if [ "$EXTENSION_NAME" = "$BASE_EXT" ]; then
IS_BASE=1
echo " '$EXTENSION_NAME' est une extension de base."
break
fi
done
if [ "$IS_BASE" -eq 0 ]; then
echo " '$EXTENSION_NAME' est une extension personnalisée. Ajout à la liste de sauvegarde."
echo "extensions/$EXTENSION_NAME" >> /tmp/backup_list.txt
fi
fi
done
echo "--- Liste de sauvegarde complète ---"
cat /tmp/backup_list.txt
echo "---"
echo "Création de l'archive : $OUTPUT_FILE"
tar czf "$OUTPUT_FILE" -T /tmp/backup_list.txt --exclude='./tmp/backup_list.txt'
echo "Commande tar exécutée."
if [ -f "$OUTPUT_FILE" ]; then
chmod 600 "$OUTPUT_FILE"
echo "Permissions du fichier de sauvegarde mises à 600."
echo "Sauvegarde des données essentielles et des extensions personnalisées de MediaWiki terminée : $OUTPUT_FILE" >> /var/log/backup_wiki.log
echo "--- Fin du script ---"
else
echo "Erreur : Le fichier de sauvegarde $OUTPUT_FILE n'a pas été créé."
echo "--- Fin du script \(avec erreur\) ---"
exit 1
fi
rm /tmp/backup_list.txt
echo "Fichier temporaire /tmp/backup_list.txt supprimé."
NB : Les nombreuses lignes echo ont été ajoutées à des fin de corrections en cours de programmation et peuvent être simplifiées...
- Rendre le script exécutable :
- Rendre le script exécutable :
chmod +x /usr/local/bin/backup_wiki.sh
- Automatiser le script le samedi à 3h30 du matin :
Avec crontab -e, ajouter la ligne :
- Automatiser le script le samedi à 3h30 du matin :
30 3 * * 6 /usr/local/bin/backup_wiki.sh