Un dossier par présentation en Markdown, converti en diaporama HTML autonome par Marp CLI, et une page d'accueil générée qui les liste toutes. - scripts/build.mjs : build strict (fiche validée, images vérifiées, aucune ressource externe hormis le logo), page d'accueil filtrable, presentations.json et .htaccess pour l'en-tête CORS - theme/alpinux.css : thème commun pour la vidéoprojection, classes titre et demo - slides/_modele : modèle commenté, non publié - slides/pdf-signer : « Lire, remplir et signer ses PDF », avec notes d'orateur - scripts/deploy-presentations.sh et deploy/ : déploiement par webhook Gitea, sur le modèle du wiki et de www Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01M713yNBL8cssBA1Zri5QLT
161 lines
6.7 KiB
Bash
Executable file
161 lines
6.7 KiB
Bash
Executable file
#!/bin/bash
|
|
# Installe la chaîne de déploiement de presentations.alpinux.org sur owni. À lancer en
|
|
# root — relancer ne casse rien, chaque étape vérifie d'abord ce qui existe.
|
|
#
|
|
# sudo bash deploy/installer.sh
|
|
#
|
|
# Ce que ça met en place : Node.js dans /opt/presentations-alpinux/node, une clé de
|
|
# déploiement en lecture seule, un clone du dépôt, le service d'écoute du webhook sur
|
|
# 127.0.0.1:9878, le relais Apache /deploy, et le droit d'écriture de l'utilisateur du
|
|
# service sur le DocumentRoot.
|
|
#
|
|
# Le script s'arrête à l'étape 3 tant que la clé de déploiement n'est pas déclarée
|
|
# dans Gitea : la déclarer, puis relancer.
|
|
set -euo pipefail
|
|
|
|
BASE="/opt/presentations-alpinux"
|
|
REPO_DIR="$BASE/repo"
|
|
UTILISATEUR="abonnelc"
|
|
CIBLE="/var/www/clients/client1/web22/web"
|
|
VHOST="/etc/apache2/sites-available/presentations.alpinux.org.vhost"
|
|
SECRET_FICHIER="/etc/default/presentations-webhook"
|
|
JOURNAL="/var/log/presentations-deploy.log"
|
|
UNITE="/etc/systemd/system/presentations-webhook.service"
|
|
PORT="9878"
|
|
|
|
# Node.js : la version LTS, figée. Pour en changer, modifier ce numéro et relancer.
|
|
NODE_VERSION="v24.21.0"
|
|
NODE_ARCHIVE="node-$NODE_VERSION-linux-x64.tar.xz"
|
|
NODE_URL="https://nodejs.org/dist/$NODE_VERSION"
|
|
|
|
# Le dépôt est tiré par SSH, avec une clé qui ne sert qu'à lui.
|
|
CLE="/home/$UTILISATEUR/.ssh/id_ed25519_presentations_deploy"
|
|
ALIAS_SSH="gitea-presentations"
|
|
DEPOT_URL="$ALIAS_SSH:alpinux.cedrica5l/alpinux-presentations.git"
|
|
|
|
SOURCE="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|
|
|
[ "$(id -u)" -eq 0 ] || { echo "À lancer en root : sudo bash $0" >&2; exit 1; }
|
|
|
|
echo "==> 1/7 Node.js $NODE_VERSION dans $BASE/node"
|
|
install -d -o "$UTILISATEUR" -g "$UTILISATEUR" "$BASE"
|
|
if [ -x "$BASE/node/bin/node" ] && [ "$("$BASE/node/bin/node" --version)" = "$NODE_VERSION" ]; then
|
|
echo " (déjà là)"
|
|
else
|
|
tmp="$(mktemp -d)"
|
|
curl -fsSL -o "$tmp/$NODE_ARCHIVE" "$NODE_URL/$NODE_ARCHIVE"
|
|
curl -fsSL -o "$tmp/SHASUMS256.txt" "$NODE_URL/SHASUMS256.txt"
|
|
(cd "$tmp" && grep " $NODE_ARCHIVE\$" SHASUMS256.txt | sha256sum -c -)
|
|
rm -rf "$BASE/node"
|
|
install -d "$BASE/node"
|
|
tar -xJf "$tmp/$NODE_ARCHIVE" -C "$BASE/node" --strip-components=1 --no-same-owner
|
|
rm -rf "$tmp"
|
|
echo " $("$BASE/node/bin/node" --version) installé"
|
|
fi
|
|
|
|
echo "==> 2/7 Clé de déploiement"
|
|
if [ ! -f "$CLE" ]; then
|
|
sudo -u "$UTILISATEUR" ssh-keygen -q -t ed25519 -N "" -C "deploy@presentations.alpinux.org" -f "$CLE"
|
|
echo " clé créée"
|
|
fi
|
|
CONFIG_SSH="/home/$UTILISATEUR/.ssh/config"
|
|
if ! grep -q "^Host $ALIAS_SSH\$" "$CONFIG_SSH" 2>/dev/null; then
|
|
sudo -u "$UTILISATEUR" tee -a "$CONFIG_SSH" > /dev/null <<EOF
|
|
|
|
Host $ALIAS_SSH
|
|
HostName alpinux.org
|
|
Port 3022
|
|
User git
|
|
IdentityFile $CLE
|
|
IdentitiesOnly yes
|
|
EOF
|
|
chmod 600 "$CONFIG_SSH"
|
|
echo " alias SSH « $ALIAS_SSH » ajouté"
|
|
fi
|
|
|
|
echo "==> 3/7 Dépôt dans $REPO_DIR"
|
|
if [ -d "$REPO_DIR/.git" ]; then
|
|
sudo -u "$UTILISATEUR" git -C "$REPO_DIR" pull --ff-only origin main
|
|
elif ! sudo -u "$UTILISATEUR" git clone "$DEPOT_URL" "$REPO_DIR"; then
|
|
echo
|
|
echo "Le serveur n'a pas pu cloner le dépôt. Déclarer cette clé publique dans Gitea :" >&2
|
|
echo " dépôt alpinux-presentations → Paramètres → Clés de déploiement → Ajouter" >&2
|
|
echo " (sans cocher l'accès en écriture)" >&2
|
|
echo
|
|
cat "$CLE.pub"
|
|
echo
|
|
echo "Puis relancer : sudo bash $0" >&2
|
|
exit 1
|
|
fi
|
|
|
|
echo "==> 4/7 Scripts et journal"
|
|
# Le serveur exécute ces copies, pas les fichiers du dépôt : une modification de
|
|
# deploy/ ou de scripts/deploy-presentations.sh ne prend effet qu'en relançant
|
|
# installer.sh. Un push ne peut donc pas changer ce que le service exécute.
|
|
install -o "$UTILISATEUR" -g "$UTILISATEUR" -m 755 "$SOURCE/scripts/deploy-presentations.sh" "$BASE/deploy-presentations.sh"
|
|
install -o "$UTILISATEUR" -g "$UTILISATEUR" -m 755 "$SOURCE/deploy/webhook.py" "$BASE/webhook.py"
|
|
touch "$JOURNAL" && chown "$UTILISATEUR":"$UTILISATEUR" "$JOURNAL"
|
|
|
|
echo "==> 5/7 Droit d'écriture sur $CIBLE"
|
|
# Le DocumentRoot appartient à web22 ; une ACL suffit à y laisser écrire le service,
|
|
# sans toucher au propriétaire ni aux droits qu'attend ISPConfig.
|
|
setfacl -m "u:$UTILISATEUR:rwx" "$CIBLE"
|
|
|
|
echo "==> 6/7 Secret du webhook et service systemd"
|
|
if [ -f "$SECRET_FICHIER" ]; then
|
|
echo " (secret déjà là, inchangé)"
|
|
else
|
|
(umask 077; printf 'PRESENTATIONS_WEBHOOK_SECRET=%s\n' "$(openssl rand -hex 24)" > "$SECRET_FICHIER")
|
|
fi
|
|
chmod 600 "$SECRET_FICHIER"
|
|
install -m 644 "$SOURCE/deploy/presentations-webhook.service" "$UNITE"
|
|
systemctl daemon-reload
|
|
systemctl enable --now presentations-webhook
|
|
systemctl restart presentations-webhook
|
|
systemctl is-active --quiet presentations-webhook && echo " service actif"
|
|
|
|
echo "==> 7/7 Relais Apache /deploy"
|
|
if grep -q "127.0.0.1:$PORT" "$VHOST"; then
|
|
echo " déjà relayé"
|
|
else
|
|
cp -a "$VHOST" "$VHOST.bak-$(date +%Y%m%d%H%M)"
|
|
awk -v port="$PORT" '
|
|
{ print }
|
|
!fait && /^[[:space:]]*<VirtualHost[^>]*:443>/ {
|
|
print "\t\tProxyPass /deploy http://127.0.0.1:" port "/deploy"
|
|
print "\t\tProxyPassReverse /deploy http://127.0.0.1:" port "/deploy"
|
|
fait = 1
|
|
}
|
|
' "$VHOST" > "$VHOST.tmp"
|
|
# Recopié dans le fichier plutôt que déplacé par-dessus : un « mv » remplacerait
|
|
# l'original par un fichier neuf, avec d'autres droits.
|
|
cat "$VHOST.tmp" > "$VHOST" && rm -f "$VHOST.tmp"
|
|
grep -q "127.0.0.1:$PORT" "$VHOST" || { echo " ÉCHEC : relais non posé dans $VHOST" >&2; exit 1; }
|
|
echo " relais ajouté"
|
|
fi
|
|
if apache2ctl configtest; then
|
|
systemctl reload apache2
|
|
else
|
|
echo "Configuration Apache invalide : rien n'a été rechargé." >&2
|
|
echo "La sauvegarde .bak-* est à côté du vhost." >&2
|
|
exit 1
|
|
fi
|
|
|
|
echo
|
|
echo "────────────────────────────────────────────────────────────"
|
|
echo "Reste à faire à la main :"
|
|
echo
|
|
echo "1. Déclarer le webhook dans Gitea"
|
|
echo " dépôt alpinux-presentations → Paramètres → Webhooks → Ajouter → Gitea"
|
|
echo " URL : https://presentations.alpinux.org/deploy"
|
|
echo " Méthode : POST, type de contenu : application/json"
|
|
echo " Secret : sudo cat $SECRET_FICHIER"
|
|
echo " Événement : Push seulement, filtre de branche : main"
|
|
echo
|
|
echo "2. Recopier le relais dans ISPConfig pour qu'il survive à une régénération"
|
|
echo " du vhost : Sites → presentations.alpinux.org → Options → Directives Apache"
|
|
echo " (les deux lignes de deploy/apache-vhost.exemple.conf)"
|
|
echo
|
|
echo "Première mise en ligne, sans attendre un push :"
|
|
echo " sudo -u $UTILISATEUR $BASE/deploy-presentations.sh; tail -5 $JOURNAL"
|
|
echo "────────────────────────────────────────────────────────────"
|