Scripts Bash para Administración de Servidores: Ejemplos Prácticos de Automatización

Introducción

Los scripts Bash son la habilidad fundamental para la administración de sistemas Linux y la automatización DevOps. Aunque herramientas modernas como Ansible y Terraform sobresalen en orquestación compleja, los scripts Bash siguen siendo esenciales para automatizaciones rápidas, tareas de mantenimiento del sistema y situaciones donde instalar herramientas adicionales no es práctico. Todo administrador de sistemas debe dominar los scripts Bash para automatizar tareas repetitivas, implementar soluciones de monitoreo y gestionar servidores de manera eficiente.

Esta guía completa presenta scripts Bash listos para producción para tareas comunes de administración de servidores. Cada script incluye manejo de errores, registro de eventos y mejores prácticas que los hacen adecuados para entornos de producción.

Requisitos Previos

  • Conocimiento básico de la línea de comandos Linux/Unix
  • Comprensión de permisos de archivos
  • Familiaridad con comandos comunes de Linux
  • Editor de texto (vim, nano o VS Code)
  • Bash 4.0+ instalado

Plantilla Esencial de Script

#!/bin/bash
set -euo pipefail

# Configuration
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
LOG_FILE="/var/log/$(basename "$0" .sh).log"

# Logging functions
log_info() {
    echo "[INFO] $(date '+%Y-%m-%d %H:%M:%S') - $*" | tee -a "$LOG_FILE"
}

log_error() {
    echo "[ERROR] $(date '+%Y-%m-%d %H:%M:%S') - $*" | tee -a "$LOG_FILE" >&2
}

# Error handling
error_exit() {
    log_error "$1"
    exit "${2:-1}"
}

# Main function
main() {
    log_info "Script started"
    # Your code here
    log_info "Script completed"
}

main "$@"

Scripts de Monitoreo del Sistema

Verificación Completa de Salud

#!/bin/bash
# system-health-check.sh

set -euo pipefail

CPU_THRESHOLD=80
MEMORY_THRESHOLD=85
DISK_THRESHOLD=85

get_cpu_usage() {
    top -bn1 | grep "Cpu(s)" | awk '{print $2}' | cut -d'%' -f1
}

get_memory_usage() {
    free | grep Mem | awk '{printf("%.0f", ($3/$2) * 100)}'
}

get_disk_usage() {
    df -h / | tail -1 | awk '{print $5}' | sed 's/%//'
}

check_metrics() {
    local alerts=()

    cpu=$(get_cpu_usage)
    if (( $(echo "$cpu > $CPU_THRESHOLD" | bc -l) )); then
        alerts+=("CPU: ${cpu}%")
    fi

    memory=$(get_memory_usage)
    if (( memory > MEMORY_THRESHOLD )); then
        alerts+=("Memory: ${memory}%")
    fi

    disk=$(get_disk_usage)
    if (( disk > DISK_THRESHOLD )); then
        alerts+=("Disk: ${disk}%")
    fi

    if [ ${#alerts[@]} -gt 0 ]; then
        echo "ALERTS: ${alerts[*]}" | mail -s "System Alert" [email protected]
    fi
}

check_metrics

Script de Respaldo Automatizado

#!/bin/bash
# automated-backup.sh

set -euo pipefail

BACKUP_SOURCE="/var/www /etc /home"
BACKUP_DEST="/backup"
RETENTION_DAYS=7
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
BACKUP_NAME="backup_${TIMESTAMP}"

create_backup() {
    mkdir -p "${BACKUP_DEST}/${BACKUP_NAME}"

    for dir in $BACKUP_SOURCE; do
        if [ -d "$dir" ]; then
            tar -czf "${BACKUP_DEST}/${BACKUP_NAME}/$(basename $dir).tar.gz" \
                "$dir" 2>&1 | tee -a /var/log/backup.log
        fi
    done

    # MySQL backup
    mysqldump --all-databases | gzip > "${BACKUP_DEST}/${BACKUP_NAME}/mysql.sql.gz"

    # Create final archive
    cd "$BACKUP_DEST"
    tar -czf "${BACKUP_NAME}.tar.gz" "$BACKUP_NAME"
    rm -rf "$BACKUP_NAME"
}

cleanup_old_backups() {
    find "$BACKUP_DEST" -name "backup_*.tar.gz" -mtime +$RETENTION_DAYS -delete
}

main() {
    echo "Starting backup at $(date)"
    create_backup
    cleanup_old_backups
    echo "Backup completed at $(date)"
}

main

Scripts de Gestión de Usuarios

Aprovisionamiento de Usuarios

#!/bin/bash
# user-provisioning.sh

set -euo pipefail

create_user() {
    local username=$1
    local fullname=$2
    local ssh_key=$3

    if id "$username" &>/dev/null; then
        echo "User $username already exists"
        return 1
    fi

    useradd -m -s /bin/bash -c "$fullname" "$username"
    usermod -aG sudo,developers "$username"

    # Setup SSH
    mkdir -p "/home/$username/.ssh"
    echo "$ssh_key" > "/home/$username/.ssh/authorized_keys"
    chmod 700 "/home/$username/.ssh"
    chmod 600 "/home/$username/.ssh/authorized_keys"
    chown -R "$username:$username" "/home/$username/.ssh"

    echo "Created user: $username"
}

# Usage: ./user-provisioning.sh username "Full Name" "ssh-rsa AAA..."
create_user "$@"

Scripts de Seguridad

Auditoría de Seguridad

#!/bin/bash
# security-audit.sh

set -euo pipefail

REPORT="/var/log/security-audit-$(date +%Y%m%d).txt"

{
    echo "Security Audit - $(date)"
    echo "================================"

    echo -e "\nUsers without password:"
    awk -F: '($2 == "") {print $1}' /etc/shadow

    echo -e "\nUsers with UID 0:"
    awk -F: '($3 == 0) {print $1}' /etc/passwd

    echo -e "\nWorld-writable files:"
    find / -xdev -type f -perm -0002 2>/dev/null | head -20

    echo -e "\nSUID files:"
    find / -xdev -type f -perm -4000 2>/dev/null

    echo -e "\nListening ports:"
    ss -tuln

    echo -e "\nFirewall status:"
    ufw status verbose 2>/dev/null || iptables -L -n

} | tee "$REPORT"

echo "Audit complete: $REPORT"

Gestión de Registros

Script de Rotación de Registros

#!/bin/bash
# log-rotation.sh

set -euo pipefail

LOG_DIRS="/var/log/nginx /var/log/application"
COMPRESS_AGE=7
DELETE_AGE=30

for dir in $LOG_DIRS; do
    if [ -d "$dir" ]; then
        # Compress old logs
        find "$dir" -name "*.log" -mtime +$COMPRESS_AGE ! -name "*.gz" -exec gzip {} \;

        # Delete very old logs
        find "$dir" -name "*.gz" -mtime +$DELETE_AGE -delete
    fi
done

echo "Log rotation completed"

Monitoreo de Rendimiento

Monitor de Recursos

#!/bin/bash
# resource-monitor.sh

set -euo pipefail

ALERT_EMAIL="[email protected]"

check_resources() {
    cpu=$(top -bn1 | grep "Cpu(s)" | awk '{print $2}' | cut -d'%' -f1)
    memory=$(free | grep Mem | awk '{printf("%.1f"), ($3/$2) * 100}')
    disk=$(df -h / | tail -1 | awk '{print $5}' | sed 's/%//')

    report="Resource Report for $(hostname)
    CPU: ${cpu}%
    Memory: ${memory}%
    Disk: ${disk}%"

    echo "$report"

    # Alert if thresholds exceeded
    if (( $(echo "$cpu > 80" | bc -l) )); then
        echo "$report" | mail -s "High CPU Alert" "$ALERT_EMAIL"
    fi
}

check_resources

Scripts de Despliegue

Despliegue de Aplicación

#!/bin/bash
# deploy-app.sh

set -euo pipefail

APP_DIR="/opt/myapp"
BACKUP_DIR="/opt/backups"
REPO_URL="https://github.com/company/app.git"
BRANCH="main"

deploy() {
    # Backup current version
    if [ -d "$APP_DIR" ]; then
        tar -czf "${BACKUP_DIR}/app-$(date +%Y%m%d_%H%M%S).tar.gz" "$APP_DIR"
    fi

    # Deploy new version
    if [ -d "$APP_DIR/.git" ]; then
        cd "$APP_DIR"
        git fetch origin
        git checkout "$BRANCH"
        git pull origin "$BRANCH"
    else
        git clone -b "$BRANCH" "$REPO_URL" "$APP_DIR"
    fi

    # Install dependencies
    cd "$APP_DIR"
    npm install --production

    # Restart service
    systemctl restart myapp

    # Verify deployment
    sleep 5
    if curl -f http://localhost:3000/health; then
        echo "Deployment successful"
    else
        echo "Deployment failed, rolling back"
        # Rollback logic here
        exit 1
    fi
}

deploy

Herramientas de Red

Monitor de Conexión

#!/bin/bash
# network-monitor.sh

set -euo pipefail

HOSTS=("8.8.8.8" "1.1.1.1" "google.com")
LOG_FILE="/var/log/network-monitor.log"

check_connectivity() {
    for host in "${HOSTS[@]}"; do
        if ping -c 3 -W 2 "$host" &>/dev/null; then
            echo "[$(date)] OK: $host" >> "$LOG_FILE"
        else
            echo "[$(date)] FAILED: $host" >> "$LOG_FILE"
            echo "Network issue detected for $host" | mail -s "Network Alert" [email protected]
        fi
    done
}

check_connectivity

Mantenimiento de Bases de Datos

Respaldo y Optimización de Bases de Datos

#!/bin/bash
# db-maintenance.sh

set -euo pipefail

DB_USER="backup_user"
DB_PASS="password"
BACKUP_DIR="/backup/mysql"
RETENTION=7

# Backup all databases
backup_databases() {
    mkdir -p "$BACKUP_DIR"

    mysql -u"$DB_USER" -p"$DB_PASS" -e "SHOW DATABASES;" | \
        grep -Ev "Database|information_schema|performance_schema|mysql" | \
        while read -r db; do
            mysqldump -u"$DB_USER" -p"$DB_PASS" \
                --single-transaction \
                "$db" | gzip > "${BACKUP_DIR}/${db}-$(date +%Y%m%d).sql.gz"
            echo "Backed up: $db"
        done
}

# Optimize tables
optimize_tables() {
    mysql -u"$DB_USER" -p"$DB_PASS" -e "SHOW DATABASES;" | \
        grep -Ev "Database|information_schema|performance_schema|mysql" | \
        while read -r db; do
            mysqlcheck -u"$DB_USER" -p"$DB_PASS" --optimize "$db"
        done
}

# Cleanup old backups
cleanup() {
    find "$BACKUP_DIR" -name "*.sql.gz" -mtime +$RETENTION -delete
}

main() {
    backup_databases
    optimize_tables
    cleanup
}

main

Mejores Prácticas

Manejo de Errores

# Always use strict mode
set -euo pipefail

# Custom error handler
error_handler() {
    echo "Error on line $1"
    cleanup_function
    exit 1
}

trap 'error_handler $LINENO' ERR

Validación de Entrada

validate_input() {
    local input=$1

    if [[ -z "$input" ]]; then
        echo "Error: Input required"
        return 1
    fi

    if [[ ! "$input" =~ ^[a-zA-Z0-9_-]+$ ]]; then
        echo "Error: Invalid characters"
        return 1
    fi

    return 0
}

Registro de Eventos

LOG_FILE="/var/log/script.log"

log() {
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*" | tee -a "$LOG_FILE"
}

log "Starting process"

Conclusión

Los scripts Bash son esenciales para la automatización de la administración de sistemas. Estos ejemplos prácticos demuestran patrones comunes para monitoreo, respaldo, gestión de usuarios y tareas de mantenimiento. Siempre pruebe los scripts en entornos que no sean de producción primero, implemente un manejo de errores adecuado y siga las mejores prácticas de seguridad.

Conclusiones clave:

  • Use set -euo pipefail para mayor seguridad
  • Implemente registros completos
  • Agregue manejo de errores y validación
  • Programe con cron o temporizadores systemd
  • Controle las versiones de sus scripts
  • Documente su código
  • Pruebe exhaustivamente antes del uso en producción

Continúe mejorando sus habilidades Bash adaptando estos ejemplos a sus necesidades específicas y construyendo una biblioteca de scripts de automatización reutilizables.