🐧 Scripts Bash — Linux — Scripts prêts à l'emploi
15 scripts Bash prêts à l'emploi pour l'administration Linux quotidienne.
Supprime les fichiers de logs de plus de N jours dans un dossier. À planifier en cron hebdomadaire.
#!/bin/bash
# ─── Variables à modifier ───────────────────────────
LOG_DIR="/var/log" # Dossier des logs
JOURS=30 # Supprimer logs > 30 jours
EXTENSIONS=("*.log" "*.gz" "*.old")
# ────────────────────────────────────────────────────
echo "[$(date)] Nettoyage des logs dans $LOG_DIR..."
for ext in "${EXTENSIONS[@]}"; do
trouve=$(find "$LOG_DIR" -name "$ext" -mtime +$JOURS 2>/dev/null)
if [ -n "$trouve" ]; then
echo "$trouve" | xargs rm -f
echo "Supprimés : $(echo "$trouve" | wc -l) fichiers $ext"
fi
done
# Libérer l'espace des journaux systemd
journalctl --vacuum-time=${JOURS}d --quiet
echo "[$(date)] Nettoyage terminé."
# Cron : 0 2 * * 0 /opt/scripts/clean_logs.sh >> /var/log/clean_logs.log 2>&1Vérifie l'espace disque sur chaque partition et envoie un email si le seuil est dépassé.
#!/bin/bash
# ─── Variables à modifier ───────────────────────────
SEUIL=80 # Alerte si usage > 80%
EMAIL="admin@monsite.fr" # Destinataire
HOSTNAME=$(hostname)
# ────────────────────────────────────────────────────
ALERTE=0
MESSAGE="Alerte disque sur $HOSTNAME :\n\n"
while IFS= read -r line; do
usage=$(echo "$line" | awk '{print $5}' | tr -d '%')
partition=$(echo "$line" | awk '{print $6}')
if [ "$usage" -gt "$SEUIL" ] 2>/dev/null; then
MESSAGE+="⚠️ $partition : ${usage}% utilisé\n"
ALERTE=1
fi
done < <(df -h | grep -vE '^Filesystem|tmpfs|udev|cdrom')
if [ "$ALERTE" -eq 1 ]; then
echo -e "$MESSAGE" | mail -s "⚠️ Alerte disque $HOSTNAME" "$EMAIL"
echo "Alerte envoyée à $EMAIL"
else
echo "Espace disque OK (seuil: $SEUIL%)"
fi
# Cron : */30 * * * * /opt/scripts/check_disk.shDump de toutes les bases de données MySQL avec rotation automatique des sauvegardes.
#!/bin/bash
# ─── Variables à modifier ───────────────────────────
DB_USER="root"
DB_PASS="motdepasse" # Ou utiliser ~/.my.cnf
BACKUP_DIR="/backup/mysql"
RETENTION=7 # Garder 7 jours
DATE=$(date +%Y%m%d_%H%M%S)
# ────────────────────────────────────────────────────
mkdir -p "$BACKUP_DIR"
# Dump de toutes les bases
databases=$(mysql -u"$DB_USER" -p"$DB_PASS" -e "SHOW DATABASES;" 2>/dev/null | grep -Ev "(Database|information_schema|performance_schema|sys)")
for db in $databases; do
FILE="$BACKUP_DIR/${db}_${DATE}.sql.gz"
mysqldump -u"$DB_USER" -p"$DB_PASS" --single-transaction --routines --triggers "$db" 2>/dev/null | gzip > "$FILE"
echo "✅ $db → $(du -sh $FILE | cut -f1)"
done
# Rotation — supprimer les sauvegardes > RETENTION jours
find "$BACKUP_DIR" -name "*.sql.gz" -mtime +$RETENTION -delete
echo "🗑️ Rotation : fichiers > ${RETENTION}j supprimés"
# Cron : 0 1 * * * /opt/scripts/backup_mysql.sh >> /var/log/backup_mysql.log 2>&1Crée plusieurs utilisateurs Linux depuis un fichier CSV. Génère automatiquement les mots de passe.
#!/bin/bash
# ─── Variables à modifier ───────────────────────────
CSV_FILE="/tmp/users.csv" # Format: login,prenom,nom,groupe
DEFAULT_GROUP="techniciens"
SHELL="/bin/bash"
# CSV exemple :
# jdupont,Jean,Dupont,techniciens
# amartin,Alice,Martin,admins
# ────────────────────────────────────────────────────
if [ ! -f "$CSV_FILE" ]; then
echo "❌ Fichier $CSV_FILE introuvable"; exit 1
fi
while IFS=',' read -r login prenom nom groupe; do
[[ "$login" =~ ^# ]] && continue # Ignorer les commentaires
# Vérifier si l'utilisateur existe déjà
if id "$login" &>/dev/null; then
echo "⚠️ $login existe déjà — ignoré"
continue
fi
# Générer un mot de passe aléatoire
PASS=$(openssl rand -base64 12)
useradd -m -s "$SHELL" -c "$prenom $nom" -G "${groupe:-$DEFAULT_GROUP}" "$login"
echo "$login:$PASS" | chpasswd
passwd --expire "$login" # Forcer le changement au 1er login
echo "✅ $login ($prenom $nom) — Pass: $PASS"
done < "$CSV_FILE"
echo "Utilisateurs créés. Les mots de passe sont à transmettre de façon sécurisée."Vérifie que les services critiques tournent et les redémarre automatiquement si nécessaire.
#!/bin/bash
# ─── Variables à modifier ───────────────────────────
SERVICES=("nginx" "mysql" "ssh" "fail2ban" "ufw")
EMAIL="admin@monsite.fr"
HOSTNAME=$(hostname)
# ────────────────────────────────────────────────────
ERREURS=0
RAPPORT="Rapport services $HOSTNAME - $(date)\n\n"
for service in "${SERVICES[@]}"; do
if systemctl is-active --quiet "$service"; then
RAPPORT+="✅ $service : actif\n"
else
RAPPORT+="❌ $service : ARRÊTÉ — tentative de redémarrage\n"
ERREURS=$((ERREURS + 1))
# Tentative de redémarrage
systemctl start "$service" 2>/dev/null
sleep 3
if systemctl is-active --quiet "$service"; then
RAPPORT+=" ↳ ✅ Redémarrage réussi\n"
else
RAPPORT+=" ↳ ❌ Échec du redémarrage — intervention manuelle requise\n"
fi
fi
done
echo -e "$RAPPORT"
if [ "$ERREURS" -gt 0 ]; then
echo -e "$RAPPORT" | mail -s "⚠️ Services arrêtés sur $HOSTNAME" "$EMAIL"
fi
# Cron : */5 * * * * /opt/scripts/check_services.shGénère un rapport complet du système : CPU, RAM, disques, réseau, OS, services actifs.
#!/bin/bash
# ─── Variables à modifier ───────────────────────────
OUTPUT="/tmp/inventaire_$(hostname)_$(date +%Y%m%d).txt"
# ────────────────────────────────────────────────────
{
echo "════════════════════════════════════════════"
echo " INVENTAIRE SYSTÈME — $(hostname)"
echo " Date : $(date)"
echo "════════════════════════════════════════════"
echo ""
echo "── OS ───────────────────────────────────────"
cat /etc/os-release | grep -E "^NAME|^VERSION="
uname -r
echo ""
echo "── CPU ──────────────────────────────────────"
grep "model name" /proc/cpuinfo | head -1 | cut -d: -f2 | xargs
echo "Cœurs : $(nproc)"
echo ""
echo "── RAM ──────────────────────────────────────"
free -h | awk 'NR==2{print "Total:"$2" | Utilisé:"$3" | Libre:"$4}'
echo ""
echo "── DISQUES ──────────────────────────────────"
df -h | grep -vE "tmpfs|udev|loop"
echo ""
echo "── RÉSEAU ───────────────────────────────────"
ip -br addr show | grep -v lo
echo ""
echo "── SERVICES ACTIFS ──────────────────────────"
systemctl list-units --type=service --state=running --no-pager --no-legend | awk '{print $1}' | head -20
echo ""
echo "── DERNIERS LOGINS ──────────────────────────"
last | head -10
} > "$OUTPUT"
echo "✅ Inventaire généré : $OUTPUT"
cat "$OUTPUT"Compresse les fichiers de logs du jour précédent et supprime les archives trop anciennes.
#!/bin/bash
# ─── Variables à modifier ───────────────────────────
APP_LOG_DIR="/var/log/myapp"
ARCHIVE_DIR="/var/log/myapp/archives"
RETENTION_DAYS=90
DATE_HIER=$(date -d "yesterday" +%Y%m%d)
# ────────────────────────────────────────────────────
mkdir -p "$ARCHIVE_DIR"
# Compresser les logs d'hier
for f in "$APP_LOG_DIR"/*.log; do
[ -f "$f" ] || continue
TAILLE_AVANT=$(du -sh "$f" | cut -f1)
gzip -c "$f" > "$ARCHIVE_DIR/$(basename $f)_${DATE_HIER}.gz"
> "$f" # Vider le fichier (pas le supprimer — l'app continue d'écrire)
echo "✅ $(basename $f) : $TAILLE_AVANT → archivé"
done
# Supprimer archives trop anciennes
find "$ARCHIVE_DIR" -name "*.gz" -mtime +$RETENTION_DAYS -delete
echo "🗑️ Archives > ${RETENTION_DAYS}j supprimées"
# Afficher l'espace récupéré
echo "📊 Espace $APP_LOG_DIR : $(du -sh $APP_LOG_DIR | cut -f1)"Analyse auth.log pour détecter les tentatives de brute-force SSH et affiche les IPs les plus actives.
#!/bin/bash
# ─── Variables à modifier ───────────────────────────
LOG_FILE="/var/log/auth.log" # Debian/Ubuntu
# LOG_FILE="/var/log/secure" # RHEL/CentOS
SEUIL_ALERTE=10 # Alerte si > N tentatives
EMAIL="admin@monsite.fr"
# ────────────────────────────────────────────────────
echo "=== Tentatives SSH échouées (dernières 24h) ==="
DEPUIS=$(date -d "24 hours ago" "+%b %e")
# Top IPs attaquantes
echo ""
echo "── Top 10 IPs ──────────────────────────────"
grep "Failed password" "$LOG_FILE" | awk '{print $(NF-3)}' | sort | uniq -c | sort -rn | head -10 | awk '{printf " %4d tentatives → %s
", $1, $2}'
# Compter le total
TOTAL=$(grep -c "Failed password" "$LOG_FILE" 2>/dev/null || echo 0)
echo ""
echo "── Total tentatives : $TOTAL"
# Connexions réussies
echo ""
echo "── Connexions réussies (dernières 24h) ──────"
grep "Accepted" "$LOG_FILE" | tail -20 | awk '{print " "$1,$2,$3,"→ user:"$9,"depuis:"$11}'
# Alerte si beaucoup de tentatives récentes
RECENTES=$(grep "Failed password" "$LOG_FILE" | grep "$(date '+%b %e')" | wc -l)
if [ "$RECENTES" -gt "$SEUIL_ALERTE" ]; then
echo "⚠️ $RECENTES tentatives aujourd'hui — alerte envoyée"
echo "⚠️ $RECENTES tentatives SSH sur $(hostname) aujourd'hui" | mail -s "Alerte SSH $(hostname)" "$EMAIL"
fiSynchronise un dossier local vers un serveur distant via SSH avec exclusions et logging.
#!/bin/bash
# ─── Variables à modifier ───────────────────────────
SOURCE="/var/www/html/"
DEST_USER="backup"
DEST_HOST="192.168.1.50"
DEST_PATH="/backup/www/"
SSH_KEY="/root/.ssh/id_rsa_backup"
LOG_FILE="/var/log/rsync_backup.log"
EXCLUDES=("*.tmp" "*.cache" ".git/" "node_modules/")
# ────────────────────────────────────────────────────
DEBUT=$(date +%s)
echo "[$(date)] Début synchronisation $SOURCE → $DEST_USER@$DEST_HOST:$DEST_PATH" | tee -a "$LOG_FILE"
# Construire les options d'exclusion
EXCL_OPTS=""
for ex in "${EXCLUDES[@]}"; do
EXCL_OPTS="$EXCL_OPTS --exclude=$ex"
done
rsync -avz --delete -e "ssh -i $SSH_KEY -o StrictHostKeyChecking=no" $EXCL_OPTS "$SOURCE" "$DEST_USER@$DEST_HOST:$DEST_PATH" 2>&1 | tee -a "$LOG_FILE"
STATUS=$?
FIN=$(date +%s)
DUREE=$((FIN - DEBUT))
if [ $STATUS -eq 0 ]; then
echo "[$(date)] ✅ Sync terminée en ${DUREE}s" | tee -a "$LOG_FILE"
else
echo "[$(date)] ❌ Erreur rsync (code: $STATUS)" | tee -a "$LOG_FILE"
fiRecherche les fichiers avec des permissions SUID/SGID qui peuvent représenter des risques de sécurité.
#!/bin/bash
# ─── Variables à modifier ───────────────────────────
RAPPORT="/tmp/audit_suid_$(date +%Y%m%d).txt"
DIRS_A_SCANNER=("/" )
EMAIL="admin@monsite.fr"
# ────────────────────────────────────────────────────
{
echo "=== AUDIT SUID/SGID — $(hostname) — $(date) ==="
echo ""
echo "── Fichiers SUID (s'exécutent en tant que owner) ─────"
find / -xdev -perm -4000 -type f 2>/dev/null | xargs ls -la 2>/dev/null | awk '{printf "%-50s %s %s
", $9, $3, $4}'
echo ""
echo "── Fichiers SGID ──────────────────────────────────────"
find / -xdev -perm -2000 -type f 2>/dev/null | xargs ls -la 2>/dev/null | awk '{printf "%-50s %s %s
", $9, $3, $4}'
echo ""
echo "── Fichiers world-writable (dangereux) ────────────────"
find / -xdev -perm -0002 -type f 2>/dev/null | grep -v proc | grep -v sys | head -20
echo ""
echo "── Comptes sans mot de passe ──────────────────────────"
awk -F: '($2 == "" ) {print $1}' /etc/shadow 2>/dev/null
} > "$RAPPORT"
echo "✅ Rapport généré : $RAPPORT"
wc -l "$RAPPORT"
# Optionnel : envoyer par email
# mail -s "Audit SUID $(hostname)" "$EMAIL" < "$RAPPORT"Script de déploiement : pull Git, installation des dépendances, restart des services.
#!/bin/bash
# ─── Variables à modifier ───────────────────────────
APP_DIR="/var/www/monapp"
GIT_BRANCH="main"
SERVICES_A_REDEMARRER=("nginx" "php8.2-fpm")
LOG_FILE="/var/log/deploy.log"
SLACK_WEBHOOK="" # Optionnel
# ────────────────────────────────────────────────────
log() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a "$LOG_FILE"; }
log "=== Début déploiement ==="
COMMIT_AVANT=$(cd "$APP_DIR" && git rev-parse --short HEAD)
# Pull Git
log "Git pull $GIT_BRANCH..."
cd "$APP_DIR" || { log "❌ Dossier introuvable"; exit 1; }
git fetch --all 2>&1 | tee -a "$LOG_FILE"
git reset --hard "origin/$GIT_BRANCH" 2>&1 | tee -a "$LOG_FILE"
COMMIT_APRES=$(git rev-parse --short HEAD)
if [ "$COMMIT_AVANT" = "$COMMIT_APRES" ]; then
log "⏩ Aucun changement (commit: $COMMIT_AVANT)"
exit 0
fi
log "📦 Nouveau commit : $COMMIT_AVANT → $COMMIT_APRES"
# Installer les dépendances si composer.json a changé
if git diff "$COMMIT_AVANT" HEAD -- composer.json | grep -q .; then
log "Mise à jour Composer..."
composer install --no-dev --optimize-autoloader 2>&1 | tee -a "$LOG_FILE"
fi
# Redémarrer les services
for svc in "${SERVICES_A_REDEMARRER[@]}"; do
systemctl reload-or-restart "$svc" && log "✅ $svc redémarré" || log "❌ Erreur $svc"
done
log "=== Déploiement terminé ==="Affiche un résumé des connexions réseau actives, ports en écoute et processus associés.
#!/bin/bash
# ─── Variables à modifier ───────────────────────────
OUTPUT="/tmp/netreport_$(date +%Y%m%d_%H%M).txt"
SEUIL_CONNEXIONS=100 # Alerte si > N connexions établies
# ────────────────────────────────────────────────────
{
echo "=== RAPPORT RÉSEAU — $(hostname) — $(date) ==="
echo ""
echo "── Ports en écoute ──────────────────────────"
ss -tlnp | awk 'NR>1 {printf "%-25s %-20s %s
", $4, $1, $6}'
echo ""
echo "── Connexions ESTABLISHED ───────────────────"
ss -tnp state established | awk 'NR>1' | head -30
echo ""
echo "── Statistiques par état ────────────────────"
ss -tan | awk 'NR>1 {print $1}' | sort | uniq -c | sort -rn
echo ""
echo "── Top IPs connectées ───────────────────────"
ss -tan state established | awk 'NR>1 {print $5}' | cut -d: -f1 | sort | uniq -c | sort -rn | head -10
TOTAL_CONN=$(ss -tan state established | awk 'NR>1' | wc -l)
echo ""
echo "── Total connexions établies : $TOTAL_CONN"
} | tee "$OUTPUT"
if [ "$TOTAL_CONN" -gt "$SEUIL_CONNEXIONS" ]; then
echo "⚠️ Attention : $TOTAL_CONN connexions (seuil: $SEUIL_CONNEXIONS)"
fi